不能用 go test -bench 测微服务接口吞吐,它不走网络栈、不控并发、不统计错误率和 p95,测的只是 handler 函数在内存里跑多快;vegeta/wrk 比自写 go 脚本更可靠,因其天然支持连接复用控制、qps 节拍、超时熔断和错误分类,而手写脚本极易漏配 http.transport 导致 fd 耗尽或结果失真。

不能用 go test -bench 测微服务接口吞吐,它不走网络栈、不控并发、不统计错误率和 P95,测的只是 handler 函数在内存里跑多快。
为什么 vegeta/wrk 比自写 Go 脚本更可靠
vegeta 和 wrk 是专为真实链路压测设计的工具,它们天然支持连接复用控制、QPS 节拍、超时熔断和错误分类,而手写脚本极易漏掉关键配置导致结果失真。
- vegeta 支持带 body、header、证书、重试策略的 HTTP 请求,且
-rate 100真正维持每秒 100 次请求节奏,不是瞬发 - wrk 的
-H "Connection: close"强制禁用 Keep-Alive,能暴露服务端连接池打满、accept 队列阻塞等真实瓶颈 - 自写 Go 脚本若没显式配置
http.Transport.MaxIdleConns和MaxIdleConnsPerHost相等,http.DefaultClient默认禁用连接池,too many open files会先于服务崩溃 - vegeta 输出直接含
latencies.p95、errors、bytes_out,无需二次解析;wrk 的Latency Distribution表格也比自己聚合time.Since更准
用 vegeta 压测时必须加的三个参数
vegeta 默认行为偏向“友好复用”,但微服务压测要的是真实压力,以下三个参数缺一不可:
-
-timeout 5s:防个别慢请求卡住整个攻击流,避免transport: context deadline exceeded淹没真实错误 -
-h "Connection: close"(或-h "Connection: keep-alive"显式指定):绕过客户端连接复用,让每个请求都走完整 TCP 握手+TLS+HTTP 生命周期 -
-body login.json或-body '{"id":"123"}':必须显式传 body,否则 POST/PUT 请求会因空体被网关拦截,返回400 Bad Request且无提示
典型命令:echo "POST http://localhost:8080/api/login" | vegeta attack -body login.json -header "Content-Type: application/json" -rate 200 -duration 30s -timeout 5s -h "Connection: close" | vegeta report
gRPC 接口压测别碰 grpc.Dial,直接上 ghz
手写 goroutine 调 grpc.Dial 是最常见翻车点:每个 goroutine 新建连接 → 服务端 fd 耗尽 → accept: too many open files;漏设 WithTimeout → 统计延迟虚低;忽略 WithBlock() → DNS 解析失败直接 panic。
-
ghz自动复用*grpc.ClientConn,并发由内部信号量控制,不爆连接数 - 支持透传
metadata.MD,压测时可注入X-Test-Flag: 1验证全链路打标是否生效 - 输出含
Percentile(P90/P95)、Errors(按 gRPC code 分类)、Requests/sec,比自己time.Now()打点更稳 - 命令示例:
ghz --insecure --proto ./api.proto --call pb.UserService.GetUser -d '{"id":"123"}' -c 100 -z 30s localhost:50051
压测机与服务端必须物理或网络隔离
本地用 localhost 压自己写的微服务,CPU、网卡、TIME_WAIT 端口全是共享资源,结果里混着客户端调度抖动和服务端真实瓶颈,根本分不清是服务不行还是你机器太卡。
- 压测机单独部署,至少与服务端不在同一台物理机或同一 K8s node 上
- 执行前调大压测机
ulimit -n(建议 ≥ 65536),否则dial tcp: lookup xxx: no such host或too many open files会提前终止 - 服务端开启
pprof(如net/http/pprof),压测中实时抓取/debug/pprof/goroutine?debug=2和/debug/pprof/heap,确认无 goroutine 泄露或内存持续上涨 - 别信单次结果:至少跑三次,每次重启服务 + 清空 Redis/DB 缓存 +
sync.Poolreset,取中位数才靠谱
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











