2. 压测基础:压测工具选型、参数设置与结果解读
在定位尾延迟性能瓶颈之前,必须建立可靠的压测基础。本章从工具选型、参数配置、结果解读三个维度,帮助你在 Go 服务压测中获取有效数据,避免因压测方法不当导致误判。
2.1 压测工具选型
针对 Go 服务的尾延迟压测,主流工具有 wrk、vegeta、ghz。三者在协议支持、并发模型、延迟统计方面差异显著,选型需结合被测服务协议与压测目标。
| 特性 | wrk | vegeta | ghz |
|---|---|---|---|
| 协议支持 | HTTP/1.1、HTTPS | HTTP/1.1、HTTPS | gRPC (HTTP/2)、Protobuf |
| 并发模型 | 多线程 + epoll/kqueue | 单进程 + goroutine | goroutine + HTTP/2 流 |
| 延迟统计 | 平均值、标准差、百分位 | 平均值、百分位、直方图 | 平均值、百分位、延迟分布 |
| 脚本化 | Lua 脚本(有限) | 命令行 + JSON 配置 | 命令行 + 配置文件 |
| 适用场景 | HTTP 短连接、高并发 | HTTP 持续压测、CI/CD | gRPC 服务、流式 RPC |
2.2 压测参数设置
压测参数直接影响尾延迟数据的真实性。核心参数包括 并发数、持续时间、请求速率。错误设置会导致压测结果偏离实际生产负载。
2.2.1 并发数
并发数指同时发送请求的虚拟用户数。对于 Go 服务,并发数应大于服务 goroutine 池大小,以暴露调度竞争和锁争用。建议从 10 开始,逐步递增至 500 或 1000,观察尾延迟拐点。
2.2.2 持续时间
持续时间必须覆盖服务的热身期和稳态期。Go 服务的 JIT 编译、内存分配器预热、连接池初始化通常需要 10–30 秒。建议压测时长 ≥ 60 秒,并丢弃前 10 秒数据。
2.2.3 请求速率
请求速率(RPS)控制压测强度。固定速率模式适合模拟稳定流量;递增速率模式适合寻找服务瓶颈。尾延迟压测推荐使用固定速率,避免速率波动引入噪声。
| 参数 | 推荐范围 | 尾延迟影响 |
|---|---|---|
| 并发数 | 10 – 1000 | 过高并发导致 goroutine 调度延迟 |
| 持续时间 | 60 – 300 秒 | 过短无法暴露慢请求累积效应 |
| 请求速率 | 100 – 10000 RPS | 速率超过服务容量时尾延迟急剧上升 |
2.3 压测结果解读
压测结果的核心指标包括 吞吐量、延迟百分位、错误率。尾延迟定位重点关注 P99、P99.9、P99.99 百分位。
2.3.1 吞吐量
吞吐量(RPS 或 TPS)反映服务处理能力。当吞吐量达到平台期后继续增加并发,尾延迟会显著上升,这是服务进入饱和区的标志。
2.3.2 延迟百分位
延迟百分位是尾延迟分析的核心。P50 代表中位数延迟,P99 代表 99% 请求的延迟上限,P99.9 和 P99.99 代表极端尾延迟。Go 服务的尾延迟通常由 GC 暂停、锁竞争、网络抖动引起。
2.3.3 错误率
错误率超过 1% 时,压测结果不可信。常见错误包括超时、连接重置、HTTP 5xx。错误请求的延迟数据通常被工具丢弃或标记,需单独分析。
• P99 < 100ms:服务延迟健康
• P99 100–500ms:存在轻微尾延迟,需排查 GC 或锁
• P99 > 500ms 且 P99.9 急剧上升:服务进入饱和区或存在慢路径
• P99.99 比 P99 高 10 倍以上:存在极端尾延迟,需 pprof 定位
2.4 压测命令示例
以下给出 wrk、vegeta、ghz 的典型压测命令,参数设置遵循上述推荐值。
wrk 压测 HTTP 服务
wrk -t12 -c200 -d120s --latency http://localhost:8080/api/v1/hello
参数说明: -t12 表示 12 个线程,-c200 表示 200 个并发连接,-d120s 表示持续 120 秒,--latency 输出延迟百分位。
vegeta 压测 HTTP 服务
echo "GET http://localhost:8080/api/v1/hello" | vegeta attack \
-rate=500 \
-duration=120s \
-workers=50 \
| vegeta report --type=hist[0,50ms,100ms,200ms,500ms,1s]
参数说明: -rate=500 固定 500 RPS,-workers=50 并发工作协程数,--type=hist 输出自定义延迟直方图。
ghz 压测 gRPC 服务
ghz --insecure \
--proto ./hello.proto \
--call helloworld.Greeter.SayHello \
-d '{"name":"test"}' \
-c 100 \
-n 50000 \
--connections=10 \
--timeout=5s \
localhost:50051
参数说明: -c 100 并发数,-n 50000 总请求数,--connections=10 HTTP/2 连接数,--timeout=5s 单请求超时。
• 确保被测服务已预热(至少 10 秒空跑)
• 关闭本地其他网络密集型进程
• 压测机与被测服务在同一内网,避免网络延迟干扰
• 记录压测机的 CPU、内存、网络使用率,排除压测机瓶颈
2.5 压测结果输出示例
以 wrk 的 --latency 输出为例,解读关键字段:
Latency Distribution (HdrHistogram - Recorded Latency)
50.000% 2.34ms
75.000% 3.12ms
90.000% 4.56ms
99.000% 8.90ms
99.900% 15.20ms
99.990% 28.50ms
99.999% 45.10ms
100.000% 52.30ms
Detailed Percentile spectrum:
Value Percentile TotalCount 1/(1-Percentile)
2.340 0.500000 25000 2.00
3.120 0.750000 37500 4.00
4.560 0.900000 45000 10.00
8.900 0.990000 49500 100.00
15.200 0.999000 49950 1000.00
28.500 0.999900 49995 10000.00
45.100 0.999990 49999 100000.00
52.300 1.000000 50000
解读要点:
- P50 = 2.34ms,中位数延迟正常
- P99 = 8.90ms,99% 请求在 9ms 内完成
- P99.9 = 15.20ms,尾延迟开始显现
- P99.99 = 28.50ms,极端尾延迟约为 P50 的 12 倍
- P99.999 = 45.10ms,最大延迟 52.30ms,存在少量慢请求
2.6 压测注意事项
- 预热阶段: Go 服务的 GC 和内存分配器在启动后前 10 秒不稳定,压测数据应丢弃预热期。
- 连接复用: HTTP/1.1 和 gRPC 的连接复用策略不同,压测时需设置合理的连接数,避免连接建立开销污染延迟数据。
- 压测机资源: 压测机 CPU 使用率超过 80% 时,压测工具本身会成为瓶颈,需增加压测机或降低并发。
- 数据持久化: 使用 vegeta 的 JSON 输出或 ghz 的 CSV 输出保存原始数据,便于后续对比分析。
• 不要只压测 30 秒,尾延迟需要长时间暴露慢请求累积效应
• 不要忽略错误请求,错误请求的延迟数据可能被工具丢弃
• 不要只关注 P99,P99.9 和 P99.99 才是尾延迟的核心指标
• 不要在压测过程中调整服务配置,会导致数据不可比