Go并发压力测试核心是控制goroutine生命周期、资源竞争与真实负载模型;盲目增并发会掩盖瓶颈、扭曲pprof数据;-bench适合无状态逻辑,需加-benchmem看内存分配,禁用time.Sleep,I/O场景应换专用压测工具。

Go 并发程序的压力测试,核心不是“起多少 goroutine”,而是控制好 goroutine 生命周期、资源竞争点和真实负载模型。盲目增加并发数只会掩盖瓶颈,甚至让 pprof 数据失真。
用 go test -bench 测纯函数并发吞吐,但别信默认结果
基准测试适合验证无状态逻辑(比如加解密、编解码),但默认 Benchmark 不模拟真实请求节奏,容易高估吞吐:
-
-benchmem必加,看每次操作分配了多少内存,Allocs/op高往往意味着 GC 压力大 - 避免在
Benchmark函数里写time.Sleep模拟延迟——它会阻塞整个B.N循环,扭曲ns/op - 若被测函数含 I/O(如 HTTP 调用、DB 查询),
go test -bench无法反映连接池、超时、重试等行为,应改用专用压测工具
func BenchmarkConcurrentParseJSON(b *testing.B) {
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = json.Unmarshal([]byte(`{"id":1}`), &struct{ ID int }{})
}
})
}
HTTP 服务压测:用 hey 或 vegeta,别手写 goroutine 循环
自己用 for i := 0; i 发请求,既难控 QPS,又无法统计成功率、P95 延迟、连接复用效果。推荐:
-
hey -n 10000 -c 100 -m POST -d '{"x":1}' http://localhost:8080/api:轻量、输出直观,支持基本认证和 header -
vegeta attack -targets=targets.txt -rate=200 -duration=30s | vegeta report:可定义复杂请求流(如阶梯增压)、支持 TLS 和自定义 body - 注意设置
http.Transport的MaxIdleConns和MaxIdleConnsPerHost,否则压测客户端自身会因连接耗尽而失败
查并发瓶颈:pprof 要抓对时间点,且必须看 goroutine 和 mutex profile
服务在压测中变慢,光看 cpu profile 可能找不到根因:
立即学习“go语言免费学习笔记(深入)”;
-
curl "http://localhost:6060/debug/pprof/goroutine?debug=2":看是否大量 goroutine 卡在select、chan receive或net/http.(*conn).serve—— 这说明处理逻辑阻塞或 channel 容量不足 -
curl "http://localhost:6060/debug/pprof/mutex?debug=1":若contention高,说明锁争用严重;配合go tool pprof查具体锁位置 - 启动服务时加
-gcflags="-l"禁用内联,能让 pprof 显示更准确的调用栈
真实场景必须模拟业务约束:超时、重试、限流、连接池
压测结果脱离这些,等于没测:
- HTTP client 必须设
Timeout,否则一个慢请求拖垮整个 goroutine 池 - 数据库连接池(如
sql.DB.SetMaxOpenConns)要与压测并发数匹配;过小会排队,过大则 DB 扛不住 - 用
golang.org/x/time/rate.Limiter在入口限流,观察下游组件(Redis、MySQL)在不同 QPS 下的响应曲线 - 压测持续时间至少 2–3 分钟,短于 30 秒的结果受 GC 周期、JIT(如果启用了)干扰太大
最常被忽略的一点:压测环境的 GOMAXPROCS 和生产是否一致?容器中未显式设置时,Go 1.21+ 会按 cgroup CPU quota 自动调整,但旧版本或非容器环境可能仍为全核数,导致线程调度行为差异极大。











