← 返回博客
go2026-09-12 22:01:232 分钟 · 527 0

Gin 熔断与重试:保护下游不雪崩

用指数退避重试兜住瞬时故障,用 sony/gobreaker 熔断挡住持续故障的下游,再配 context 超时,避免一个慢依赖拖垮整条链路。

#gin#熔断#重试

你的服务依赖数据库、Redis、别的 RPC。下游偶发抖一下,不该让上层跟着挂。重试兜瞬时错误,熔断在下游持续故障时快速失败,超时保证不无限等。三件合起来,下游挂了你的服务还能活。

1. 重试只兜瞬时错误

网络闪断、超时这类能自愈的才重试。业务错误(参数错、权限不足)重试没用,反而放大流量:

func withRetry(fn func() error, max int) error {
    var err error
    for i := 0; i < max; i++ {
        if err = fn(); err == nil {
            return nil
        }
        if errors.Is(err, ErrBusiness) {
            return err // 业务错不重试
        }
        time.Sleep(backoff(i))
    }
    return err
}

2. 指数退避加抖动

每次等更久,避免重试风暴撞在一起:

func backoff(i int) time.Duration {
    base := 100 * time.Millisecond
    j := time.Duration(rand.Intn(100)) * time.Millisecond
    return base*time.Duration(1<<i) + j
}

1<<i 是指数增长,随机 j 打散多个调用方的重试节奏。

3. 熔断挡持续故障

下游彻底挂了,重试只会堆更多超时请求、拖慢线程。用 sony/gobreaker 在连续失败到阈值时熔断,直接拒请求:

var cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{
    Name:          "mysql-query",
    MaxRequests:   3, // 半开时放行的探测数
    Timeout:       5 * time.Second, // open 持续多久
    ReadyToTrip: func(c gobreaker.Counts) bool {
        return c.ConsecutiveFailures > 5
    },
})

func callDB(ctx context.Context) (string, error) {
    return cb.Execute(func() (string, error) {
        return queryWithCtx(ctx)
    })
}

三态:closed 正常放行;连续失败超阈值转 open,请求直接失败不调下游;Timeout 后转 half-open,放几个探测,成功则恢复 closed。

4. 超时别无限等

每次下游调用带 context 超时,防止一个慢查询卡住整个请求:

func queryWithCtx(ctx context.Context) (string, error) {
    ctx, cancel := context.WithTimeout(ctx, 800*time.Millisecond)
    defer cancel()
    return db.QueryRowContext(ctx, "...").Text()
}

超时返回 context.DeadlineExceeded,上层重试或走熔断。超时值按 P99 耗时定,留余量。

5. 在 service 层组合

handler 不直接碰这些,包在 service 的下游调用里:

func (s *OrderSvc) Pay(ctx context.Context, id string) error {
    return withRetry(func() error {
        _, err := callDownstream(ctx, id) // 内部带超时 + 熔断
        return err
    }, 3)
}

handler 只调 Pay,容错逻辑沉淀在 service,接口层干净。

6. 上线清单

重试只对幂等、瞬时错误,带退避和抖动,设最大次数。熔断阈值按正常错误率定,误判会误伤。超时值小于网关/客户端超时,避免上层已断你还在等。熔断和限流配合:限流防自己被冲,熔断防下游拖垮自己。监控熔断次数,频繁跳闸说明下游真有问题。

下一篇讲多租户,让一套服务服务多个客户而数据不串。

相关推荐

本文为原创文章,采用CC BY-NC-SA 4.0协议授权,转载请保留署名与原文链接。原文链接:https://www.wxbuluo.com/article/191