go test -bench 不是 web 压测工具,仅测 handler 内存与 cpu 逻辑;真实压测需走网络栈、控并发、收 qps 与延迟分布,应使用 hey 或 vegeta 等外部工具。

Go 的 go test -bench 不是 Web 压力测试工具,它测的是 handler 内存+CPU 逻辑,不是真实 HTTP 服务吞吐。真要压 Web 服务,得走网络栈、控并发、收 QPS 和延迟分布——这三件事 testing.B 根本不干。
用 httptest 做 Benchmark 只适合验证 handler 逻辑
它把请求和响应塞进内存里跑,跳过 TCP、TLS、连接池、反向代理、路由分发这些真实瓶颈点。适合的场景很窄:
- 确认某个
http.HandlerFunc里没写死循环、没意外分配大对象 - 对比两种 JSON 解析方式(
json.Unmarshalvseasyjson)在纯内存下的开销 - 排查中间件是否引入锁竞争(需配合
-cpuprofile)
实操时务必:b.ResetTimer() 放在初始化之后;log.SetOutput(io.Discard) 关掉日志;别在循环里 time.Sleep 或新建 *http.Client。否则数据全失真。
真实链路压测必须用外部工具:推荐 hey 或 vegeta
hey 轻量、输出干净、默认禁用 keep-alive,适合快速摸底;vegeta 支持 POST/JSON/header/阶梯加压,适合 API 链路。两者都比手写 goroutine 更稳——你不用操心连接复用、超时穿透、goroutine 泄漏。
立即学习“go语言免费学习笔记(深入)”;
- 用
hey -c 100 -z 30s -H "Connection: close" http://localhost:8080/api模拟 100 并发持续 30 秒,强制关闭连接 - 用
echo "GET http://localhost:8080/api" | vegeta attack -rate=200 -duration=30s -timeout=5s | vegeta report控制精确 RPS - 所有命令里必须加
-timeout和显式关 keep-alive,否则客户端复用会掩盖服务端 accept 队列或连接池瓶颈
自己写压测脚本?关键不是发请求,而是控节奏和防泄漏
新手常犯错误:for i := 0; i —— 这瞬间起 1000 协程,打爆本地文件描述符或目标服务。真正要控制的是并发数、请求间隔、错误重试和结果聚合。
- 用带缓冲 channel 或
semaphore限制最大并发,比如sem := make(chan struct{}, 50) - 每个请求用独立
*http.Request,设req.Close = true避免复用干扰单次计时 - 用
sync.WaitGroup等全部完成,用time.Now()记每请求耗时,最后算 P95/P99,别只看平均值 - 压测机和服务端必须分离,同一台机器压自己,CPU 和网卡争抢会让结果毫无参考价值
压测最易被忽略的一点:每次运行前清缓存、重启服务、调 debug.FreeOSMemory()、关日志。不这么做,三次压测结果波动可能比优化带来的提升还大。











