文章目录
- 一、开篇:流控之后,还需要熔断
- 二、熔断规则核心参数解析
- 2.1 DegradeRule的完整字段
- 2.2 三种熔断策略对照
- 三、慢调用比例熔断实战
- 3.1 配置示例
- 3.2 熔断触发条件
- 3.3 熔断后的行为
- 3.4 生产配置建议
- 四、异常比例与异常数熔断实战
- 4.1 异常比例熔断
- 4.2 异常数熔断
- 4.3 三种策略组合使用
- 五、断路器状态机与DegradeSlot源码解析
- 5.1 两种断路器实现
- 5.2 DegradeSlot的entry与exit
- 5.3 tryPass的核心逻辑
- 5.4 状态转换的触发时机
- 5.5 熔断器状态机图示
- 六、系统自适应保护
- 6.1 核心理念
- 6.2 五种系统规则阈值类型
- 6.3 配置示例
- 6.4 Load保护的特殊逻辑
- 七、集群限流
- 7.1 为什么需要集群限流
- 7.2 Token Server与Token Client
- 7.3 集群流控规则配置
- 7.4 Token Server部署方式
- 7.5 Token Server高可用方案
- 八、踩坑指南
- 坑一:熔断规则count配反了
- 坑二:熔断后没有降级响应
- 坑三:熔断恢复后立即再次熔断
- 坑四:系统自适应保护的Load阈值不生效
- 坑五:集群限流Token Server不可用导致全局限流失效
- 坑六:集群限流规则ID不唯一导致规则冲突
- 九、课后作业
- 十、下节预告
- 🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航
适配版本:Sentinel 1.8.9、Spring Cloud Alibaba 2025.1.0.0、Spring Cloud 2025.1.3(Oakwood)、Spring Boot 4.0.8、JDK 21
课程定位:熔断限流容错阶段进阶,从熔断三种策略到系统自适应保护,从状态机源码到集群限流部署,构建完整的容错闭环
一、开篇:流控之后,还需要熔断
第22课我们完成了Sentinel流控的全方位实战:直接/关联/链路三种模式、快速失败/Warm Up/排队等待三种效果、热点参数限流、规则持久化到Nacos。流控解决的是“流量太大”的问题——当请求量超过阈值时,主动拒绝或排队,保护系统不被过载压垮。
但流控有一个前提假设:被限流的资源本身是健康的。如果下游服务已经出现故障(如响应时间从50ms飙升到5秒),继续向它发送请求,即使QPS在阈值以内,也会导致线程被阻塞、调用链被拖垮。这时候需要的是熔断——检测到下游服务异常后,主动切断调用,让上游服务快速失败或返回降级响应。
熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。熔断器的工作模式是三个状态的循环:关闭 → 打开 → 半开 → 关闭。关闭状态下正常放行;打开状态下所有请求立即失败(不发送到下游);半开状态下放行少量请求探测下游是否恢复。
本课将从熔断的三种策略讲起,深入DegradeSlot的源码和断路器状态机,实战慢调用比例、异常比例、异常数三种熔断规则的配置,然后讲解系统自适应保护的五种阈值类型,最后完成集群限流的Token Server部署。
二、熔断规则核心参数解析
2.1 DegradeRule的完整字段
熔断降级规则由DegradeRule类定义,包含以下核心字段:
publicclassDegradeRuleextendsAbstractRule{privateintgrade;// 熔断策略类型privatedoublecount;// 阈值(含义取决于grade)privateinttimeWindow;// 熔断后恢复时间(秒)privateintminRequestAmount;// 最小请求数(防止统计噪声)privatedoubleslowRatioThreshold;// 慢请求比例阈值(仅RT模式)privateintstatIntervalMs;// 统计窗口长度(毫秒,默认1000ms)}2.2 三种熔断策略对照
| 策略 | grade值 | count含义 | 触发条件 | 适用场景 |
|---|---|---|---|---|
| 慢调用比例 | 0(DEGRADE_GRADE_RT) | 慢调用临界RT(毫秒) | 统计窗口内请求数≥minRequestAmount,且慢调用比例≥slowRatioThreshold | 下游服务响应变慢 |
| 异常比例 | 1(DEGRADE_GRADE_EXCEPTION_RATIO) | 异常比例阈值(0.0~1.0) | 统计窗口内请求数≥minRequestAmount,且异常比例≥count | 下游服务异常率升高 |
| 异常数 | 2(DEGRADE_GRADE_EXCEPTION_COUNT) | 每秒异常数阈值 | 统计窗口内异常数≥count | 快速失败,对异常数敏感 |
关键理解:从Sentinel 1.8开始,RT模式不再看“平均RT”,而是看“慢请求比例”——统计窗口内,响应时间超过count的请求占比超过slowRatioThreshold时才触发熔断。这比1.7之前的“连续N个请求都超时”更科学,避免了因个别慢请求导致的误熔断。
三、慢调用比例熔断实战
3.1 配置示例
@ConfigurationpublicclassDegradeRuleConfig{@PostConstructpublicvoidinitDegradeRules(){List<DegradeRule>rules=newArrayList<>();// 慢调用比例熔断DegradeRuleslowRule=newDegradeRule("callPaymentService").setGrade(RuleConstant.DEGRADE_GRADE_RT)// 慢调用比例模式.setCount(1000)// 慢调用RT阈值:1000ms.setSlowRatioThreshold(0.5)// 慢调用比例阈值:50%.setMinRequestAmount(5)// 最小请求数:5.setTimeWindow(10)// 熔断时长:10秒.setStatIntervalMs(10000);// 统计窗口:10秒rules.add(slowRule);DegradeRuleManager.loadRules(rules);}}配置解析:
| 参数 | 值 | 含义 |
|---|---|---|
count | 1000 | 响应时间超过1000ms的请求记为“慢调用” |
slowRatioThreshold | 0.5 | 慢调用比例超过50%触发熔断 |
minRequestAmount | 5 | 统计窗口内至少有5个请求才做判断 |
timeWindow | 10 | 熔断后10秒内请求快速失败 |
statIntervalMs | 10000 | 统计窗口为10秒 |
3.2 熔断触发条件
触发熔断的完整条件(三个条件同时满足):
- 统计窗口(
statIntervalMs)内,总请求数 ≥minRequestAmount - 慢调用(RT >
count)的比例 ≥slowRatioThreshold - 当前断路器状态为CLOSED
3.3 熔断后的行为
熔断触发后,断路器从CLOSED变为OPEN:
- OPEN状态:
timeWindow秒内,所有请求被立即拒绝,抛出DegradeException - HALF_OPEN状态:
timeWindow到期后,断路器进入半开状态,放行一个探测请求- 如果探测请求的RT <
count(不是慢调用),断路器恢复到CLOSED - 如果探测请求仍然是慢调用,断路器重新回到OPEN,重新计时
- 如果探测请求的RT <
3.4 生产配置建议
| 场景 | count(RT阈值) | slowRatioThreshold | timeWindow |
|---|---|---|---|
| 支付/订单等核心服务 | 800ms | 0.3 | 30秒 |
| 商品查询等一般服务 | 500ms | 0.5 | 10秒 |
| 日志上报等非核心服务 | 2000ms | 0.8 | 5秒 |
黄金法则:count应设置为下游服务P99响应时间的1.5~2倍。如果下游P99是300ms,count设为500-600ms。设置过低会导致正常的慢请求被误判,设置过高则失去熔断的意义。
四、异常比例与异常数熔断实战
4.1 异常比例熔断
DegradeRuleexceptionRatioRule=newDegradeRule("callUserService").setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)// 异常比例模式.setCount(0.5)// 异常比例阈值:50%.setMinRequestAmount(10)// 最小请求数:10.setTimeWindow(30)// 熔断时长:30秒.setStatIntervalMs(10000);// 统计窗口:10秒触发条件:统计窗口内请求数 ≥ 10,且异常比例 ≥ 50%。
异常比例的统计范围:异常降级仅针对业务异常,对Sentinel限流降级本身的异常(BlockException)不生效。需要通过Tracer.trace(ex)记录业务异常,或使用@SentinelResource注解(会自动统计)。
4.2 异常数熔断
DegradeRuleexceptionCountRule=newDegradeRule("callInventoryService").setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)// 异常数模式.setCount(20)// 异常数阈值:20.setTimeWindow(60)// 熔断时长:60秒.setStatIntervalMs(60000);// 统计窗口:60秒触发条件:统计窗口内异常数 ≥ 20。
异常比例 vs 异常数:异常比例适用于请求量大且相对稳定的场景(比例更有统计意义);异常数适用于请求量小或波动大的场景(比例容易被少数请求扭曲)。
4.3 三种策略组合使用
同一个资源可以配置多条熔断规则,任意一条触发即熔断:
List<DegradeRule>rules=newArrayList<>();rules.add(newDegradeRule("callUserService").setGrade(RuleConstant.DEGRADE_GRADE_RT).setCount(500).setSlowRatioThreshold(0.6).setMinRequestAmount(10).setTimeWindow(30));rules.add(newDegradeRule("callUserService").setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO).setCount(0.5).setMinRequestAmount(10).setTimeWindow(30));rules.add(newDegradeRule("callUserService").setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT).setCount(30).setTimeWindow(30));DegradeRuleManager.loadRules(rules);五、断路器状态机与DegradeSlot源码解析
5.1 两种断路器实现
Sentinel的断路器分为两类:
| 断路器类 | 适用策略 | 统计维度 |
|---|---|---|
ResponseTimeCircuitBreaker | 慢调用比例 | 慢调用数、总请求数 |
ExceptionCircuitBreaker | 异常比例、异常数 | 异常数、总请求数 |
5.2 DegradeSlot的entry与exit
DegradeSlot是ProcessorSlotChain的最后一环,负责熔断规则的校验:
publicclassDegradeSlotextendsAbstractLinkedProcessorSlot<DefaultNode>{@Overridepublicvoidentry(Contextcontext,ResourceWrapperresourceWrapper,DefaultNodenode,intcount,booleanprioritized,Object...args){// 执行熔断检查performChecking(context,resourceWrapper);// 继续执行(实际上已无下一个Slot)fireEntry(context,resourceWrapper,node,count,prioritized,args);}privatevoidperformChecking(Contextcontext,ResourceWrapperr)throwsBlockException{List<CircuitBreaker>circuitBreakers=DegradeRuleManager.getCircuitBreakers(r.getName());if(circuitBreakers==null||circuitBreakers.isEmpty())return;for(CircuitBreakercb:circuitBreakers){if(!cb.tryPass(context)){thrownewDegradeException(cb.getRule().getLimitApp(),cb.getRule());}}}}执行时机:DegradeSlot.entry()在请求进入时执行,检查断路器是否允许通过。DegradeSlot.exit()在请求完成时执行,触发circuitBreaker.onRequestComplete()回调,更新统计指标并判断是否触发状态转换。
5.3 tryPass的核心逻辑
publicbooleantryPass(Contextcontext){// 1. 当前状态为CLOSED → 允许通过if(currentState.get()==State.CLOSED){returntrue;}// 2. 当前状态为OPEN → 检查是否已过熔断时长if(currentState.get()==State.OPEN){// 熔断时长已到 → 尝试转换为HALF_OPENif(currentState.compareAndSet(State.OPEN,State.HALF_OPEN)){// 成功转换,放行探测请求returntrue;}// 熔断时长未到 → 拒绝returnfalse;}// 3. 当前状态为HALF_OPEN// 只放行一个探测请求,其他请求拒绝returncurrentState.compareAndSet(State.HALF_OPEN,State.HALF_OPEN);}5.4 状态转换的触发时机
| 状态转换 | 触发条件 | 执行位置 |
|---|---|---|
| CLOSED → OPEN | 统计窗口内慢调用/异常比例超过阈值 | onRequestComplete() |
| OPEN → HALF_OPEN | timeWindow到期 | tryPass() |
| HALF_OPEN → CLOSED | 探测请求成功 | onRequestComplete() |
| HALF_OPEN → OPEN | 探测请求失败(慢调用或异常) | onRequestComplete() |
5.5 熔断器状态机图示
┌──────────┐ │ CLOSED │ 正常状态,所有请求通过 │ (关闭) │ 统计慢调用/异常指标 └────┬─────┘ │ 触发熔断条件 │ (慢调用比例 ≥ slowRatioThreshold │ 或 异常比例 ≥ count │ 或 异常数 ≥ count) ▼ ┌──────────┐ │ OPEN │ 熔断状态,所有请求被拒绝 │ (打开) │ 返回 DegradeException └────┬─────┘ │ timeWindow 到期 ▼ ┌──────────┐ │HALF_OPEN │ 半开状态,放行一个探测请求 │ (半开) │ └────┬─────┘ │ ├─── 探测请求成功(RT < count 且无异常) │ → 恢复 CLOSED │ └─── 探测请求失败(慢调用或异常) → 重新 OPEN,重新计时六、系统自适应保护
6.1 核心理念
Sentinel系统自适应保护从整体维度对应用入口流量进行控制,结合应用的Load、总体平均RT、入口QPS和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡。
传统方案根据load1阈值来决定是否限流,存在两个问题:负载是“果”而非“因”,调整通过率后需要等待一段时间才能看到效果;下游恢复后负载仍然很高,恢复缓慢。Sentinel借鉴了TCP BBR的思想:用load1作为启动控制流量的值,而允许通过的流量由处理请求的能力(响应时间、当前QPS)来决定。
6.2 五种系统规则阈值类型
| 类型 | 触发条件 | 说明 |
|---|---|---|
| Load | load1 > 阈值 且 并发线程数 > 系统容量 | 仅对Linux/Unix生效,系统容量 = maxQps × minRt |
| CPU使用率 | CPU使用率 > 阈值 | 取值范围0.0~1.0 |
| 平均RT | 所有入口流量的平均RT > 阈值 | 单位毫秒 |
| 并发线程数 | 所有入口流量的并发线程数 > 阈值 | 全局维度 |
| 入口QPS | 所有入口流量的QPS > 阈值 | 全局维度 |
重要限制:系统规则是应用整体维度的,不是资源维度的,且仅对入口流量(EntryType.IN)生效。
6.3 配置示例
@ConfigurationpublicclassSystemRuleConfig{@PostConstructpublicvoidinitSystemRules(){List<SystemRule>rules=newArrayList<>();// CPU使用率超过80%触发系统保护SystemRulecpuRule=newSystemRule();cpuRule.setHighestCpuUsage(0.8);rules.add(cpuRule);// 入口QPS超过10000触发系统保护SystemRuleqpsRule=newSystemRule();qpsRule.setQps(10000);rules.add(qpsRule);// 并发线程数超过500触发系统保护SystemRulethreadRule=newSystemRule();threadRule.setMaxThread(500);rules.add(threadRule);SystemRuleManager.loadRules(rules);}}6.4 Load保护的特殊逻辑
Load保护的触发条件较为特殊,需要同时满足两个条件:
- 当前系统load1 >
highestSystemLoad阈值 - 当前并发请求数 > 系统容量(系统容量 =
maxQps × minRt)
为什么需要两个条件?仅凭load1判断会误伤——load1高可能是由于I/O等待而非CPU竞争。加上并发数的判断后,只有在“系统确实处理不过来”时才触发保护,避免了对正常高负载的误判。
Load阈值设定参考值:CPU cores × 2.5。例如4核机器,Load阈值设为10。
七、集群限流
7.1 为什么需要集群限流
单机限流存在一个根本问题:流量分配不均匀。假设集群有10台机器,每台限流10 QPS,理论上集群总量100 QPS。但实际流量可能不均匀——某些机器收到15 QPS被限流,而其他机器只收到5 QPS,导致“总量没到,但部分机器已经限流”。
集群限流可以精确控制整个集群的调用总量,确保不管流量如何分布,总QPS始终不超过预设阈值。
7.2 Token Server与Token Client
集群流控中有两种身份:
| 身份 | 职责 |
|---|---|
| Token Server | 集群流控服务端,处理来自Token Client的请求,根据规则判断是否发放令牌 |
| Token Client | 集群流控客户端,向Token Server申请令牌,根据返回结果决定是否限流 |
通信机制:Token Client向Token Server发送令牌申请请求,Token Server根据当前集群的QPS统计和规则阈值,判断是否发放令牌。如果发放,Client放行请求;如果不发放,Client执行本地限流逻辑。
7.3 集群流控规则配置
FlowRule添加集群模式:
ClusterFlowConfigclusterConfig=newClusterFlowConfig().setFlowId(1L)// 全局唯一的规则ID.setThresholdType(ClusterRuleConstant.FLOW_THRESHOLD_GLOBAL)// 全局阈值模式.setFallbackToLocalWhenFail(true);// Token Server不可用时回退到本地限流FlowRulerule=newFlowRule("cluster-resource").setGrade(RuleConstant.FLOW_GRADE_QPS).setCount(1000)// 集群总QPS阈值.setClusterMode(true).setClusterConfig(clusterConfig);FlowRuleManager.loadRules(Collections.singletonList(rule));关键字段说明:
| 字段 | 含义 | 说明 |
|---|---|---|
flowId | 全局唯一规则ID | 由管控端分配,保持全局唯一 |
thresholdType | 阈值模式 | 0=单机均摊,1=全局阈值 |
fallbackToLocalWhenFail | 回退策略 | Token Server不可用时是否回退到本地限流 |
单机均摊 vs 全局阈值:单机均摊模式下,配置的阈值等同于单机承受限额,Token Server根据连接数计算总阈值(3个Client连接,单机阈值10,总阈值30);全局模式下,配置的阈值就是整个集群的总阈值。
7.4 Token Server部署方式
方式一:独立模式。单独部署一个Token Server进程,所有Token Client连接到它:
ClusterTokenServertokenServer=newSentinelDefaultTokenServer();tokenServer.start();方式二:嵌入模式。集群中选择一个节点同时作为Token Server和Token Client:
// 在应用启动时,将当前节点嵌入为Token ServerClusterTokenServertokenServer=newSentinelDefaultTokenServer();tokenServer.start();// 同时将当前节点作为Token ClientClusterStateManager.applyState(ClusterStateManager.CLUSTER_CLIENT);生产建议:独立模式更稳定(Token Server故障不影响业务节点),但需要额外的部署资源;嵌入模式节省资源,但Token Server节点的故障会影响整个集群的限流功能。推荐使用独立模式,并通过Nacos实现Token Server的自动选举和故障转移。
7.5 Token Server高可用方案
Token Server本身如果成为单点,整个集群限流功能就会失效。高可用方案如下:
方案一:Nacos自主选举。借助Nacos注册中心,集群中所有节点注册到Nacos,选取注册列表中第一个节点作为Token Server。如果Token Server不可用,重新选举。
方案二:Sentinel Dashboard指定。通过Sentinel Dashboard手动指定某个节点为Token Server,其他节点作为Token Client。Dashboard提供了集群流控的配置界面。
方案三:Fallback保护。配置fallbackToLocalWhenFail=true,当Token Client无法连接Token Server时,自动回退到本地单机限流模式,保证服务不会因Token Server故障而完全不可用。
八、踩坑指南
坑一:熔断规则count配反了
现象:慢调用比例模式下,count设为0.5,但期望的是RT阈值500ms。
原因:混淆了count和slowRatioThreshold。慢调用比例模式下,count是RT阈值(毫秒),slowRatioThreshold才是慢调用比例阈值(0.0~1.0)。
解决:setCount(500)设置RT阈值,setSlowRatioThreshold(0.5)设置比例阈值。
坑二:熔断后没有降级响应
现象:熔断触发后,返回的是Sentinel默认的DegradeException,前端无法处理。
原因:未配置blockHandler或BlockExceptionHandler。
解决:使用@SentinelResource的blockHandler指定降级方法,或实现BlockExceptionHandler接口统一处理(第22课6.2节)。
坑三:熔断恢复后立即再次熔断
现象:熔断时长到期后,第一个探测请求通过,但随后立即再次熔断。
原因:下游服务的问题没有真正恢复,探测请求仍然是慢调用或异常。
解决:这是正常行为——熔断器的半开状态本身就是“试探性恢复”。应检查下游服务是否真正恢复健康,或适当增加timeWindow给下游更长的恢复时间。
坑四:系统自适应保护的Load阈值不生效
现象:配置了Load保护规则,但系统load1已经很高,仍然没有触发限流。
原因:Load保护需要同时满足“load1 > 阈值”和“并发线程数 > 系统容量”两个条件。如果并发数不够高,即使load1很高也不会触发。
解决:检查并发线程数是否超过maxQps × minRt。如果并发数不足,Load保护不会生效——这是设计行为,避免对正常高负载的误判。
坑五:集群限流Token Server不可用导致全局限流失效
现象:Token Server宕机后,所有Token Client的集群限流完全失效,流量全部放行。
原因:未配置fallbackToLocalWhenFail=true。
解决:始终设置fallbackToLocalWhenFail=true,确保Token Server不可用时自动回退到本地单机限流,保证基本的保护能力。
坑六:集群限流规则ID不唯一导致规则冲突
现象:多个集群限流规则配置了相同的flowId,导致限流行为异常。
原因:flowId是全局唯一的,不能重复。
解决:由管控端统一分配flowId,或使用数据库自增ID确保唯一性。
九、课后作业
作业一:为callUserService资源配置慢调用比例熔断:RT阈值800ms,慢调用比例阈值50%,最小请求数5,熔断时长15秒。模拟下游服务响应缓慢(Thread.sleep(1000)),验证熔断触发和恢复。
作业二:为callPaymentService资源配置异常比例熔断:异常比例阈值40%,最小请求数10,熔断时长30秒。通过人为抛出异常验证熔断触发,观察异常比例从上升到达标再到熔断的完整过程。
作业三:配置系统自适应保护规则,CPU使用率阈值0.8,入口QPS阈值5000,并发线程数阈值300。使用压测工具施加压力,观察哪个维度的阈值最先触发。
作业四:部署Token Server(独立模式),配置集群限流规则(全局阈值模式,QPS=1000)。启动两个Token Client实例,验证集群总QPS精确控制在1000以内。然后停止Token Server,验证fallbackToLocalWhenFail回退机制。
作业五(进阶):阅读DegradeSlot和ResponseTimeCircuitBreaker源码,画出慢调用比例熔断的完整状态转换图,标注每个状态转换的触发条件和执行方法。
十、下节预告
第24课将进入Sentinel网关限流、授权规则 & 生产级容错方案。内容包括Gateway网关专属限流(Sentinel集成Gateway)、黑白名单授权规则、IP限流、用户维度限流、规则Nacos持久化的完整实战,以及生产环境的故障演练和容错体系搭建。本课完成了Sentinel的熔断降级和系统保护,第24课将把Sentinel的能力扩展到网关层,并构建完整的生产级容错体系。
🔗《最新版 SpringCloud 2025 从入门到实战》系列课程导航
去订阅
第一部分:微服务前置基础 & 新版环境搭建(第1-5课)
第二部分:注册中心核心(Nacos 最新版)(第6-9课)
第三部分:配置中心核心(Nacos配置中心)(第10-12课)
第四部分:服务通信核心(OpenFeign + LoadBalancer)(第13-16课)
第五部分:网关核心(SpringCloud Gateway 新版)(第17-20课)
第六部分:熔断、限流、降级(Sentinel 新版)(第21-24课)
第七部分:微服务监控、链路追踪、日志体系(第25-28课)
第八部分:微服务高阶特性 & 分布式核心能力(第29-31课)
第九部分:企业级完整项目实战 & 架构复盘(第32-35课)