SpringCloud——CircuitBreaker断路器
一、Hystrix目前也进入维护模式
(1)是什么
- 了解一下即可,2024年了不再使用Hystrix
- Hystrix 是一款开源的分布式系统容错框架,通过熔断机制(自动切断故障依赖)、资源隔离(限制线程 / 信号量)和降级回退(提供友好替代响应),防止单个服务故障引发级联崩溃,保障系统在高并发或依赖异常时仍能保持弹性
(2)Hystrix官宣,停更进维
(3)Hystrix未来替换方案
二、概述
(1)2023年影响极大的真实生产故障
(2)分布式系统面临的问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败
(3)我们的诉求
- 问题:禁止服务雪崩故障
- 解决:有问题的节点,快速熔断(快速返回失败处理或者返回默认兜底数据【服务降级】)
- Hystrix断路器是一种分布式系统故障防护机制,通过实时监控服务异常(如超时、错误),在检测到故障时自动触发熔断,快速返回预设的降级响应(FallBack),避免客户端线程被长时间阻塞,并切断故障传播链,防止雪崩效应,保障系统整体可用性
(4)如何搞定上述问题,避免整个系统大面积故障
2.4.1给我搞定
(1)服务熔断
- 类比保险丝,保险丝闭合状态 (CLOSE) 可以正常使用,当达到最大服务访问后,直接拒绝访问跳闸限电 (OPEN),此刻调用方会接受服务降级的处理并返回友好兜底提示
- 就是家里保险丝,从闭合 CLOSE 供电状态→跳闸 OPEN 打开状态
(2)服务降级
- 服务器忙,请稍后再试
- 不让客户端等待并立刻返回一个友好提示,fallback
(3)服务限流
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟 N 个,有序进行
(4)服务限时
(5)服务预热
(6)接近实时的监控
(7)兜底的处理动作
2.4.2NOW
我们用什么替代?Spring Cloud Circuit Breaker
三、Circuit Breaker是什么
(1)官网
Spring Cloud Circuit Breaker
(2)实现原理
CircuitBreaker 用于保护分布式系统,提升可用性与健壮性。当组件或服务故障时,它切换至 OPEN 状态,阻断请求发送,减少故障方负载以防止崩溃,确保系统继续运行;还能通过在组件间自动切换,避免单点故障问题
(3)一句话
Circuit Breaker 只是一套规范和接口,落地实现者是 Resilience4J
四、Resilience4J
(1)是什么
GitHub - resilience4j/resilience4j: Resilience4j is a fault tolerance library designed for Java8 and functional programming
(2)能干嘛
GitHub - resilience4j/resilience4j: Resilience4j is a fault tolerance library designed for Java8 and functional programming
(3)怎么玩
- 官网:CircuitBreaker
- 中文手册:
五、案例实战
(1)熔断(CircuitBreaker)
5.1.1断路器3大状态
5.1.2断路器3大状态之间的转换
5.1.3断路器所有配置参数参考
(1)英文
CircuitBreaker
(2)中文手册




