压测 gin 前必须关闭 logger 和 recovery 中间件、禁用 debug 日志、避免 handler 内同步 i/o;推荐用 wrk -t4 -c100 -d30s 压测,注意中间件顺序与第三方中间件需 gin.wraph() 转换。

别直接跑 go test -bench,那测的不是 Gin,是你的本地 GC 波动和没关的 debug 日志。
压测前必须关掉的三件事
Gin 默认开启 Logger 和 Recovery 中间件,压测时若不显式关闭,QPS 会掉一半以上:
-
gin.SetMode(gin.ReleaseMode)—— 必须放在gin.New()之后、路由注册之前 - 手动移除或跳过
gin.Logger()和gin.Recovery(),哪怕你只压空路由 - 确认没在 handler 里打
log.Printf或fmt.Println—— 这些同步 I/O 会卡住 goroutine
wrk 参数怎么设才接近真实并发
用 ab 或默认 curl 循环压 Gin,结果毫无参考价值。真实链路的瓶颈从来不在路由匹配,而在连接复用和 header 写入时机:
- 推荐命令:
wrk -t4 -c100 -d30s http://localhost:8080/ping -
-t线程数建议 ≤ CPU 核心数,-c连接数应 ≥ 并发请求数(避免连接复用掩盖瓶颈) - 别用
-H "Connection: close"—— 这会让 Gin 每次都走新连接,测的是 net/http 底层,不是框架调度
为什么 gin.Context 不影响性能,但中间件顺序会
Gin 的 gin.Context 确实比 Echo 多一层封装,但实际开销微乎其微;真正拖慢吞吐的是中间件注册逻辑错位:
- 把
auth放在Recovery后面 → panic 发生时鉴权已跳过,请求被放行后才崩 - 把日志中间件写在 DB 查询之后 → 每次都要等 SQL 返回才开始记日志,延迟被放大
- 所有依赖
http.Handler接口的第三方中间件(如prometheus.Handler())必须 wrap:用gin.WrapH()转换,否则 panic 报错cannot set header after written
比框架本身更值得调优的三个点
在真实业务中,Gin 框架调度开销通常
- JSON 序列化不用
json.Marshal—— 改用easyjson或ffjson预生成代码,反射开销直降 30%+ - DB 查询没走索引?一条慢查询抵得上 1000 个 Gin 路由匹配
- 中间件里同步写磁盘日志?换成异步 channel + batch flush,P99 延迟下降明显
选 Gin 不是为了它“最快”,而是团队熟悉它的生命周期约束、错误传播路径和中间件模型——这比跑分数字重要得多。











