vegeta默认精确计算并输出p50/p95/p99延迟,推荐用vegeta report -type=json | jq '.latencies.p95'提取真实值,避免误用-rate=0、忽略-timeout或仅看mean掩盖长尾问题。

用 vegeta 精确采集 P95/P99 延迟分布
vegeta 是目前 Go 生态中对延迟分位数支持最直接、输出最稳定的 CLI 工具。它默认就计算并输出 latencies.p50、latencies.p95、latencies.p99,无需额外脚本处理。
常见误用点:
- 用
-rate=0或未设-max-workers导致请求被排队,测出的是调度延迟而非服务延迟 - 忽略
-timeout,超时请求被计入错误率但不参与延迟统计,导致 P99 被人为拉低 - 从
vegeta report直接读 mean——它掩盖长尾;必须查latencies.p95字段或导出 JSON 后用jq '.latencies.p95'提取
推荐命令组合:
echo "POST http://localhost:8080/api/users" | vegeta attack -rate=200 -duration=60s -timeout=3s -header="Content-Type: application/json" -body='{"name":"test"}' | vegeta encode > results.bin
再用 vegeta report -type=json results.bin | jq '.latencies.p95' 获取真实 P95。
绕开 HTTP/1.1 连接复用干扰吞吐量测量
Go 默认 http.DefaultClient 复用 TCP 连接,而多数微服务框架(如 Gin、Echo)在连接复用下会隐藏连接池瓶颈。压测时若不显式断连,QPS 数值虚高,无法反映真实并发承载力。
正确做法分两类:
- 用
hey时加-H "Connection: close",强制短连接 - 用 vegeta 时配
-http2=false+ 自定义 transport:在 Go 压测脚本中设置http.Transport.MaxIdleConns = 0和MaxIdleConnsPerHost = 0 - 若测试 gRPC 接口,则必须禁用 HTTP/2 的流复用,改用
grpc.WithTransportCredentials(insecure.NewCredentials())并控制WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(4*1024*1024))避免缓冲区放大效应
手写 Go 压测脚本时 goroutine 泄漏与计时失真
自己写 for i := 0; i 是最常见也最危险的写法:既没控并发、也没等完成、更没处理 panic,结果是 QPS 不准、延迟偏高、内存暴涨。
关键修复点:
- 用
semaphore或sync.WaitGroup+chan struct{}控制并发上限,避免瞬间打爆服务或客户端文件描述符 - 计时必须包裹在
req, _ := http.NewRequest(...)之后、client.Do(req)之前,否则包含 DNS 解析和 TLS 握手——这些不属于接口逻辑耗时 - 每次请求后调用
resp.Body.Close(),否则底层连接不会归还给 idle pool,后续请求会新建连接,掩盖真实复用效果 - 延迟切片别直接
append([]float64{}, dur.Seconds()),大压测(>10k 请求)会触发频繁 GC;改用预分配数组或环形缓冲(如github.com/cespare/xxhash风格的 fixed-size ring buffer)
pprof 抓不到瓶颈?检查 goroutine 和 mutex profile 时间点
服务压测中变慢,只看 /debug/pprof/profile(CPU)往往找不到根因。真正卡点常藏在阻塞型系统调用或锁争用里。
必须同时抓三类 profile:
-
curl "http://localhost:6060/debug/pprof/goroutine?debug=2":看是否大量 goroutine 卡在net/http.(*conn).serve或select,说明 handler 有同步阻塞(如未设 timeout 的 DB 查询) -
curl "http://localhost:6060/debug/pprof/mutex?debug=1":若contention=xxx高,配合go tool pprof查具体锁位置,常见于全局 map 未分片、日志 writer 未异步化 -
curl "http://localhost:6060/debug/pprof/heap?gc=1":压测中 heap 持续上涨,大概率是响应体未复用bytes.Buffer或 JSON marshal 重复分配
注意:pprof 必须在压测流量稳定后(比如第 30 秒)再抓,前几秒是冷启动抖动,数据无参考价值。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











