返回归档
📹技术分享

限流、熔断与降级:微服务高可用性的核心保障机制

文章目录

在分布式系统中,服务间依赖关系复杂,任何一点异常都可能引发连锁反应。限流、熔断、降级是应对流量冲击、故障传播和部分失效的三大利器,三者配合使用,能显著提升系统的稳定性和用户体验。本文结合实际代码,系统梳理三者的概念、关系、实践方法与最佳配置。

一、核心概念

1. 限流(Rate Limiting)

限流是对单位时间内请求数量进行显式限制的机制,目的是防止系统被突发流量击垮。

算法 原理简述 优点 缺点 是否允许突发 典型应用场景 代表实现
固定窗口 固定时间段(如1s)内计数请求,超过阈值拒绝,窗口结束清零 实现最简单、内存开销极低 临界问题(窗口边界突发可瞬间超限) 简单并发控制、秒杀 Redis INCR + EXPIRE
滑动窗口 将时间切分成N个小窗口,滑动统计最近一段时间的总请求数 解决临界问题,统计更平滑 实现稍复杂,需维护队列 高并发API、Hystrix/Sentinel统计 Sentinel滑动窗口、Guava
漏桶 请求进入“桶”,以固定速率“漏出”处理,桶满则拒绝 输出速率绝对平滑,保护下游 无法应对突发(即使空闲也匀速) 保护下游接口、匀速排队 Nginx limit_req、Sentinel匀速排队
令牌桶 以固定速率向桶中生成令牌,请求需消耗令牌通过,桶可积累 允许一定突发,限制平均速率 短时可能有少量超发 网关限流、接口调用(最常用) Guava RateLimiter、Redisson

典型实现方式包括令牌桶、漏桶、固定窗口、滑动窗口等

image

只要桶中有令牌,请求就可以通过

image

漏桶:只有等到了水滴,才能被serve

  • 漏桶:强迫“流出”匀速,保护下游不被突发打垮(更像流量整形)。
  • 令牌桶:允许“流入”有一定突发,但长期平均受控(更像配额/许可制)。

固定窗口

gantt
    title 固定窗口限流示意(限制 100 请求/分钟)
    dateFormat X
    axisFormat %S

    section 窗口1 (0-60s)
    已处理请求 (98)    :done, 0, 58

    section 窗口2 (60-120s)
    已处理请求 (100)   :done, 60, 120

    section 临界问题
    窗口1末尾 (50请求) :crit, 55, 60
    窗口2开头 (50请求) :crit, 60, 65

滑动窗口

image

本质:主动保护系统资源,避免因请求量远超承载能力而导致整体崩溃。

2. 熔断(Circuit Breaker)

熔断器持续监控下游服务的健康状况,当错误率、超时率或并发数超过预设阈值时,自动进入“打开”状态,拒绝后续请求,直接走降级逻辑。

状态机:Closed → Open → Half-Open(探测恢复)

本质:快速失败,阻断故障扩散,避免雪崩效应。

3. 降级(Fallback)

降级是在熔断触发或服务不可用时,主动提供备选方案,使系统仍能返回部分可用结果。

降级策略分为:

  • 空结果降级(非核心路径)
  • 错误传递降级(核心路径)
  • 跳过功能降级(可选增强功能)
  • 多级降级(备用配置重试)

本质:在部分功能不可用时,保证系统基本可用性。

二、机制关系图

graph LR
    A[用户请求] --> B{限流检查}
    B -->|通过| C{熔断器状态}
    B -->|拒绝| D[返回限流错误]
    C -->|关闭| E[调用下游服务]
    C -->|打开| F[触发降级]
    E -->|成功| G[返回结果]
    E -->|失败| H[记录错误率]
    H -->|超过阈值| I[打开熔断器]
    I --> F
    F --> J[返回降级结果]
    I -->|SleepWindow 后| K[半开状态]
    K -->|成功| L[关闭熔断器]
    K -->|失败| I

三、代码实践(基于 Hystrix)

1. 限流配置(并发限流)

hystrix.ConfigureCommand("SplitQuery", hystrix.CommandConfig{
    Timeout:               11000,
    MaxConcurrentRequests: 100,   // 核心限流参数
    RequestVolumeThreshold: 10,
    ErrorPercentThreshold:  50,
    SleepWindow:           30000,
})

超过 100 个并发请求时,后续请求立即失败,无需等待下游。

2. 熔断 + 降级使用示例(Wiki 检索)

err := hystrix.Do("WikiRetrieval", func() error {
    wikiResults, err = retrieval.NewWikiRetrieval().Query(ctx, ...)
    return err
}, func(err error) error {
    logger.Warnf("WikiRetrieval circuit breaker open, err: %v", err)
    wikiResults = []entity.WikiInfo{} // 空结果降级
    return nil                        // 不阻塞主流程
})
// 第一级:Hystrix 熔断
err = hystrix.Do("WebSearch", func() error {
    resp, err = cseCall...Do()
    return err
}, func(err error) error {
    logger.Warnf("Google search circuit breaker triggered")
    return err // 返回错误,触发上层 backup
})

// 第二级:备用配置重试
if isRateLimitError(err) && len(backupConfigs) > 0 {
    result, backupErr := executeWithBackup(...)
    if backupErr == nil {
        return result, nil
    }
}

四、最佳实践

熔断器配置推荐值

hystrix.CommandConfig{
    Timeout:                5000,  // P99 + 20% 缓冲
    MaxConcurrentRequests:  50,    // 根据下游实际容量设置
    RequestVolumeThreshold: 10,    // 统计窗口最小请求数
    ErrorPercentThreshold:  50,    // 错误率阈值
    SleepWindow:            30000, // 30~60s 给下游恢复时间
}

降级策略选择表

场景 推荐策略 返回值 影响范围
并行检索通道 空结果降级 [] 或 nil 不影响主流程
核心功能 错误传递 原始 error 上层必须处理
可选增强功能 跳过功能 nil 仅跳过该功能
有备用配置 多级降级 触发 backup 提升可用性

监控建议

// 暴露熔断状态
g.GET("/hystrix/circuit-breakers", func(c *gin.Context) {
    for _, cmd := range enum.HystrixCommands {
        if circuit, _, _ := hystrix.GetCircuit(cmd); circuit != nil {
            // 返回 is_open、allow_request 等状态
        }
    }
})

五、总结

机制 核心作用 主要手段 实践原则
限流 防止过载 令牌桶 / MaxConcurrentRequests 优先级最高,先保护自己
熔断 阻断故障扩散 错误率/慢调用 + 状态机 快速失败,给下游恢复时间
降级 保证基本可用 空结果/缓存/多级 backup 根据功能重要性分层设计

实践铁律

  1. 先做限流,保护系统不被击垮;
  2. 再做熔断,阻断故障蔓延;
  3. 最后做降级,确保“坏了也能用”。

三者配合得当,系统才能在高并发、故障频发的真实生产环境中保持稳定。