一、前言
在微服务应用中,服务存在一定的依赖关系,如果某个目标服务调用慢或者有大量超时造成服务不可用,间接导致其他的依赖服务不可用,最严重的可能会阻塞整条依赖链,最终导致业务系统崩溃(又称雪崩效应)。
上述的问题将是本篇需要解决的问题。
二、简单介绍
# 2.1 请求熔断
断路器是一种开关设置,当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个符合预期的服务降级处理(fallback),而不是长时间的等待或者抛出调用方无法处理的异常,这样保证了服务调用方的线程不会长时间被占用,从而避免了故障在分布式系统的蔓延乃至崩溃。
# 2.2 服务降级
fallback 相当于是降级操作。对于查询操作, 我们可以实现一个 fallback 方法, 当请求后端服务出现异常的时候, 可以使用 fallback 方法返回的值。 fallback 方法的返回值一般是设置的默认值或者来自缓存,告知后面的请求服务不可用了,不要再请求了。
# 2.3 实现方案
Spring Cloud Hystrix 实现了断路器、线程隔离等一系列服务保护功能。它是基于 Netflix 的开源框架 Hystrix 实现的,该框架的目的在于通过控制访问远程系统、服务和第三方库节点,从而对延迟和故障提供更强大的容错能力。
Hystrix 具备服务熔断、服务降级、线程和信号隔离、请求缓存、请求合并以及服务监控的能力。
三、请求熔断实战
本次测试案例基于之前发表的文章中介绍的案例进行演示,不清楚的读者请先转移至 《Spring Cloud 入门 之 Feign 篇(三)》 进行浏览。
现在的项目列表如下:
服务实例 |
端口 |
描述 |
common-api |
- |
公用的 api,如:实体类 |
eureka-server |
9000 |
注册中心(Eureka 服务端) |
goods-server |
8081 |
商品服务(Eureka 客户端) |
goods-server-02 |
8082 |
商品服务(Eureka 客户端) |
goods-server-03 |
8083 |
商品服务(Eureka 客户端) |
order-server |
8100 |
订单服务(Eureka 客户端) |
在 goods-server (3个)项目中:
# 3.1 添加依赖
- <!-- hystrix -->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
- </dependency>
# 3.2 设置熔断策略
我们来修改获取商品的方法,给它设置熔断策略:
- @Service
- public class GoodsServiceImpl implements GoodsService{
- // 模拟数据库
- private static Map<String, Goods> data;
- static {
- data = new HashMap<>();
- data.put("1", new Goods("1", "手机", "国产手机", 8081));
- data.put("2", new Goods("2", "电脑", "台式电脑", 8081));
- @Override
- @HystrixCommand(fallbackMethod = "defaultByHystrix")
- public Goods findGoodsById(String goodsId) {
- Goods goods = data.get(goodsId);
- if (goods == null) {
- throw new RuntimeException("商品不存在");
- return goods;
- public Goods defaultByHystrix(String goodsId) {
- return new Goods("-1", "商品", "默认商品", 8081);
在 findGoodsById 方法上加 @HystrixCommand 注解。当调用商品服务超时或出现异常时,Hystrix 会调用 @HystrixCommand 中指定的 fallbackMethod 方法获取返回值,并返回给调用者。
注意:fallbackMethod 方法要求与正常方法有相同的入参和回参。
# 3.3 启动熔断功能
在启动类上添加 @EnableCircuitBreaker 注解:
- @EnableCircuitBreaker
- @EnableEurekaClient
- @SpringBootApplication
- public class GoodsServerApplication {
- public static void main(String[] args) {
- SpringApplication.run(GoodsServerApplication.class, args);
# 3.4 熔断测试
- 我们首先演示服务提供方没有开启熔断的功能,即先把上边的 @EnableCircuitBreaker 注解进行注释。
启动好所有项目,使用 Postman 请求 order-server 进行下单操作,运行结果如下:
由于我们请求发送的 goodsId 的商品不存在,服务提供方抛会异常,调用方无法处理,因此只能展示图中的异常信息。
- 下面,我们再将 @EnableCircuitBreaker 注解的注释放开,运行结果如下:
从图中可知,虽然客户端请求了一个 goodsId 不存在的商品,但是由于服务提供方开启了熔断机制,返回了一个默认的商品,从而使接口能正常通信而不是抛出调用方不可处理的异常导致整个系统不能正常运行。
看到这里,或许会有读者产生一个疑问,如果服务方定义 N 个方法,是不是意味着同时也要定义 N 个异常处理的方法呢,答案是否定的。
Hystrix 还提供了 @DefaultProperties 统一处理请求熔断。
- @Service
- @DefaultProperties(defaultFallback = "defaultByHystrix")
- public class GoodsServiceImpl implements GoodsService{
- // 模拟数据库
- private static Map<String, Goods> data;
- static {
- data = new HashMap<>();
- data.put("1", new Goods("1", "手机", "国产手机", 8081));
- data.put("2", new Goods("2", "电脑", "台式电脑", 8081));
- @Override
- @HystrixCommand
- public Goods findGoodsById(String goodsId) {
- Goods goods = data.get(goodsId);
- if (goods == null) {
- throw new RuntimeException("商品不存在");
- return goods;
- public Goods defaultByHystrix() {
- return new Goods("-1", "商品", "默认商品", 8081);
注意:defaultFallback 定义的方法必须是无参的。
四、服务降级实战
在 common-api 项目中:
# 4.1 定义 Fallback
- @Component
- public class GoodsServiceClientFallbackFactory implements FallbackFactory<GoodsServiceClient> {
- @Override
- public GoodsServiceClient create(Throwable cause) {
- return new GoodsServiceClient() {
- @Override
- public Result goodsInfo(String goodsId) {
- return Result.fail(500, "商品服务系统出现异常,请联系管理员");
- };
使用单独的类处理异常逻辑,当与服务端无法正常通信时调用此类中的方法返回结果。
# 4.2 修改 Feign 客户端
将上边定义好的 FallbackFactory 设置到 @FeignClient 注解上:
- @FeignClient(value="GOODS", fallbackFactory = GoodsServiceClientFallbackFactory.class)
- public interface GoodsServiceClient {
- @RequestMapping("/goods/goodsInfo/{goodsId}")
- public Result goodsInfo(@PathVariable("goodsId") String goodsId);
# 4.3 开启服务降级功能
在 order-server 项目中:
- server:
- port: 8100
- spring:
- application:
- name: ORDER
- eureka:
- instance:
- instance-id: order-api-8100
- prefer-ip-address: true # 访问路径可以显示 IP
- client:
- service-url:
- defaultZone: http://localhost:9000/eureka/ # 注册中心访问地址
- feign:
- hystrix:
- enabled: true
在启动类上加 FallbackFactory 类的包扫描目录:
- @ComponentScan(basePackages = {"com.extlight.springcloud"}) // 为了能扫描 common-api 项目中的 GoodsServiceClientFallbackFactory
- @EnableFeignClients(basePackages = {"com.extlight.springcloud"})
- @EnableEurekaClient
- @SpringBootApplication
- public class OrderServerApplication {
- public static void main(String[] args) {
- SpringApplication.run(OrderServerApplication.class, args);
打开 Postman 请求下单接口,结果如下图:
我们手动关闭商品服务,模拟异常情况,当订单服务再次访问商品服务时并不是一直等待请求响应,而是直接返回 fallback 信息。
五、仪表盘
除了服务熔断、降级的功能外,Hystrix 还提供了准及时的调用监控。 Hystrix 会持续地记录所有通过 Hystrix 发起的请求的执行信息,并以统计报表和图形方式展示给用户。
# 5.1 配置被监控方
goods-server (3个)项目中:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
修改 application.yml,开放端口:
- management:
- endpoints:
- web:
- exposure:
- include: "*"
# 5.2 配置监控方
1.新建一个名为 hystrix-dashboard 项目,添加如下依赖:
- <!-- hystrix-dashboard -->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
- </dependency>
2.新建 application.yml
- server:
- port: 9300
- spring:
- application:
- name: Hystrix-Dashboard
3.开启监控功能
在启动类上添加 @EnableHystrixDashboard 注解。
- @EnableHystrixDashboard
- @SpringBootApplication
- public class HystrixdashboardApplication {
- public static void main(String[] args) {
- SpringApplication.run(HystrixdashboardApplication.class, args);
启动,浏览器访问: http://localhost:9300/hystrix :
# 5.3 监控设置
我们以监控 goods-server 为例,在监控界面添加监控信息:
- # 需要监控的服务地址
- http://localhost:8081/actuator/hystrix.stream
- delay: 请求间隔时间
- title: 监控名称
- 点击 monitor stream
- 多次访问 goods-server 项目接口。
最终效果如下:
如何查看监控信息呢?
实心圆:通过颜色的变化代表实例的健康程度,健康度从绿色>黄色>橙色>红色递减。其大小也会根据实例的请求流量发生变化,流量越大实心圆越大。
曲线:用来记录间隔时间内流量的相对变化,通常可以观察到流量的上升和下降趋势。
六、案例源码
Hystrix demo 源码
七、参考资料
hystrix-javanica
hystrix configuration
hystrix dashboard
https://www.extlight.com/2019/03/19/Spring-Cloud-入门-之-Hystrix-篇(四)/