Golang并发编程如何做压力测试_Go语言性能测试方法

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 服务压测:用 heyvegeta,别手写 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.TransportMaxIdleConnsMaxIdleConnsPerHost,否则压测客户端自身会因连接耗尽而失败

查并发瓶颈:pprof 要抓对时间点,且必须看 goroutinemutex profile

服务在压测中变慢,光看 cpu profile 可能找不到根因:

  • curl "http://localhost:6060/debug/pprof/goroutine?debug=2":看是否大量 goroutine 卡在 selectchan receivenet/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 自动调整,但旧版本或非容器环境可能仍为全核数,导致线程调度行为差异极大。