在分布式系统中,服务间依赖关系复杂,任何一点异常都可能引发连锁反应。限流、熔断、降级是应对流量冲击、故障传播和部分失效的三大利器,三者配合使用,能显著提升系统的稳定性和用户体验。本文结合实际代码,系统梳理三者的概念、关系、实践方法与最佳配置。
一、核心概念
1. 限流(Rate Limiting)
限流是对单位时间内请求数量进行显式限制的机制,目的是防止系统被突发流量击垮。
| 算法 | 原理简述 | 优点 | 缺点 | 是否允许突发 | 典型应用场景 | 代表实现 |
|---|---|---|---|---|---|---|
| 固定窗口 | 固定时间段(如1s)内计数请求,超过阈值拒绝,窗口结束清零 | 实现最简单、内存开销极低 | 临界问题(窗口边界突发可瞬间超限) | 否 | 简单并发控制、秒杀 | Redis INCR + EXPIRE |
| 滑动窗口 | 将时间切分成N个小窗口,滑动统计最近一段时间的总请求数 | 解决临界问题,统计更平滑 | 实现稍复杂,需维护队列 | 否 | 高并发API、Hystrix/Sentinel统计 | Sentinel滑动窗口、Guava |
| 漏桶 | 请求进入“桶”,以固定速率“漏出”处理,桶满则拒绝 | 输出速率绝对平滑,保护下游 | 无法应对突发(即使空闲也匀速) | 否 | 保护下游接口、匀速排队 | Nginx limit_req、Sentinel匀速排队 |
| 令牌桶 | 以固定速率向桶中生成令牌,请求需消耗令牌通过,桶可积累 | 允许一定突发,限制平均速率 | 短时可能有少量超发 | 是 | 网关限流、接口调用(最常用) | Guava RateLimiter、Redisson |
典型实现方式包括令牌桶、漏桶、固定窗口、滑动窗口等

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

漏桶:只有等到了水滴,才能被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
滑动窗口

本质:主动保护系统资源,避免因请求量远超承载能力而导致整体崩溃。
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 // 不阻塞主流程
})
3. 多级降级示例(Google Search)
// 第一级: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 | 根据功能重要性分层设计 |
实践铁律:
- 先做限流,保护系统不被击垮;
- 再做熔断,阻断故障蔓延;
- 最后做降级,确保“坏了也能用”。
三者配合得当,系统才能在高并发、故障频发的真实生产环境中保持稳定。