go test -bench=测不出真实http吞吐量,因其使用httptest.newrequest和httptest.newrecorder纯内存模拟,绕过tcp、tls、连接池、accept队列、反向代理等真实网络链路,仅测试handler函数在理想内存环境下的执行速度;真实压测应选用hey、vegeta或wrk等工具,并严格控制变量(如禁用日志、复用连接、隔离系统干扰)。

go test -bench=. 为什么测不出真实 HTTP 吞吐量
它根本没走网络栈——httptest.NewRequest 和 httptest.NewRecorder 是纯内存模拟,绕过了 TCP、TLS、连接池、accept 队列、反向代理等所有真实链路环节。你测的是 handler 函数在理想内存环境下的执行速度,不是服务在线上能扛多少并发。
- 适合场景:
BenchmarkJSONUnmarshal、BenchmarkRouteMatch这类纯计算或本地 I/O 逻辑 - 必须调用
b.ResetTimer(),否则路由初始化、中间件构造、日志配置等开销全算进结果里 - 禁用日志:
log.SetOutput(io.Discard),否则log.Printf可拖慢几十倍延迟 - 外部依赖(DB/Redis/gRPC)必须 mock,否则结果不可复现、不可比
真实链路压测该用什么工具和参数
别用 ab,它已过时且不支持 Keep-Alive 控制;hey 是 Go 生态事实标准,vegeta 更适合带 body 和 header 的 POST 场景,wrk 适合高吞吐 GET 压测。
-
hey -c 150 -q 2 -o csv http://localhost:8080/api/users:稳压 300 QPS,避免本机端口耗尽 -
wrk -c 200 -d 30s -t 4 --timeout 5s -H "Connection: close" http://localhost:8080/api/users:强制每请求新建连接,暴露服务端连接池瓶颈 echo "POST http://localhost:8080/api/login" | vegeta attack -body login.json -header "Content-Type: application/json" -rate 100 -duration 30s -timeout 5s | vegeta report- 压测前关掉服务端调试日志:
log.SetOutput(io.Discard),否则 I/O 成瓶颈
gRPC 微服务压测不能手写 goroutine
手写脚本极易误用 grpc.Dial(每 goroutine 新建连接 → 打爆服务端 fd)、漏设 context.WithTimeout(统计失真)、忽略 WithBlock()(阻塞在 DNS 或连接建立上)。
- 直接用
ghz:ghz --insecure --proto ./api.proto --call pb.UserService.GetUser -d '{"id":"123"}' -c 50 -z 30s localhost:50051 - 若必须手写,
*grpc.ClientConn必须复用,所有调用包在context.WithTimeout内,用信号量控并发 - gRPC 压测必须关注 TLS 握手开销、流控响应、Metadata 透传,这些在 HTTP 工具里根本测不到
pprof 采集和结果稳定性怎么保障
没 pprof 的压测等于盲测;单次结果波动大,不是代码问题,而是系统干扰——CPU 频率、后台进程、GC 时间点都在影响数据。
- 边压边采:
curl http://localhost:6060/debug/pprof/profile?seconds=30 > cpu.prof,每次压测都抓一份 - 三次独立运行:每次清页缓存(
sync && echo 3 | sudo tee /proc/sys/vm/drop_caches)、重启服务、手动 GC 两次(runtime.GC()) - Linux 下切性能模式:
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor - 笔记本压测前关 Slack/Chrome/iTerm,用
powermetrics --samplers sched,proc | grep "idle wakeups"确保低于 50/s
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











