Golang微服务中如何进行压测_Golang微服务压测方法

9次阅读

微服务压测必须走真实链路,禁用 KeepAlive,用 vegeta/wrk/ghz 等工具暴露连接池、TIME_WaiT、accept 队列等生产级问题;go test -bench 仅适用于 mock 外部依赖后的 handler 逻辑验证。

Golang微服务中如何进行压测_Golang微服务压测方法

微服务压测不是跑个 go test -bench 就算完事——它压的要是真实链路,否则你看到的 QPS 是假的,延迟是骗人的,瓶颈永远藏在连接池、TIME_WAIT 或 mock 掉的 redis 里。

go test -bench接口?只适合 handler 逻辑验证

它能快速验证单个 http handler 或 gRPC 方法的纯 Go 层性能,但前提是:禁用日志、mock 所有外部依赖(DB/redis/gRPC 调用)、关闭中间件。否则你测的不是服务,是日志写入速度或连接建立耗时。

  • b.ResetTimer() 必须加在初始化之后、循环之前,否则初始化开销(如创建 request、recorder)会被计入结果
  • -benchmemB/opallocs/op,内存分配高往往意味着 GC 压力大,不是吞吐问题而是泄漏苗头
  • 别在循环里写 time.Sleep 模拟节奏——它会卡死整个 b.N 循环,ns/op 完全失真
  • I/O 类函数(比如调用 http.Client.Do)不适合用它压,因为不走真实网络、复用连接、忽略超时重试逻辑

真实链路压测必须走完整网络,且禁用 KeepAlive

vegeta、wrk、ghz 这类工具才能暴露服务端 accept 队列溢出、连接池打满、TIME_WAIT 泛滥等生产级问题。关键不是“能不能发出去”,而是“服务端扛不扛得住”。

  • vegeta 示例:echo "POST http://localhost:8080/api/login" | vegeta attack -body login.json -header "Content-Type: application/json" -rate 100 -duration 30s -timeout 5s -insecure;务必加 -insecure(若用 https)和显式 -timeout
  • gRPC 压测统一用 ghz:支持 metadata 注入、QPS 控制、并发连接数调节,输出含 P90/P99 和错误码分布,比手写 client 稳定得多
  • 所有客户端必须设 DisableKeepAlives: true(vegeta 默认关,wrk 默认开,ghz 用 --keepalive=false),否则连接复用掩盖服务端连接管理缺陷
  • 每次压测前清空服务端 page cache、重启服务、手动触发两次 runtime.GC(),避免缓存干扰和 GC 周期污染数据

边压边采 pprof,三次取中位数才敢信

压测时 CPU、heap、goroutine 不采集,等于闭眼开车。pprof 数据必须和请求流量对齐,否则你根本分不清是慢在 decode 还是慢在锁竞争。

立即学习go语言免费学习笔记(深入)”;

  • 启动服务时加 net/http/pprof,压测中用 wget http://localhost:6060/debug/pprof/profile?seconds=30 抓 30 秒 CPU profile,同时抓 /heap/goroutine?debug=2
  • 不要只看一次结果:连续压三次,每次间隔 2 分钟,取 QPSP99 的中位数,排除 GC 尖峰或冷启动抖动
  • pprof 分析重点看:top3 函数耗时占比、goroutine 数是否随并发线性增长、heap 中是否有未释放的 []byte 或 map
  • 若发现 goroutine 数持续上涨,立刻查 pprof/goroutine?debug=2,常见坑是 channel 写入阻塞、context.Done() 未监听、defer 关闭资源遗漏

压测最难的不是起多少并发,而是让每次结果可复现、可归因。mock 掉什么、保留什么、连接怎么建、缓存怎么清——这些细节决定你是在调优,还是在碰运气。

text=ZqhQzanResources