- 网址:
- 默认 CircuitBreaker.java 配置类:io.github.resilience4j.circuitbreaker.CircuitBreakerConfig
- 中文手册精简版:
5.1.4熔断+降级案例需求说明
- 6次访问中当执行方法的失败率达到50%时CircuitBreaker将进入开启OPEN状态(保险丝跳闸断电)拒绝所有请求
- 等待5秒后,CircuitBreaker 将自动从开启OPEN状态过渡到半开HALF_OPEN状态,允许一些请求通过以测试服务是否恢复正常
- 如还是异常CircuitBreaker 将重新进入开启OPEN状态;如正常将进入关闭CLOSE闭合状态恢复正常处理请求
5.1.5按照COUNT_BASED(计数的滑动窗口)
(1)修改cloud-provider-payment8001
新建PayCircuitController
package com.atguigu.cloud.controller;
import cn.hutool.core.util.IdUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
public class PayCircuitController {
@GetMapping(value = "/pay/circuit/{id}")
public String myCircuit(@PathVariable("id") Integer id){
if (id == -4) {
throw new RuntimeException("------ Circuit id 不能负数");
}
if (id == 9999) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Hello, circuit! inputId: "+id+" \t " + IdUtil.simpleUUID();
}
}
(2)修改PayFeignApi接口
(3)修改cloud-consumer-order80
- 改POM
<!--resilience4j-circuitbreaker--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId> </dependency> <!-- 由于断路保护等需要AOP实现,所以必须导入AOP包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
- 写YML
resilience4j: circuitbreaker: configs: default: failureRateThreshold: 50 slidingWindowType: COUNT_BASED slidingWindowSize: 6 minimumNumberOfCalls: 6 automaticTransitionFromOpenToHalfOpenEnabled: true waitDurationInOpenState: 5s permittedNumberOfCallsInHalfOpenState: 2 recordExceptions: - java.lang.Exception instances: cloud-payment-service: baseConfig: default
- 新建OrderCircuitController
- @CircuitBreaker
- 系统繁忙,请稍后再试。不让调用者等待,并立刻返回一个友好提示
(4)测试(按照错误次数达到多少后开启断路)
- 自测cloud-consumer-feign-order80
- 查看YML
- 正确
- 错误
- 一次error,一次OK,试试看看
- 50%错误后触发熔断并给出服务降级,告知调用者服务不可用
- 此时就算是输入正确的访问地址也无法调用服务,它还在断路中(OPEN状态),一会儿过渡到半开并继续正确地址访问,慢慢切换回CLOSED状态
- 多次故意填写错误值(-4):多次故意填写错误值(-4),然后慢慢填写正确值(正整数11),发现刚开始不满足条件,就算是正确的访问地址也不能进行
5.1.6按照TIME_BASED(时间的滑动窗口)
(1)基于时间的滑动窗口
(2)修改cloud-consumer-feign-order80
(3)为避免实验效果,记得关闭FeignConfig字节写的重试三次
(4)测试(慢查询)
- 一次超时,一次正常访问,同时进行
- http://localhost/feign/pay/circuit/9999
- http://localhost/feign/pay/circuit/11
- http://localhost/feign/pay/circuit/9999
- 第1~4个超时,整多一点4个,一次访问,同时进行
- http://localhost/feign/pay/circuit/9999
- 正常访问也受到了牵连,因为服务熔断不能访问了
- http://localhost/feign/pay/circuit/9999
5.1.7小总结
(1)断路器开启或者关闭的条件:
- 当满足一定的峰值和失败率达到一定条件后,断路器将会进入 OPEN 状态(保险丝跳闸),服务熔断
- 当 OPEN 的时候,所有请求都不会调用主业务逻辑方法,而是直接走 fallbackmethod 兜底方法,服务降级
- 一段时间之后,断路器会从 OPEN 进入到 HALF OPEN 半开状态,会放几个请求过去探探链路是否通?如成功,断路器会关闭 CLOSE(类似保险丝闭合,恢复可用);如失败,继续开启。重复上述
(2)个人建议不要混合用,推荐按照调用次数 count_based,一家之言仅供参考
(2)隔离(BulkHead)
5.2.1官网
- Bulkhead
- 中文:https://github.com/Imhml/Resilience4j-Guides-Chinese/blob/main/core-modules/bulkhead.md
5.2.2是什么
限并发
5.2.3能干嘛
依赖隔离 & 负载保护:用来限制对于下游服务的最大并发数量的限制
5.2.4Resilience4j提供了如下两种隔离的实现方式,可以限制并发执行的数量
5.2.5实现SemaphoreBulkhead(信号量舱壁)
(1)概述
- 基本上就是我们JUC信号灯内容的同样思想
- 信号量舱壁(SemaphoreBulkhead)原理
- 当信号量有空闲时,进入系统的请求会直接获取信号量并开始业务处理
- 当信号量全被占用时,接下来的请求将会进入阻塞状态,SemaphoreBulkhead提供了一个阻塞计时器,如果阻塞状态的请求在阻塞计时内无法获取到信号量则系统会拒绝这些请求
- 若请求在阻塞计时内获取到了信号量,那将直接获取信号量并执行相应的业务处理
(2)源码分析
io.github.resilience4j.bulkhead.internal.SemaphoreBulkhead
(3)cloud-provider-payment8001 支付微服务,修改 PayCircuitController
(4)ayFeignApi 接口新增舱壁 api 方法
(5)修改 cloud-consumer-feign-order80
- POM
<!--resilience4j-bulkhead--> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-bulkhead</artifactId> </dependency>
- YML
- 示例:
- 内容:
- 示例:
- 业务类(OrderCircuitController)
(6)测试
- 步骤:
- 浏览器新打开2个窗口,各点一次,分别点击http://localhost/feign/pay/bulkhead/9999
- 每个请求调用需要耗时5秒,2个线程瞬间达到配置过的最大并发数2
- 此时第3个请求正常的请求访问,http://localhost/feign/pay/bulkhead/3
- 直接被舱壁限制隔离了,碰不到8001
- 等其中一个窗口停止了,再去正常访问,并发数小于2 了,可以OK
- 结果:
5.2.6实现FixedThreadPoolBulkhead(固定线程池舱壁)

(1)概述
- FixedThreadPoolBulkhead的功能与SemaphoreBulkhead一样也是用于限制并发执行的次数的,但是二者的实现原理存在差别而且表现效果也存在细微的差别。FixedThreadPoolBulkhead使用一个固定线程池和一个等待队列来实现舱壁
- 当线程池中存在空闲时,则此时进入系统的请求将直接进入线程池开启新线程或使用空闲线程来处理请求
- 当线程池中无空闲时时,接下来的请求将进入等待队列,若等待队列仍然无剩余空间时接下来的请求将直接被拒绝, 在队列中的请求等待线程池出现空闲时,将进入线程池进行业务处理
- 另外:ThreadPoolBulkhead只对CompletableFuture方法有效,所以我们必创建返回CompletableFuture类型的方法
(2)源码分析
- io.github.resilience4j.bulkhead.internal.FixedThreadPoolBulkhead
- 底子就是 JUC 里面的线程池 ThreadPoolExecutor
- submit 进线程池返回 CompletableFuture<T>
(3)修改cloud-consumer-feign-order80
- POM
<!--resilience4j-bulkhead--> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-bulkhead</artifactId> </dependency>
- YML
- controller
(4)测试地址
(3)限流(RateLimiter)
5.3.1官网
- RateLimiter
- 中文:Resilience4j-Guides-Chinese/core-modules/ratelimiter.md at main · lmhmhl/Resilience4j-Guides-Chinese · GitHub
5.3.2是什么
5.3.3面试题:说说常见限流算法
- 漏斗算法 (Leaky Bucket)
- 令牌桶算法 (Token Bucket)(SpringCloud默认使用该算法)
- 滚动时间窗 (tumbling time window)
- 滑动时间窗口 (sliding time window)
5.3.4cloud-provider-payment8001支付微服务修改PayCircuitController新增myRateLimit方法
5.3.5PayFeignApi接口新增限流api方法
5.3.6修改cloud-consumer-feign-order80
- POM
<!--resilience4j-ratelimiter--> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-ratelimiter</artifactId> </dependency>
- YML
- order的controller