gin默认不触发sentinel熔断,因sentinel-golang不自动织入http handler,需在handler中手动调用degrade.entry/exit并显式上报错误,否则规则不生效、指标无法统计。

为什么 Gin 默认不触发 Sentinel 熔断
因为 sentinel-golang 不像 Java 版那样自动织入 HTTP handler,它只提供资源粒度的降级能力,degrade.LoadRules 只是注册规则,不会绑定到任何请求生命周期。如果你没在 handler 里手动调用 degrade.Entry 和 degrade.Exit,熔断永远不生效——连异常率都统计不到。
常见错误包括:忘记 defer entry.Exit()、panic 没被 degrade.TraceError 捕获、资源名用了带动态参数的路径(如 /order/:id),导致规则分散无法聚合统计。
在 Gin handler 中正确埋点的三要素
以订单查询接口为例,必须同时满足以下三点才算完成熔断接入:
-
degrade.Entry("order_query")要在业务逻辑前调用,返回blockErr != nil时立即中止请求 -
defer entry.Exit()必须存在,且不能被return或 panic 跳过(建议包裹在recover中) - 所有可能 error 或 panic 都要显式传给
degrade.TraceError("order_query", err),框架不自动捕获
示例片段:
func getOrder(c *gin.Context) {
entry, blockErr := degrade.Entry("order_query")
if blockErr != nil {
c.AbortWithStatusJSON(429, map[string]string{"msg": "service degraded"})
return
}
defer func() {
if r := recover(); r != nil {
degrade.TraceError("order_query", fmt.Errorf("panic: %v", r))
}
entry.Exit()
}()
err := callOrderService()
if err != nil {
degrade.TraceError("order_query", err)
c.AbortWithStatusJSON(500, map[string]string{"msg": "internal error"})
return
}
c.JSON(200, order)
}
把熔断逻辑抽成 Gin 中间件是否可行
可以,但要注意资源名必须可配置,且中间件需支持路径参数提取和标准化(避免 /user/123 和 /user/456 被当成两个资源)。推荐做法是:
- 用
c.FullPath()或预定义的路由标识(如c.Get("resource_name"))作为资源名 - 在路由注册时显式设置资源名:
router.GET("/order/:id", setResourceName("order_query"), getOrder) - 中间件内统一处理
Entry/Exit/TraceError,但 panic 捕获仍需defer/recover包裹
不推荐直接用 c.Request.URL.Path,它含查询参数,易导致资源爆炸。
规则配置中的关键参数陷阱
Count 和 Grade 的组合容易配错:
-
Grade: degrade.GradeExceptionRatio时,Count是 0–1 的小数(如0.3表示 30% 异常率) -
Grade: degrade.GradeSlowRequestRatio时,Count同样是小数,但依赖stat.InboundRT上报,需确保业务代码里调用stat.RecordResponseTime -
MinRequestAmount: 10很关键——低于该请求数窗口内不触发判断,测试时容易误判“规则没生效” -
TimeWindow: 60单位是秒,不是毫秒;且是滑动窗口,不是固定时间切片
上线前务必用压测工具连续发 >10 次请求,再制造错误,才能验证熔断是否真正进入 OPEN 状态。
最易被忽略的是 panic 捕获位置:Gin 的 recovery 中间件在 Next() 后才 recover,而 degrade.Entry 在 Next() 前就已进入,所以必须在业务 handler 内部做 recover + TraceError,否则 panic 会绕过熔断统计。











