用 AI 压 gRPC 与 HTTP 接口:ghz、k6 与结果解读
gRPC 压测绕不开 ghz:它直接用 .proto 描述文件发起调用,不需要你写客户端代码,参数与输出都是纯文本,正好适合贴给 AI 解读。HTTP 接口交给 k6 或 wrk。真正费时间的不是发压,而是看懂输出——平均值好看、P99 难看,是这两个协议压测里最常见的翻车方式。
一、ghz 常用参数
| 参数 | 含义 | 使用要点 |
|---|---|---|
--proto / --import-paths | proto 文件与依赖的搜索目录 | 依赖其他 proto 时不补 import 路径会报找不到类型 |
--call | 方法全名,如 pkg.Service/Method | 必须带包名;写错会报 method not found,而非参数错误 |
-c | 并发数(并发 worker) | 与 --rps 分开调:先定速率看能否达成,再加并发看延迟 |
--rps | 目标速率上限(每秒请求数) | 设 0 表示不限速;此时实际速率由 -c 与服务端延迟共同决定 |
-n / -z | 总请求数 / 持续时间 | 短测用 -n,稳态与稳定性场景用 -z 5m 便于对齐时间轴 |
-d / -m | 请求体 JSON / metadata(鉴权头) | 结构复杂先本地验证;token 过期会导致中段大量失败 |
--insecure | 明文连接,不做 TLS | 仅内网压测用;要评估 TLS 开销就补一次不带它的对照 |
-O / --format | 输出格式:summary / json / csv / html | 要画每秒请求数曲线就导出 json 或 csv,别只看 summary |
二、压 gRPC
# 1) 先用 grpcurl 确认方法和参数都对,再上 ghz
grpcurl -plaintext -d '{"uid":"u-1"}' -H 'authorization: Bearer dev-token' \
10.0.0.12:9090 im.v1.UserService/Get
# 2) 定速率压测:8000 QPS、并发 200、持续 5 分钟,导出 JSON 供后续分析
ghz --insecure --proto ./proto/user.proto --import-paths ./proto \
--call im.v1.UserService/Get -d '{"uid":"u-1001"}' -m '{"authorization":"Bearer <token>"}' \
--rps 8000 -c 200 -z 5m --timeout 3s -O json -o ghz-user.json 10.0.0.12:9090
# 3) 找拐点:不限速,只加并发,每档跑 2 分钟
for c in 50 100 200 400 800; do
ghz --insecure --proto ./proto/user.proto --call im.v1.UserService/Get -d '{"uid":"u-1001"}' \
--rps 0 -c $c -z 2m -O summary 10.0.0.12:9090 | tee "ghz-c$c.txt"
sleep 60
done
Summary:
Count: 2400000 Total: 300.12 s
Slowest: 482.11 ms Fastest: 0.42 ms
Average: 6.85 ms Requests/sec: 7996.80
Latency distribution:
50 % in 4.78 ms <- 中位数
95 % in 18.02 ms
99 % in 61.44 ms <- 长尾,体感问题在这里
Status code distribution:
[OK] 2399811 responses [DeadlineExceeded] 189 responses
关键读法:Average 6.85ms 而 P99 61.44ms,说明约 1% 的请求在排队或遇到锁竞争;Requests/sec 7996.80 略低于目标 --rps 8000,加上 189 条 DeadlineExceeded,要看超时是否集中在某一时段而不是均匀分布。
三、压 HTTP 接口
# k6:恒定到达率,请求体与鉴权按接口实际情况替换
k6 run -e BASE=http://10.0.0.12:8080 -e TOKEN="$T" --summary-export=http-summary.json bench/http-get.js
# wrk:吞吐基线快照,配 Lua 脚本做参数化
wrk -t8 -c400 -d120s --latency -s bench/get.lua http://10.0.0.12:8080/api/v1/items
-- bench/get.lua:每个请求换一个 id,避免单热点把结论带偏
local counter = 0
request = function()
counter = counter + 1
return wrk.format("GET", "/api/v1/items/" .. (counter % 100000),
{ ["Authorization"] = "Bearer " .. (counter % 200) })
end
k6 按分位与阈值给结论,适合进流水线;wrk 输出分位较少但吞吐更高,适合做压测机能力快照。两者都要记录压测机自身的 CPU:wrk 线程数超过物理核数时,瓶颈就在压测机。
四、让 AI 解读结果
角色:性能分析师。下面是一次 gRPC 压测的完整输出与背景,只解读,不要重写脚本。
背景:单实例 4C8G;接口逻辑 = 先查 Redis,未命中查 MySQL;压测机 8C16G 独立节点;
目标 = 8000 QPS,P99 < 100ms,错误率 < 0.1%;压测期间服务端 CPU 62%,GC 暂停累计 1.2s。
原始输出:
<粘贴 ghz 的 summary 或 json 统计段>
要求:
1) 分别解读平均值与 P99,说明两者差距指向哪类问题(排队、锁竞争、GC、下游慢)
2) 列出错误码分布,逐类给出可能原因与下一步验证动作
3) 判断每秒请求数是否平稳,给出判断依据,并说明还需要哪些数据才能确认
4) 每条结论标明是「数据支持」还是「需要补充采集」,并写出这次压测回答不了的问题
第 4 条是让 AI 解读压测数据时的安全绳:压测数据很少具备充分的因果证据,要求它区分「数据支持」与「需要补充采集」,能挡掉大部分自信但错误的因果断言。
五、读结果的三条规则
| 观测项 | 判读 | 典型误判 |
|---|---|---|
| 平均 vs P99 | 平均正常、P99 陡增 → 少量请求排队,查锁、GC、下游抖动 | 「平均才 7ms,没问题」,掩盖 1% 用户的糟糕体感 |
| 错误码分布 | 4xx 多半是脚本问题,5xx 是服务问题,超时可能来自下游或压测机 | 把 401 集中爆发当成服务端不稳 |
| 每秒请求数曲线 | 导出 json/csv 后按秒聚合,看是否平稳、是否随加压阶梯同步下降 | 只看总 Requests/sec 平均值,忽略中途掉速 |
六、protobuf 与 JSON 的体积差异
| 对比项 | protobuf | JSON | 影响 |
|---|---|---|---|
| 字段名 | 只传字段号(1~2 字节) | 每次传完整键名 | 小消息下键名占大头,差距 2~5 倍 |
| 类型与定界 | 类型由 .proto 描述,长度前缀定界 | 靠文本字面量与引号逗号 | 字段越多,JSON 冗余越明显 |
| 压缩后体积 | gzip 后差距收窄到 1.5~2 倍 | 压缩率通常更高 | 带宽受限时先比压缩后体积 |
| 解析成本 | 二进制解析,无字符串扫描 | 需要词法解析 | 高 QPS 下 JSON 的 CPU 开销不可忽略 |
protoc --encode=im.v1.Msg ./proto/im.proto < msg.json | wc -c # protobuf 字节数
wc -c < msg.json # JSON 字节数
# 比较两者的延迟:ghz 用 -d 传 JSON,或写死二进制用 -b 传文件
体积要换算到吞吐才有意义:单条省 100 字节,10 万 QPS 下就是约 10 MB/s 的出口带宽差,这才是压测报告里该出现的数字。
常见坑
| 坑 | 现象 | 做法 |
|---|---|---|
-c 与 --rps 一起无脑加大 | 分不清瓶颈在速率还是排队 | 先定 --rps 看能否达成,再单独调 -c 观察延迟 |
用 --insecure 得出延迟结论 | 报告里少了 TLS 握手与加密成本 | 标注是否启用 TLS,涉及线上容量时补对照 |
| 只导出 summary | 拿不到每秒请求数曲线 | -O json 或 -O csv 导出原始样本再按秒聚合 |
| 压测前不预热、token 中途过期 | P99 被冷启动拉高,中段 401 爆发被当成服务劣化 | 丢弃前 30 秒数据,压测时长与 token 有效期对齐 |
| 忽略响应体校验 | 服务端返回业务错误码仍计入成功 | 断言业务码,HTTP 200 不等于成功 |
小结:gRPC 用 ghz,先 grpcurl 校验方法与参数,再用 --proto、--call、-c、--rps、-z、-O json 组成命令,-c 与 --rps 分开调才能分清是速率不够还是排队;HTTP 用 k6 做带阈值的场景回归、用 wrk 做吞吐快照。解读结果时死守三条规则——平均与 P99 分开看、错误码按类归因、每秒请求数按秒画曲线;给 AI 的提示词里要求它区分「数据支持」与「需要补充采集」,比让它直接下因果结论安全得多。跨协议的对照数值与 IM 场景参数可参考 im-system 目录第 26 章。