go test -bench 不适合测 gin 接口,因为它仅测试 handler 内存执行速度,完全绕过 tcp、tls、连接池、反向代理及 net/http server loop,无法反映 dns 解析、连接建立、tls 握手等真实瓶颈。

直接用 go test -bench 测 Gin 接口,结果和线上表现基本无关——它压的根本不是你的 HTTP 服务,而是内存里一个伪造的请求响应循环。
为什么 go test -bench 不适合测 Gin 接口
因为 httptest.NewRecorder 和 httptest.NewRequest 完全绕过 TCP、TLS、连接池、反向代理、甚至 net/http 的 server loop。你测的只是 handler 函数在内存里跑多快,而真实瓶颈往往卡在 DNS 解析、连接建立、TLS 握手或 accept 队列上。
- handler 里只要调一次
log.Printf或http.Get,ns/op就彻底失真 -
b.N是串行迭代次数,不是并发数;b.RunParallel不提供失败分类、超时控制或 QPS 统计 - 默认不关日志、不 mock 外部依赖(DB/Redis/gRPC),结果不可复现也不可比对
想快速验证 Gin 接口吞吐,该用什么工具
别写 goroutine 脚本硬刚,优先用成熟命令行工具:本地摸底用 hey,需要 JSON 报告或阶梯加压用 vegeta,都得禁用连接复用才能暴露服务端真实瓶颈。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
-
hey -c 100 -q 10 -d 30s -H "Connection: close" http://localhost:8080/hello:-c 并发连接数,-q 每秒请求数,-H 关掉 Keep-Alive echo "GET http://localhost:8080/user/123" | vegeta attack -rate 50 -duration 30s -timeout 5s -header "Accept: application/json" | vegeta report- 所有工具压测前必须确保
vegeta或hey二进制已安装:go install github.com/rakyll/hey@latest
自己写 Go 压测脚本时最容易崩的三个点
如果你非要用 Go 写(比如要嵌入 CI 或复用已有 client 逻辑),以下四点不配齐,脚本一跑就 too many open files 或 dial tcp: lookup xxx: no such host。
-
http.Client.Transport必须显式配置:MaxIdleConns和MaxIdleConnsPerHost设为相同值(如 200),否则后者无效 -
IdleConnTimeout建议30 * time.Second,太短频繁重建连接,太长空闲连接占资源 -
TLSHandshakeTimeout建议5 * time.Second~10 * time.Second,防个别慢握手拖垮整个 worker - 用
time.Ticker控频,别用time.Sleep;用chan struct{}分发信号,别裸起 goroutine 循环发请求
压测时最常被忽略的系统层限制
工具再准,本地端口不够、DNS 缓存没预热、ulimit 没调大,照样压不上去或结果抖动剧烈。
- Linux 默认临时端口范围仅约 32K:
sysctl -w net.ipv4.ip_local_port_range="1024 65535" - 压测目标域名若会变 IP(如 k8s service),需提前预热 DNS 或禁用缓存:
http.DefaultTransport.(*http.Transport).DialContext = fastDialer - ulimit -n 至少设到 65535,否则
too many open files在并发超 1k 后必然出现 - 压测机与 Gin 服务必须物理隔离或网络隔离,避免 CPU / 网卡争抢干扰结果
真正关键的不是“压出多少 QPS”,而是压的时候有没有采集 pprof、有没有清缓存、重启服务、GC 两次——这些细节漏掉一个,数据就只配当参考,不能进基线报告。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










