《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Spring-Cloud/Netflix-Hystrix/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labslabx-23 目录。

原创不易,给点个 Star 嘿,一起冲鸭!

1. 概述

在开始 Spring Cloud Netflix Hystrix 的学习之前,我们先来一起瞅瞅“服务雪崩”、“服务容错”等的概念,方便我们理解为什么要使用 Hystrix 框架。

1.1 服务雪崩

在微服务的架构体系中,我们会将系统拆分成多个服务小单元,通过 HTTP 或者 RPC 进行远程调用。如下图所示:

服务雪崩 - 正常

在绝大多数情况下,服务消费者都能正常的远程调用服务提供者。但是某一时刻,服务提供者执行逻辑较慢,又或者网络出现抖动的情况,导致服务消费调用服务提供者超时或者失败。如下图所示:

服务雪崩 - 调用失败

如果这个情况持续一段时间,服务提供者的响应一直很慢,导致服务消费者的响应也跟着很慢,最终引起服务消费者的请求任务积压,也跟着一起出问题了。如下图所示:

友情提示:以 SpringMVC 提供 API 接口举例子,因为 Tomcat 的线程池是有限的,如果个别请求处理很慢,会逐步占用到整个线程池,导致后续其它请求无法被处理。

服务雪崩 - 服务雪崩

这种因为一个下游服务的故障,导致上游服务一起跟着故障的现象,我们称为“服务雪崩”。

1.2 服务容错

针对“服务雪崩”的情况,我们需要进行“服务容错”处理。解决的方向很“简单”,尽量不要去调用故障的服务,避免被拖垮。一般常用的手段有,主要是限流开关

① 限流

通过限制调用服务的频率,避免频繁调用故障服务,导致请求任务积压而自身雪崩。

② 开关

通过关闭对故障服务的调用,停止调用故障服务,从而避免服务雪崩。当然,关闭的前提是,不调用故障服务的情况下,业务逻辑依然可以走下去,或者业务数据的完整性不会被破坏。

一般来说,开关会分成手动开关和自动开关。手动开关比较好了解,自动开关是满足指定条件自动进行关闭。

自动开关比较经典的就是“断路器模式”,它源于 Martin Fowler 大佬在 《CircuitBreaker》 文章的分享。

“断路器”,又称自动开关,它是一种既有手动开关作用,又能自动进行失压、欠压、过载、和短路保护的电器

它可用来分配电能,不频繁地启动异步电动机,对电源线路及电动机等实行保护,当它们发生严重的过载或者短路及欠压等故障时能自动切断电路,其功能相当于熔断器式开关与过欠热继电器等的组合。而且在分断故障电流后一般不需要变更零部件,一获得了广泛的应用。

在微服务架构中,“断路器模式”的用途也是类似的。当某个服务提供者发生故障(相当于电器发生短路的情况)时,断路器一旦监控到这个情况,会将开关进行自动关闭。之后,在服务消费者调用该故障服务提供者时,直接抛出错误异常,不进行调用,从而避免调用服务的漫长等待。

友情提示:如果这么描述比较晦涩,稍后我们以 Hystrix 提供的断路器功能,结合它的状态来具体来瞅瞅哈。

1.3 Hystrix

Hystrix 是 Netflix 开源的分布式系统的延迟和容错库。

Hystrix 供分布式系统使用,提供延迟和容错功能,隔离远程系统、访问和第三方程序库的访问点,防止级联失败,保证复杂的分布系统在面临不可避免的失败时,仍能有其弹性。

Hystrix 图标

Netflix 称,在分布式环境中,不可避免会造成一些服务的失败。Hystrix 库旨在控制分布式服务中提供更大容限和服务失败之间的相互关系。Hystrix 通过隔离访问远程系统、服务和第三方库的点,阻止级联故障,从而使复杂的分布式系统更具弹性。

Hystrix 源于 Netflix API 团队在去年启动的弹性工程项目,在此期间,Hystrix 得到了不断发展,并逐渐成熟。现在,在 Netflix 网站中,每天有数十亿的独立线程和信号通过 Hystrix 进行调用,Hystrix 的运行时间和弹性也得到了显著的改善。

Hystrix 比较重要的是三个特性:1)Fallback 服务降级;2)断路器机制;3)资源隔离。

1.3.1 Fallback 服务降级

在服务调用失败时,我们可以通过 Hystrix 实现 Fallback 服务降级。

例如说,对于查询操作,我们给它实现一个 fallback 方法。当请求服务提供者发生异常时,我们可以执行 fallback 方法获得返回结果。示例代码如下:

fallback 示例

一般情况下,fallback 方法的返回结果使用设置的默认值,又或者来自缓存。

友情提示:如果想要深入了解,可阅读《Hystrix 源码解析 —— 请求执行(四)之失败回退逻辑》

1.3.2 断路器机制

Hystrix 内置断路器 HystrixCircuitBreaker 实现,一共有三种状态:

  • CLOSED :关闭
  • OPEN :打开
  • HALF_OPEN :半开

牛逼!HystrixCircuitBreaker 比较神来之笔,就是增加了 HALF_OPEN 状态,不仅仅实现了自动化的关闭,还实现了自动化的打开

其中,断路器处于 OPEN 状态时,链路处于非健康状态,命令执行时,直接调用回退逻辑,跳过正常逻辑。

HystrixCircuitBreaker 状态变迁如下图 :

红线 :初始时,断路器处于 CLOSED 状态,链路处于健康状态。当满足如下条件,断路器从 CLOSED 变成 OPEN 状态:

  • 周期( 可配,HystrixCommandProperties.default_metricsRollingStatisticalWindow = 10000 ms )内,总请求数超过一定( 可配,HystrixCommandProperties.circuitBreakerRequestVolumeThreshold = 20 ) 。
  • 错误请求占总请求数超过一定比例( 可配,HystrixCommandProperties.circuitBreakerErrorThresholdPercentage = 50% ) 。

绿线 :断路器处于 OPEN 状态,命令执行时,若当前时间超过断路器开启时间一定时间( HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds = 5000 ms ),断路器变成 HALF_OPEN 状态,尝试调用正常逻辑,根据执行是否成功,打开或关闭熔断器【蓝线】。

友情提示:如果想要深入了解,可阅读《Hystrix 源码解析 —— 断路器 HystrixCircuitBreaker》

1.3.3 资源隔离

Hystrix 使用了“舱壁隔离模式”来隔离和限制各个请求,从而实现资源的隔离。

Hystrix 通过线程池信号量(Semaphore 两种模式来实现隔离。

① 线程池模式

默认情况下,Hystrix 采用线程池模式来实现隔离。

针对调用的每一个服务,我们给其单独分配一个线程池。例如说,产品服务的调用分配在 A 线程池,用户服务的调用分配在 B 线程池。这样隔离后,两个服务的调用不会相互影响。

② 信号量模式

使用线程池模式来隔离时,需要进行上下文的切换,带来一定的性能损耗。因此,如果对性能有较高要求,且能够接受信号量模式不支持超时的情况,可以考虑采用信号量模式。

友情提示:如果想要深入了解,可阅读《Hystrix 源码解析 —— 命令执行(二)之执行隔离策略》

1.4 Spring Cloud Netflix Hystrix

Spring Cloud Netflix 提供的 spring-cloud-netflix-hystrix 组件,基于 Spring Cloud 的编程模型中的 CircuitBreaker,接入 Hystrix 作为断路器,实现服务容错的功能。

下面,我们正式开始本文的旅程,开始学习 Spring Cloud Netflix Hystrix 咯。

2. 快速入门

示例代码对应仓库:

本小节,我们来搭建一个 Hystrix 组件的快速入门示例。步骤如下:

  • 首先,搭建一个 user-service 用户服务,提供获取用户信息的 HTTP API 接口。
  • 然后,搭建一个用户服务的消费者,使用 Hystrix 实现服务容错。

2.1 搭建用户服务

创建 labx-23-user-service 项目,搭建用户服务。代码如下图所示:

项目代码

比较简单,主要是提供 http://127.0.0.1:18080/user/get 接口,获取用户详情。具体的代码,肯定不用艿艿啰嗦讲解哈,点击 labx-23-user-service 查看。

2.2 搭建 Hystrix 示例项目

创建 labx-23-scn-hystrix-demo01 项目,搭建一个用户服务的消费者,使用 Hystrix 实现服务容错。代码如下图所示:

项目代码

2.2.1 引入依赖

pom.xml 文件中,引入 Spring Cloud Netflix Hystrix 相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>labx-23-scn-hystrix-demo01</artifactId>

<properties>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>

<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 引入 Spring Cloud Netflix Hystrix 相关依赖,将 Hystrix 作为服务保障组件,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>

</project>将 Hystrix 作为服务保障组件,并实现对其的自动配置

通过 spring-cloud-starter-netflix-hystrix 包,引入 Spring Cloud Netflix Hystrix 相关依赖,将 Hystrix 作为服务保障组件,并实现对其的自动配置。

2.2.2 DemoApplication

创建 DemoApplication 类,作为 Hystrix 示例项目的启动类。代码如下:

@SpringBootApplication
@EnableCircuitBreaker // <1> 声明开启断路器
public class DemoApplication {

@Bean
public RestTemplate restTemplate() { // <2>
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}

<1> 处,在类上添加 @EnableCircuitBreaker 注解,声明开启断路器功能。

<2> 处,创建 RestTemplate Bean,用于后续调用用户服务 HTTP API 接口。

2.2.3 DemoController

创建 DemoController 类,提供调用用户服务的 HTTP API 接口。代码如下:

@RestController
@RequestMapping("/demo")
public class DemoController {

private Logger logger = LoggerFactory.getLogger(getClass());

@Autowired
private RestTemplate restTemplate;

@GetMapping("/get_user")
@HystrixCommand(fallbackMethod = "getUserFallback")
public String getUser(@RequestParam("id") Integer id) {
logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id);
return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody();
}

public String getUserFallback(Integer id, Throwable throwable) {
logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable));
return "mock:User:" + id;
}

}

① 在 #getUser(Integer id) 方法,我们使用 RestTemplate 调用用户服务提供的 /user/get 接口,获取用户详情。

② 在 #getUser(Integer id) 方法,添加了 Hystrix 提供的 @HystrixCommand 注解,设置执行发生 Exception 异常时,执行 fallbackMethod 属性对应的 #getUserFallback(Integer id, Throwable throwable) 方法。注意,fallbackMethod 方法的参数要和原始方法一致,最后一个为 Throwable 异常

通过不同的 Throwable 异常,我们可以进行不同的 fallback 降级处理。极端情况下,Hystrix 断路器熔断(打开)时,不会执行 #getUser(Integer id) 方法,而是直接抛出 Hystrix circuit short-circuited and is OPEN 异常,然后也是进入 fallback 降级处理。

③ 我们来完整看看 @HystrixCommand 注解的参数:

1. fallbackMethod 属性:

指定 fallback 服务降级的处理方法,处理相应的异常。

2. ignoreExceptions 属性:

指定忽略指定的异常 Class,不进行 fallback 服务降级。

3. commandKey 属性:

Hystrix Command 命令,默认未配置情况下,使用方法名。例如说,我们上面的 #getUser(...) 对应的 commandKey 属性默认为 getUser

4. groupKey 属性:

Hystrix Command 命令分组键,用于 Hystrix 根据不同的分组来统计命令的统计、告警、仪表盘信息。

默认未配置情况下,使用方法所在类名。例如说,我们上面的 #getUser(...) 方法所在类为 DemoController,则对应的 groupKey 属性默认为 DemoController。

5. threadPoolKey 属性

线程池名,用于划分不同的线程池,进行资源隔离。

默认未配置情况下,相同 groupKey 的 Hystrix Command 使用同一个线程池。在配置情况下,相同 groupKey + threadPoolKey 使用同一个线程池。也就是说,groupKey必选基础维度,而 threadPoolKey可选的进一步细化维度。

2.3 简单测试

执行 DemoApplication 启动用户服务,执行 UserServiceApplication 启动 Hystrix 示例项目。

① 使用浏览器,访问 http://127.0.0.1:8080/demo/get_user?id=1 地址,成功调用用户服务,返回结果为 User:1

② 停止 DemoApplication 关闭用户服务。

使用浏览器,访问 http://127.0.0.1:8080/demo/get_user?id=1 地址,失败调用用户服务,返回结果为 mock:User:1

此时我们会看到如下日志,可以判断触发 Hystrix 的 fallback 服务降级的方法。

2020-05-09 22:32:07.729  INFO 68093 --- [emoController-6] c.i.s.l.h.controller.DemoController      : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-09 22:32:07.731 INFO 68093 --- [emoController-6] c.i.s.l.h.controller.DemoController : [getUserFallback][id(1) exception(ConnectException: Connection refused (Connection refused))]

疯狂使用浏览器,访问 http://127.0.0.1:8080/demo/get_user?id=1 地址,会触发 Hystrix 断路器熔断(打开),不再执行 #getUser(Integer id) 方法,而是直接 fallback 触发 #getUserFallback(Integer id, Throwable throwable) 方法。日志内容如下:

2020-05-09 22:34:20.946  INFO 68093 --- [nio-8080-exec-2] c.i.s.l.h.controller.DemoController      : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
2020-05-09 22:34:21.099 INFO 68093 --- [nio-8080-exec-3] c.i.s.l.h.controller.DemoController : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
2020-05-09 22:34:21.173 INFO 68093 --- [nio-8080-exec-4] c.i.s.l.h.controller.DemoController : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]

④ 重新执行 UserServiceApplication 启动用户服务。

使用浏览器,多次访问 http://127.0.0.1:8080/demo/get_user?id=1 地址,Hystrix 断路器的状态逐步从打开 => 半开 => 关闭。日志内容如下:

// 打开
2020-05-09 22:39:05.226 INFO 68093 --- [io-8080-exec-10] c.i.s.l.h.controller.DemoController : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
...

// 半开
[getUser][准备调用 user-service 获取用户(1)详情]

// 关闭
[getUser][准备调用 user-service 获取用户(1)详情]
[getUser][准备调用 user-service 获取用户(1)详情]
[getUser][准备调用 user-service 获取用户(1)详情]
...

3. 请求缓存

示例代码对应仓库:

Hystrix 支持在同一个 HystrixRequestContext 上下文中,提供缓存的功能,以提升高并发场景下的性能,同时也带来相同缓存键返回相同结果的特性。

通过 Hystrix 主要提供了 @CacheResult@CacheRemove 注解,我们可以使用 Hystrix 请求缓存功能。

@CacheResult 注解,添加在方法上,声明将方法的执行结果进行缓存,并后续从缓存中获取结果。

  • cacheKeyMethod 属性:设置缓存键的生成方法。

另外,我们也可以使用 @CacheKey 注解,直接设置缓存键的字符串,它的优先级比 `@CacheResult.cacheKeyMethod` 属性高。不过可以先暂时忽略哈~

@CacheRemove 注解,添加在方法上,声明移除指定 Hystrix Command 生成的缓存。

  • commandKey 属性:设置 Hystrix Command
  • cacheKeyMethod 属性:设置缓存键的生成方法。

下面,我们直接在「2. 快速入门」小节的基础上,直接增加 Hystrix 请求缓存相关的代码。改动点如下图所示:

项目调整

友情提示:以下的内容,我们都是修改 Hystrix 示例项目。

3.1 HystrixRequestContextFilter

创建 HystrixRequestContextFilter 类,基于 HTTP 请求级别创建 HystrixRequestContext 上下文。代码如下:

@Component
@WebFilter(urlPatterns = "/")
public class HystrixRequestContextFilter implements Filter {

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 初始化 HystrixRequestContext
HystrixRequestContext context = HystrixRequestContext.initializeContext();
// 继续过滤器
try {
chain.doFilter(request, response);
} finally {
// 销毁 HystrixRequestContext
context.close();
}
}

}

😈 这里的代码,可以使用 try with resources 简化成如下,不过考虑方便胖友清晰理解,就暂时没这么干哈~

3.2 CacheDemoService

创建 CacheDemoService 类,提供 Hystrix 使用的示例,代码如下:

@Service
public class CacheDemoService {

private Logger logger = LoggerFactory.getLogger(CacheDemoService.class);

@Autowired
private RestTemplate restTemplate;

@HystrixCommand(fallbackMethod = "getUserFallback")
@CacheResult(cacheKeyMethod = "genGetUserCacheKey")
public String getUser(Integer id) {
logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id);
return restTemplate.getForEntity("http://127.0.0.1:18080/user/get?id=" + id, String.class).getBody();
}

@HystrixCommand
@CacheRemove(commandKey = "getUser", cacheKeyMethod = "genGetUserCacheKey")
public void updateUser(Integer id) {
logger.info("[updateUser][更新用户({})详情]", id);
}

public String getUserFallback(Integer id, Throwable throwable) {
logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable));
return "mock:User:" + id;
}

public String genGetUserCacheKey(Integer id) {
return "USER_" + id;
}

}

① 在 #getUser(Integer id) 方法上,添加 @CacheResult 注解,并设置 cacheKeyMethod 缓存键的方法为 #genGetUserCacheKey(Integer id)

② 在 #updateUser(Integer id) 方法上,添加 @CacheRemove 注解,在设置 cacheKeyMethod 缓存键的方法为 #genGetUserCacheKey(Integer id) 之外,还需要设置 commandKey Hystrix Command 键为 getUser

3.3 CacheDemoController

创建 CacheDemoController 类,提供示例接口。代码如下:

@RestController
@RequestMapping("/cache-demo")
public class CacheDemoController {

@Autowired
private CacheDemoService cacheDemoService;

@GetMapping("/get_user")
public String getUser(@RequestParam("id") Integer id) {
String userA = cacheDemoService.getUser(id);
String userB = cacheDemoService.getUser(id);
String userC = cacheDemoService.getUser(id);
return userC;
}

@GetMapping("/update_user")
public String updateUser(@RequestParam("id") Integer id) {
String userA = cacheDemoService.getUser(id);
cacheDemoService.updateUser(id);
String userC = cacheDemoService.getUser(id);
return userC;
}

}

① 在 /cache-demo/get_user 接口中,我们连续调用了 CacheDemoService#getUser(Integer id) 方法三次,测试后两次是不是直接从缓存中获取结果

② 在 /cache-demo/update_user 接口中,我们在中间调用了 CacheDemoService#updateUser(Integer id) 方法,看看最后一次是不是需要重新执行,不走缓存

3.4 简单测试

执行 UserServiceApplication 启动用户服务,执行 DemoApplication 启动 Hystrix 示例项目。

① 使用浏览器,访问 http://127.0.0.1:8080/cache-demo/get_user?id=1 地址,IDEA 控制台打印日志如下:

2020-05-12 08:52:06.137  INFO 21899 --- [heDemoService-1] c.i.s.l.h.service.CacheDemoService       : [getUser][准备调用 user-service 获取用户(1)详情]

真正执行了 CacheDemoService#getUser(Integer id) 方法一次,后面两次都是从缓存中获得结果。

② 使用浏览器,访问 http://127.0.0.1:8080/cache-demo/update_user?id=1 地址,IDEA 控制台打印日志如下:

2020-05-12 08:53:04.817  INFO 21899 --- [heDemoService-2] c.i.s.l.h.service.CacheDemoService       : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-12 08:53:04.829 INFO 21899 --- [heDemoService-3] c.i.s.l.h.service.CacheDemoService : [updateUser][更新用户(1)详情]
2020-05-12 08:53:04.832 INFO 21899 --- [heDemoService-4] c.i.s.l.h.service.CacheDemoService : [getUser][准备调用 user-service 获取用户(1)详情]

最后执行 CacheDemoService#getUser(Integer id) 方法,说明 CacheDemoService#update(Integer id) 方法有清理缓存

友情提示:想要进一步深入的胖友,可以阅读《Hystrix 源码解析 —— 执行结果缓存》文章。

4. 请求合并

示例代码对应仓库:

Hystrix 支持在同一个 HystrixRequestContext 上下文中,提供请求合并的功能,将一段时间的相同类型的请求,延迟合并请求服务提供者的批量 API 接口,以减少请求次数,减少服务压力。可能有点抽象,我们以用户查询举例子,如下图所示:

用户查询

  • 系统在执行的过程中,需要调用用户服务来查询 A、B、C 三个用户的信息。
  • Hystrix 请求合并会自动将查询 A、B、C 三个用户的请求,通过后台延迟收集的方式,一次性请求用户服务的 /user/gets?ids={ids} 接口。

如果还是觉得有点懵逼,不用慌噢,我们在「2. 快速入门」小节的基础上,直接增加 Hystrix 请求合并相关的代码。改动点如下图所示:

项目结构

4.1 搭建用户服务

修改 labx-23-user-service 项目,在用户服务中增加 /user/batch_get 接口,批量查询用户信息。代码如下图所示:

项目结构

4.2 搭建 Hystrix 示例项目

修改 labx-23-scn-hystrix-demo01 项目,主要增加 Hystrix 请求合并的示例代码,通过 @HystrixCollapser 注解进行声明:

  • collapserKey 属性:Hystrix 合并请求,默认为方法名。
  • batchMethod 属性:合并请求时,执行的方法名。Hystrix 的合并请求,并不能智能的知道调用的批量接口,所以需要手动编写调用方法。
  • scope 属性:合并请求的范围,目前有 REQUEST 请求和 GLOBAL 全局两个级别。
  • collapserProperties 属性:Hystrix 合并请求的拓展变量。一般我们可以通过 "timerDelayInMilliseconds" 变量,来设置延迟的时长。

4.2.1 CollapserDemoService

修改 CollapserDemoService 类,提供 Hystrix 使用的示例,代码如下:

@Service
public class CollapserDemoService {

private Logger logger = LoggerFactory.getLogger(CollapserDemoService.class);

@Autowired
private RestTemplate restTemplate;

@HystrixCollapser(
batchMethod = "getUsers",
collapserProperties = {
@HystrixProperty(name = "timerDelayInMilliseconds", value = "10000") // 演示,所以设置的时间较长
}
)
public Future<String> getUserFuture(Integer id) {
throw new RuntimeException("This method body should not be executed");
}

@HystrixCommand
public List<String> getUsers(List<Integer> ids) {
logger.info("[getUsers][准备调用 user-service 获取多个用户({})详情]", ids);
String[] users = restTemplate.getForEntity("http://127.0.0.1:18080/user/batch_get?ids=" + StringUtils.join(ids, ',')
, String[].class).getBody();
return users == null || users.length == 0 ? Collections.emptyList() : Arrays.asList(users);
}

}

#getUserFuture(Integer id) 方法上,添加 @HystrixCollapser 注解,声明请求合并的操作。

① 通过设置 batchMethod 属性为 "getUsers",从而调用 #getUsers(List<Integer> ids) 方法,调用用户服务的 /user/batch_get?ids={ids} 接口,一次性获取指定编号的用户信息。

友情提示:要注意,batchMethod 对应的批量操作的方法的方法参数只能一个,并且类型规定为 List 类型

同时要注意,返回的结果也要是 List 类型,并且结果是和参数的顺序映射的噢。

② 通过设置 collapserProperties 属性,设置 "timerDelayInMilliseconds" 为 10 秒,设置延迟合并单个请求,进行批量请求的最大等待时间为 10 秒。

友情提示:实际场景下,我们肯定不会设置 10 秒这么大的数值,延迟太久了。胖友可以根据自己的需要,设置 100 毫秒以内。

③ 因为 #getUserFuture(Integer id) 方法不会真正被执行,所以我们在实现中就直接抛出 RuntimeException 异常。

4.2.2 CollapserDemoController

创建 CollapserDemoController 类,提供示例接口。代码如下:

@RestController
@RequestMapping("/collapser-demo")
public class CollapserDemoController {

private Logger logger = LoggerFactory.getLogger(CollapserDemoController.class);

@Autowired
private CollapserDemoService collapserDemoService;

@GetMapping("/test")
public void test() throws ExecutionException, InterruptedException {
logger.info("[test][准备获取用户信息]");
Future<String> user01 = collapserDemoService.getUserFuture(1);
Future<String> user02 = collapserDemoService.getUserFuture(2);
logger.info("[test][提交获取用户信息]");

logger.info("[test][user({}) 的结果为({})]", 1, user01.get());
logger.info("[test][user({}) 的结果为({})]", 2, user02.get());
}

}

/collapser-demo/test 接口中,我们调用了两次 CollapserDemoService#getUserFuture(Integer id) 方法,测试是否会进行请求合并。

同时,打印相应的日志,方便我们确认实际执行的时间。

4.3 简单测试

执行 DemoApplication 启动用户服务,执行 UserServiceApplication 启动 Hystrix 示例项目。

① 使用浏览器,访问 http://127.0.0.1:8080/collapser-demo/test 地址,IDEA 控制台打印日志如下:

2020-05-12 22:03:17.912  INFO 38723 --- [io-8080-exec-10] c.i.s.l.h.c.CollapserDemoController      : [test][准备获取用户信息]
2020-05-12 22:03:17.913 INFO 38723 --- [io-8080-exec-10] c.i.s.l.h.c.CollapserDemoController : [test][提交获取用户信息]

// 10 秒后,发起批量请求
2020-05-12 22:03:27.917 INFO 38723 --- [erDemoService-4] c.i.s.l.h.service.CollapserDemoService : [getUsers][准备调用 user-service 获取多个用户([1, 2])详情]

// 请求执行完成,返回结果
2020-05-12 22:03:27.921 INFO 38723 --- [io-8080-exec-10] c.i.s.l.h.c.CollapserDemoController : [test][user(1) 的结果为(User:1)]
2020-05-12 22:03:27.923 INFO 38723 --- [io-8080-exec-10] c.i.s.l.h.c.CollapserDemoController : [test][user(2) 的结果为(User:2)]

② 在 CollapserDemoController 中,艿艿又额外增加了 /collapser-demo/test_02 接口,交换了下用户 12 的请求顺序。代码如下:

// CollapserDemoController.java

@GetMapping("/test_02")
public void test02() throws ExecutionException, InterruptedException {
logger.info("[test][准备获取用户信息]");
Future<String> user01 = collapserDemoService.getUserFuture(2);
Future<String> user02 = collapserDemoService.getUserFuture(1);
logger.info("[test][提交获取用户信息]");

logger.info("[test][user({}) 的结果为({})]", 1, user01.get());
logger.info("[test][user({}) 的结果为({})]", 2, user02.get());
}

胖友猜测下,打印日志的结果是怎么样的?为什么会导致这样的原因呢?

友情提示:想要进一步深入的胖友,可以阅读《Hystrix 源码解析 —— 命令合并执行》文章。

5. Hystrix Dashboard 监控

示例代码对应仓库:

Spring Cloud Netflix 提供了 spring-cloud-netflix-hystrix-dashboard 组件,提供 Hystrix Dashboard 运维界面的功能,便于我们监控 Hystrix 的运行情况。

Hystrix Dashboard

下面,我们来搭建 Hystrix Dashboard 监控的示例,一共会有三个项目,如下图所示:

项目结构

5.1 搭建用户服务

直接复用 labx-23-user-service 项目,作为用户服务即可。

5.2 搭建 Hystrix 示例项目

基于「2.2 搭建 Hystrix 示例项目」小节的 labx-23-scn-hystrix-demo01 项目,复制labx-23-scn-hystrix-actuator 项目,进行搭建 Hystrix 示例项目,修改点如下图所示:

项目改动点

主要是引入 Spring Boot Actuator 组件,从而暴露 hystrix.stream 端点,提供 Hystrix 监控数据。

① 修改 pom.xml 文件,引入 Spring Boot Actuator 依赖如下:

<!-- 实现对 Actuator 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

② 创建 application.yml 配置文件,配置暴露 hystrix.stream 端点如下:

management:
endpoints:
web:
exposure:
include: 'hystrix.stream' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。

友情提示:对监控端点不了解的胖友,可以访问《芋道 Spring Boot 监控端点 Actuator 入门》文章,进行简单的学习。

下面,我们进行下 hystrix.stream 端点的测试,便于胖友有点画面感。

① 执行 UserServiceApplication 启动用户服务,执行 DemoApplication 启动 Hystrix 示例项目。

② 使用浏览器,访问 http://127.0.0.1:8080/demo/get_user?id=1 地址,执行 Hystrix Command 的调用,从而产生 Hystrix 监控数据。

③ 使用浏览器,访问 http://127.0.0.1:8080/actuator/hystrix.stream 地址,获得 Hystrix 监控数据如下图所示:

`hystrix.stream` 端点

这样一看,胖友是不是就有点感觉了!如此,Hystrix Dashboard 通过调用 hystrix.stream 端点,进行相应的信息展示

5.3 搭建 Hystrix Dashboard

新建 labx-23-scn-hystrix-dashboard 项目,搭建 Hystrix Dashboard 运维界面。整体项目如下图所示:

项目结构

5.3.1 引入依赖

创建 pom.xml 文件,引入 Hystrix Dashboard 依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>labx-23-scn-hystrix-dashboard</artifactId>

<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>

<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 实现对 Hystrix Dashboard 的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>

</project>

添加 spring-cloud-starter-netflix-hystrix-dashboard 来引入 Hystrix Dashboard 依赖,并实现其自动配置。

5.3.2 配置文件

创建 application.yml 配置文件,设置 Hystrix Dashboard 启动端口为 9090

server:
port: 9090

5.3.3 HystrixDashboardApplication

创建 HystrixDashboardApplication 类,作为 Hystrix Dashboard 启动类。代码如下:

@SpringBootApplication
@EnableHystrixDashboard // 声明开启 Hystrix Dashboard 功能
public class HystrixDashboardApplication {

public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}

}

通过添加 @EnableHystrixDashboard 注解,声明开启 Hystrix Dashboard 功能。

5.3.4 简单测试

执行 HystrixDashboardApplication 启动 Hystrix Dashboard。

① 使用浏览器,访问 http://127.0.0.1:9090/hystrix/ 地址,进入 Hystrix Dashboard 首页。如下图所示:

Hystrix Dashboard - 首页 01

② 在框框中,输入 http://127.0.0.1:8080/actuator/hystrix.stream 地址,抓取「5.2 搭建 Hystrix 示例项目」的 Hystrix 监控数据。如下图所示:

Hystrix Dashboard - 首页 02

③ 点击「Monitor Stream」按钮,展示 Hystrix 监控数据。如下图所示:

Hystrix Dashboard - 监控展示

后续,胖友可以不断请求 http://127.0.0.1:8080/actuator/hystrix.stream 地址,产生 Hystrix 监控数据,然后查看 Hystrix Dashboard。

6. Turbine 聚合监控

示例代码对应仓库:

在实际项目中,一个服务我们会部署多个实例,同时一般服务肯定是多个,如果直接使用 Hystrix Dashboard 搭配 hystrix.stream 端点的方式来监控 Hystrix 数据,只能一个一个服务实例进行查看,显然非常不方便。很多时候,我们希望看到所有服务,并且将相同服务实例的 Hystrix 监控数据进行聚合展示。

因此,Netflix 提供了 spring-cloud-netflix-turbine 组件,将所有服务实例的 hystrix.stream 端点提供的监控数据进行聚合,提供给 Hystrix Dashboard 获取并展示。如此,整体架构就变成下图:

整体架构

  • Hystrix Dashboard 不支持抓取服务实例的 hystrix.stream 端点提供的 Hystrix 监控数据,而是抓取 Turbine 聚合各个服务实例后的 Hystrix 监控数据。
  • Turbine 是从注册中心获取所有服务实例的地址,从而抓取它们的 hystrix.stream 端点的 Hystrix 监控数据,进行聚合计算。

下面,我们基于「5. Hystrix Dashboard 监控」小节的基础上,改造使用 Turbine 进行聚合 Hystrix 监控数据。最终项目如下图:

项目结构

6.1 搭建 Eureka 注册中心

参考《芋道 Spring Cloud Netflix 注册中心 Eureka 入门 》文章,搭建 Eureka 注册中心。如下图所示:

Eureka 注册中心 - 项目

具体项目地址是 labx-22-scn-eureka-server-standalone

执行 EurekaServerApplication 类,启动 Eureka 注册中心。启动完成后,访问 http://127.0.0.1:8761/ 地址,确认启动成功。

Eureka 注册中心 - 界面

友情提示:这里使用 Eureka 作为注册中心只是一种选择,除此之外,我们还可以使用其它接入 Spring Cloud 编程模型的注册中心。

例如说,Spring Cloud Alibaba Nacos Discovery。胖友只需要把涉及到 Eureka 相关的依赖和配置改成 Nacos 的即可。

6.2 搭建用户服务

直接复用 labx-23-user-service 项目,作为用户服务即可。

这里不把用户服务注册到 Eureka 注册中心中,因为我们暂时不需要 Turbine 从用户服务采集 Hystrix 监控数据,同时用户服务也没有引入 Hystrix 组件。

6.3 搭建 Hystrix 示例项目

基于「5.2 搭建 Hystrix 示例项目」小节的 labx-23-scn-hystrix-actuator 项目,复制labx-23-scn-hystrix-demo01-cluster 项目,进行搭建 Hystrix 示例项目,修改点如下图所示:

项目改动点

主要是引入 Eureka Client 组件,将 Hystrix 示例项目注册到 Eureka 注册中心,从而能够被 Turbine 获取到。

① 修改 pom.xml 文件,引入 Eureka Client 依赖如下:

<!-- 引入 Spring Cloud Netflix Eureka Client 相关依赖,将 Eureka 作为注册中心的客户端,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

② 修改 application.yml 配置文件,注册到 Eureka 注册中心 :

management:
endpoints:
web:
exposure:
include: 'hystrix.stream' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。

spring:
application:
name: hystrix-demo # 应用名

eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址

① 执行 UserServiceApplication 启动用户服务。

② 执行 DemoApplication 启动 Hystrix 示例项目,端口号为 8080,注册到 Eureka 注册中心。

③ 按照下图配置,然后执行 DemoApplication 启动 Hystrix 示例项目,端口号为 8081,注册到 Eureka 注册中心。

IDEA 配置

如此,我们在 Eureka 注册中心中可以看到 hystrix-demo 两个服务实例。如下图所示:

Eureka 注册中心

6.4 搭建 Hystrix Dashboard + Turbine

基于「5.2 搭建 Hystrix 示例项目」小节的 labx-23-scn-hystrix-dashboard 项目,复制labx-23-scn-hystrix-dashboard-turbine 项目,进行搭建 Hystrix 示例项目,修改点如下图所示:

项目改动点

主要改动点,就是引入 Eureka Client 和 Turbine,下面我们来详细一个一个瞅瞅~

6.4.1 引入依赖

修改 pom.xml 文件,引入 Eureka Client 和 Turbine 依赖。

<!-- 实现对 Turbine 的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>

<!-- 引入 Spring Cloud Netflix Eureka Client 相关依赖,将 Eureka 作为注册中心的客户端,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

主要添加 spring-cloud-starter-netflix-turbine 来引入 Turbine 依赖,并实现其自动配置。

6.4.2 配置文件

修改 application.yml 配置文件,添加 Eureka Client 和 Turbine 配置项。

server:
port: 9090

spring:
application:
name: hystrix-dashboard

eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/ # Eureka-Server 地址

# Turbine 配置项,对应 TurbineProperties 配置类
turbine:
app-config: hystrix-demo # 配置需要 Turbine 聚合的服务名;如果有多个,使用逗号分隔。
combine-host-port: true # 服务是否以 host + port 进行区分,默认为 true。如果设置为 false,则只以 host 进行区分,这样会导致相同主机部署了相同服务的多个实例,会被认为是一个
cluster-name-expression: new String('default') # 指定集群名,设置为 `default` 表示默认集群。

① 通过 eureka.client 配置项,我们可以从 Eureka 注册中心获取实例列表,这样 Turbine 就可以获取对应的地址。

② 通过 turbine 配置项,我们可以配置 Turbine 需要聚合的服务名。

6.4.3 HystrixDashboardApplication

修改 HystrixDashboardApplication 类,添加 @EnableTurbine 注解,声明开启 Turbine 功能。代码如下:

@SpringBootApplication
@EnableHystrixDashboard // 声明开启 Hystrix Dashboard 功能
@EnableTurbine // 声明开启 Turbine 功能
public class HystrixDashboardApplication {

public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}

}

6.4.4 简单测试

执行 HystrixDashboardApplication 启动 Hystrix Dashboard + Turbine

① 使用浏览器,访问 http://127.0.0.1:8080/demo/get_user?id=1http://127.0.0.1:8081/demo/get_user?id=1 地址,执行 Hystrix Command 的调用,从而产生 Hystrix 监控数据。

② 使用浏览器,访问 http://127.0.0.1:9090/turbine.stream 地址,可以获得 Turbine 聚合 Hystrix 监控数据如下图所示:

Turbine 聚合

③ 使用浏览器,访问 http://127.0.0.1:9090/hystrix/ 地址,进入 Hystrix Dashboard 首页。在框框中,输入 http://127.0.0.1:9090/turbine.stream 地址,抓取 Turbine 聚合 Hystrix 监控数据。如下图所示:

  • Hystrix Dashboard —— 首页
  • Hystrix Dashboard —— 监控

7. 集成到 Zuul

传送到《芋道 Spring Cloud Netflix 网关 Zuul 入门》「10. 基于 Hystrix 实现服务容错」小节。

8. 集成到 Spring Cloud Gateway

传送到《芋道 Spring Cloud 网关 Spring Cloud Gateway 入门》「11. 基于 Hystrix 实现服务容错」小节。

9. 集成到 Feign

示例代码对应仓库:

本小节我们来进行 Feign 和 Hystrix 的整合,该功能由 Spring Cloud Alibaba Sentinel 的 feign-hystrix 模块提供。

Feign 是一款声明式 HTTP 客户端,可以更快捷、更优雅的实现 HTTP API 调用。不了解的胖友,推荐阅读下《芋道 Spring Cloud 声明式调用 Feign 入门》文章。

下面,我们来搭建 Feign 和 Hystrix 整合的示例,最终项目如下图所示:

项目结构

9.1 搭建用户服务

直接复用 labx-23-user-service 项目,作为用户服务即可。

9.2 搭建 Hystrix 示例项目

创建 labx-23-scn-hystrix-feign 项目,搭建一个用户服务的消费者,使用 Feign 进行调用,使用 Hystrix 实现服务容错。

9.2.1 引入依赖

创建 pom.xml 文件中,主要引入 Sentinel 和 Feign 相关依赖。代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>labx-23-scn-hystrix-feign</artifactId>

<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
</properties>

<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 引入 Spring Cloud Netflix Hystrix 相关依赖,将 Hystrix 作为服务保障组件,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

<!-- 引入 Spring Cloud OpenFeign 相关依赖,使用 OpenFeign 提供声明式调用,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>

</project>

引入 Hystrix spring-cloud-starter-netflix-hystrixFeign spring-cloud-starter-openfeign 依赖,并实现它们的自动配置。

9.2.2 配置文件

创建 application.yaml 配置文件,设置 feign.hystrix.enabled 配置项为 true,开启 Feign 对 Hystrix 的集成。

feign:
hystrix:
enabled: true # 开启 Hystrix 对 Feign 的支持,默认为 false 关闭。

旁白君:艿艿一开始以为 feign.hystrix.enabled 配置项默认为 true,所以导致 Hystrix 一直不生效。

9.2.3 UserServiceFeignClient

创建 UserServiceFeignClient 接口,接口,实现对用户服务 user-service 声明式调用。代码如下:

@FeignClient(name = "user-service", url = "http://127.0.0.1:18080", fallbackFactory = UserServiceFeignClientFallbackFactory.class)
public interface UserServiceFeignClient {

@GetMapping("/user/get")
String getUser(@RequestParam("id") Integer id);

}

通过 @FeignClient 注解,声明一个 FeignClient 客户端。

name 属性,设置 FeignClient 客户端的名字。

url 属性,设置调用服务的地址。因为我们没有引入注册中心,所以我们直接设置稍后启动的服务 demo-provider 的地址。

fallbackFactory 属性,设置 fallback 工厂类。fallback 的作用是,用于在 HTTP 调动失败而抛出异常的时候,提供 fallback 处理逻辑。

9.2.4 UserServiceFeignClientFallbackFactory

创建 UserServiceFeignClientFallbackFactory 类,用于创建 UserServiceFeignClient 对应 Fallback 实现类的工厂类。代码如下:

@Component // <1>
public class UserServiceFeignClientFallbackFactory implements FallbackFactory<UserServiceFeignClient> {

private Logger logger = LoggerFactory.getLogger(getClass());

@Override
public UserServiceFeignClient create(Throwable cause) {
return new UserServiceFeignClient() { // <2>

@Override
public String getUser(Integer id) {
logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(cause));
return "mock:User:" + id;
}

};
}

}

<1> 处,类上需要添加 @Component 注解,因为 @FeignClient 注解的 fallbackFactory 属性,是通过从 Spring 中获取 fallbackFactory 对应类型的 Bean。

<2> 处,创建 DemoProviderFeignClient 的实现类,这样每个实现方法,能够一一对应,进行 fallback 处理逻辑。

9.2.5 FeignDemoController

创建 FeignDemoController 类,提供一个通过 Feign 调用用户服务提供者的 HTTP 接口。代码如下:

@RestController
@RequestMapping("/feign-demo")
public class FeignDemoController {

private Logger logger = LoggerFactory.getLogger(getClass());

@Autowired
private UserServiceFeignClient userServiceFeignClient;

@GetMapping("/get_user")
public String getUser(@RequestParam("id") Integer id) {
logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id);
return userServiceFeignClient.getUser(id);
}

}

9.2.6 DemoApplication

创建 DemoApplication 类,创建应用启动类。代码如下:

@SpringBootApplication
@EnableCircuitBreaker // 声明开启断路器
@EnableFeignClients // 开启 Feign Client 功能
public class DemoApplication {

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}

@EnableFeignClients 注解,添加在类上,声明开启 Feign 客户端的功能。

9.3 简单测试

执行 DemoApplication 启动用户服务,执行 UserServiceApplication 启动 Hystrix 示例项目。

① 使用浏览器,访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,成功调用用户服务,返回结果为 User:1

② 停止 DemoApplication 关闭用户服务。

使用浏览器,访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,失败调用用户服务,返回结果为 mock:User:1

此时我们会看到如下日志,可以判断触发 Hystrix 的 fallback 服务降级的方法。

2020-05-14 21:22:49.738  INFO 71995 --- [nio-8080-exec-7] c.i.s.l.h.c.FeignDemoController          : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-14 21:22:49.752 INFO 71995 --- [-user-service-6] .f.UserServiceFeignClientFallbackFactory : [getUserFallback][id(1) exception(ConnectException: Connection refused (Connection refused))]

疯狂使用浏览器,访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,会触发 Hystrix 断路器熔断(打开),不再执行 #getUser(Integer id) 方法,而是直接 fallback 触发在 UserServiceFeignClientFallbackFactory 定义的对应 #getUser(Integer id) 方法。日志内容如下:

2020-05-14 21:25:29.262  INFO 71995 --- [io-8080-exec-10] c.i.s.l.h.c.FeignDemoController          : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-14 21:25:29.262 INFO 71995 --- [io-8080-exec-10] .f.UserServiceFeignClientFallbackFactory : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
2020-05-14 21:25:29.340 INFO 71995 --- [nio-8080-exec-1] c.i.s.l.h.c.FeignDemoController : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-14 21:25:29.340 INFO 71995 --- [nio-8080-exec-1] .f.UserServiceFeignClientFallbackFactory : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
2020-05-14 21:25:29.425 INFO 71995 --- [nio-8080-exec-2] c.i.s.l.h.c.FeignDemoController : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-14 21:25:29.426 INFO 71995 --- [nio-8080-exec-2] .f.UserServiceFeignClientFallbackFactory : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]

④ 重新执行 UserServiceApplication 启动用户服务。

使用浏览器,多次访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,Hystrix 断路器的状态逐步从打开 => 半开 => 关闭。日志内容如下:

// 打开
2020-05-14 21:27:28.560 INFO 71995 --- [nio-8080-exec-5] .f.UserServiceFeignClientFallbackFactory : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
...

// 半开
2020-05-14 21:27:37.243 INFO 71995 --- [nio-8080-exec-7] c.i.s.l.h.c.FeignDemoController : [getUser][准备调用 user-service 获取用户(1)详情]

// 关闭
2020-05-14 21:27:39.867 INFO 71995 --- [nio-8080-exec-8] c.i.s.l.h.c.FeignDemoController : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-14 21:28:19.959 INFO 71995 --- [io-8080-exec-10] c.i.s.l.h.c.FeignDemoController : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-14 21:28:21.357 INFO 71995 --- [nio-8080-exec-1] c.i.s.l.h.c.FeignDemoController : [getUser][准备调用 user-service 获取用户(1)详情]
...

10. 集成到 Dubbo

示例代码对应仓库:

本小节我们来进行 Dubbo 和 Hystrix 的整合,目前暂时没有框架或者库提供它们的整合,所以我们只能像「2. 快速入门」小节,使用 @HystrixCommand 注解添加在进行 Dubbo RPC 调用的方法上,如下图所示:

Dubbo 示例 + `@HystrixCommand` 注解

Apache Dubbo™ 是一款高性能Java RPC框架。

下面,我们来搭建 Dubbo 和 Hystrix 整合的示例,最终项目如下图所示:

项目结构

10.1 用户服务 API

创建 labx-23-scn-hystrix-dubbo-demo-user-service-api 项目,作为用户服务 API。如下图所示:

项目结构

10.1.1 引入依赖

创建 pom.xml 文件,无需引入依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23-scn-hystrix-dubbo-demo</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>labx-23-scn-hystrix-dubbo-demo-user-service-api</artifactId>

</project>

10.1.2 UserService

创建 UserService 接口,提供用户服务 API 接口。代码如下:

public interface UserService {

String getUser(Integer id);

}

10.2 用户服务 Provider

创建 labx-23-scn-hystrix-dubbo-demo-user-service 项目,作为用户服务 Provider 实现。如下图所示:

项目结构

友情提示:考虑到本文是 Spring Cloud 相关内容,所以我们采用 Spring Cloud Alibaba Dubbo,不了解的胖友可以看看《芋道 Spring Cloud Alibaba 服务调用 Dubbo 入门》文章。

又考虑到 Nacos 作为注册中心越来越流行,所以这里就使用 Nacos 啦,不了解的胖友可以看看《芋道 Spring Cloud Alibaba 注册中心 Nacos 入门》文章。

10.2.1 引入依赖

创建 pom.xml 文件,引入 Dubbo、Nacos 依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23-scn-hystrix-dubbo-demo</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>labx-23-scn-hystrix-dubbo-demo-user-service</artifactId>

<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>

<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- 引入用户服务 API 包 -->
<dependency>
<groupId>cn.iocoder.springboot.labs</groupId>
<artifactId>labx-23-scn-hystrix-dubbo-demo-user-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

<!-- 引入 Spring Cloud Alibaba Nacos Discovery 相关依赖,将 Nacos 作为注册中心,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- 引入 Spring Cloud Alibaba Dubbo 相关依赖,实现呢 Dubbo 进行远程调用,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
</dependencies>

</project>

10.2.2 配置文件

创建 application.yaml 配置文件,添加 Dubbo 和 Nacos 配置项。

spring:
application:
name: user-service
cloud:
# Nacos 作为注册中心的配置项
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址

# Dubbo 配置项,对应 DubboConfigurationProperties 类
dubbo:
scan:
base-packages: cn.iocoder.springcloud.labx23.userservice.service # 指定 Dubbo 服务实现类的扫描基准包
# Dubbo 服务暴露的协议配置,对应 ProtocolConfig Map
protocols:
dubbo:
name: dubbo # 协议名称
port: -1 # 协议端口,-1 表示自增端口,从 20880 开始
# Dubbo 服务注册中心配置,对应 RegistryConfig 类
registry:
address: spring-cloud://127.0.0.1:8848 # 指定 Dubbo 服务注册中心的地址
# Spring Cloud Alibaba Dubbo 专属配置项,对应 DubboCloudProperties 类
cloud:
subscribed-services: '' # 设置订阅的应用列表,默认为 * 订阅所有应用。

spring.cloud.nacos.discovery 配置项,添加 Nacos 作为 Spring Cloud 注册中心的配置项。

dubbo 配置项,添加 Dubbo 相关的配置项。

10.2.3 UserServiceImpl

创建 UserServiceImpl 类,实现 UserService 接口,提供 Dubbo 用户服务。代码如下:

@org.apache.dubbo.config.annotation.Service(protocol = "dubbo", version = "1.0.0")
public class UserServiceImpl implements UserService {

@Override
public String getUser(Integer id) {
return "User:" + id;
}

}

10.2.4 UserServiceApplication

创建 UserServiceApplication 类,用户服务的启动类。代码如下:

@SpringBootApplication
public class UserServiceApplication {

public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class);
}

}

10.3 搭建 Hystrix 示例项目

创建 labx-23-scn-hystrix-dubbo-demo-application 项目,搭建一个用户服务的消费者,使用 Dubbo 进行调用,使用 Hystrix 实现服务容错。如下图所示:

项目结构

10.3.1 引入依赖

创建 pom.xml 文件,引入 Hystrix、Dubbo、Nacos 依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-23-scn-hystrix-dubbo-demo</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>labx-23-scn-hystrix-dubbo-demo-application</artifactId>

<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>

<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- 引入用户服务 API 包 -->
<dependency>
<groupId>cn.iocoder.springboot.labs</groupId>
<artifactId>labx-23-scn-hystrix-dubbo-demo-user-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 引入 Spring Cloud Alibaba Nacos Discovery 相关依赖,将 Nacos 作为注册中心,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- 引入 Spring Cloud Alibaba Dubbo 相关依赖,实现呢 Dubbo 进行远程调用,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>

<!-- 引入 Spring Cloud Netflix Hystrix 相关依赖,将 Hystrix 作为服务保障组件,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>

</project>

相比「10.2.1 引入依赖」小节来说,多引入 spring-cloud-starter-netflix-hystrix 依赖进行服务容错。

10.3.2 配置文件

创建 application.yaml 配置文件,添加 Dubbo 和 Nacos 配置项。

spring:
application:
name: demo-consumer
cloud:
# Nacos 作为注册中心的配置项
nacos:
discovery:
server-addr: 127.0.0.1:8848

# Dubbo 配置项,对应 DubboConfigurationProperties 类
dubbo:
# Dubbo 服务注册中心配置,对应 RegistryConfig 类
registry:
address: spring-cloud://127.0.0.1:8848 # 指定 Dubbo 服务注册中心的地址
# Spring Cloud Alibaba Dubbo 专属配置项,对应 DubboCloudProperties 类
cloud:
subscribed-services: user-service # 设置订阅的应用列表,默认为 * 订阅所有应用。

「10.2.2 配置文件」小节差不多,不重复啰嗦哈。

10.3.3 DemoController

创建 DemoController 类,提供一个通过 Dubbo 调用用户服务提供者的 HTTP 接口。代码如下:

@RestController
@RequestMapping("/demo")
public class DemoController {

private Logger logger = LoggerFactory.getLogger(getClass());

@Reference(protocol = "dubbo", version = "1.0.0")
private UserService userService;

@GetMapping("/get_user")
@HystrixCommand(fallbackMethod = "getUserFallback")
public String getUser(@RequestParam("id") Integer id) {
logger.info("[getUser][准备调用 user-service 获取用户({})详情]", id);
return userService.getUser(id);
}

public String getUserFallback(Integer id, Throwable throwable) {
logger.info("[getUserFallback][id({}) exception({})]", id, ExceptionUtils.getRootCauseMessage(throwable));
return "mock:User:" + id;
}

}

#getUser(Integer id) 方法上,添加了 @HystrixCommand 注解,从而在 Dubbo 调用失败时,执行 #getUserFallback(Integer id, Throwable throwable) 方法进行服务容错。

10.3.4 DemoApplication

创建 DemoApplication 类,创建应用启动类。代码如下:

@SpringBootApplication
@EnableCircuitBreaker // 声明开启断路器
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

}

10.4 简单测试

执行 DemoApplication 启动用户服务,执行 UserServiceApplication 启动 Hystrix 示例项目。

① 使用浏览器,访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,成功调用用户服务,返回结果为 User:1

② 停止 DemoApplication 关闭用户服务。

使用浏览器,访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,失败调用用户服务,返回结果为 mock:User:1

此时我们会看到如下日志,可以判断触发 Hystrix 的 fallback 服务降级的方法。

2020-05-15 07:18:06.183  INFO 75980 --- [emoController-3] c.i.s.l.demo.controller.DemoController   : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-15 07:18:06.184 INFO 75980 --- [emoController-3] c.i.s.l.demo.controller.DemoController : [getUserFallback][id(1) exception(RemotingException: message can not send, because channel is closed . url:dubbo://192.168.43.240:20880/com.alibaba.cloud.dubbo.service.DubboMetadataService?anyhost=true&application=demo-consumer&bind.ip=192.168.43.240&bind.port=20880&check=false&codec=dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=true&group=user-service&heartbeat=60000&interface=com.alibaba.cloud.dubbo.service.DubboMetadataService&lazy=false&methods=getAllServiceKeys,getServiceRestMetadata,getExportedURLs,getAllExportedURLs&pid=75980&qos.enable=false&register.ip=192.168.43.240&release=2.7.4.1&remote.application=user-service&revision=2.2.0.RELEASE&side=consumer&sticky=false&timestamp=1589498209533&version=1.0.0)]

疯狂使用浏览器,访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,会触发 Hystrix 断路器熔断(打开),不再执行 #getUser(Integer id) 方法,而是直接 fallback 触发 #getUserFallback(Integer id, Throwable throwable) 方法。日志内容如下:

2020-05-15 07:20:02.809  INFO 75980 --- [nio-8080-exec-1] c.i.s.l.demo.controller.DemoController   : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
2020-05-15 07:20:02.907 INFO 75980 --- [nio-8080-exec-2] c.i.s.l.demo.controller.DemoController : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
2020-05-15 07:20:02.995 INFO 75980 --- [nio-8080-exec-3] c.i.s.l.demo.controller.DemoController : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]

④ 重新执行 UserServiceApplication 启动用户服务。

使用浏览器,多次访问 http://127.0.0.1:8080/feign-demo/get_user?id=1 地址,Hystrix 断路器的状态逐步从打开 => 半开 => 关闭。日志内容如下:

// 打开
2020-05-14 21:27:28.560 INFO 71995 --- [nio-8080-exec-5] .f.UserServiceFeignClientFallbackFactory : [getUserFallback][id(1) exception(RuntimeException: Hystrix circuit short-circuited and is OPEN)]
...

// 半开
2020-05-15 07:21:43.486 INFO 75980 --- [moController-10] c.i.s.l.demo.controller.DemoController : [getUser][准备调用 user-service 获取用户(1)详情]

// 关闭
2020-05-15 07:21:50.449 INFO 75980 --- [moController-10] c.i.s.l.demo.controller.DemoController : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-15 07:21:50.653 INFO 75980 --- [moController-10] c.i.s.l.demo.controller.DemoController : [getUser][准备调用 user-service 获取用户(1)详情]
2020-05-15 07:21:50.818 INFO 75980 --- [moController-10] c.i.s.l.demo.controller.DemoController : [getUser][准备调用 user-service 获取用户(1)详情]
...

666. 彩蛋

至此,我们已经完成 Spring Cloud Hystrix 的学习。如下是 Hystrix 相关的官方文档:

更多关于 Hystrix 的内容,胖友可以访问《Hystrix 源码解析》

文章目录
  1. 1. 1. 概述
    1. 1.1. 1.1 服务雪崩
    2. 1.2. 1.2 服务容错
    3. 1.3. 1.3 Hystrix
      1. 1.3.1. 1.3.1 Fallback 服务降级
      2. 1.3.2. 1.3.2 断路器机制
      3. 1.3.3. 1.3.3 资源隔离
    4. 1.4. 1.4 Spring Cloud Netflix Hystrix
  2. 2. 2. 快速入门
    1. 2.1. 2.1 搭建用户服务
    2. 2.2. 2.2 搭建 Hystrix 示例项目
      1. 2.2.1. 2.2.1 引入依赖
      2. 2.2.2. 2.2.2 DemoApplication
      3. 2.2.3. 2.2.3 DemoController
    3. 2.3. 2.3 简单测试
  3. 3. 3. 请求缓存
    1. 3.1. 3.1 HystrixRequestContextFilter
    2. 3.2. 3.2 CacheDemoService
    3. 3.3. 3.3 CacheDemoController
    4. 3.4. 3.4 简单测试
  4. 4. 4. 请求合并
    1. 4.1. 4.1 搭建用户服务
    2. 4.2. 4.2 搭建 Hystrix 示例项目
      1. 4.2.1. 4.2.1 CollapserDemoService
      2. 4.2.2. 4.2.2 CollapserDemoController
    3. 4.3. 4.3 简单测试
  5. 5. 5. Hystrix Dashboard 监控
    1. 5.1. 5.1 搭建用户服务
    2. 5.2. 5.2 搭建 Hystrix 示例项目
    3. 5.3. 5.3 搭建 Hystrix Dashboard
      1. 5.3.1. 5.3.1 引入依赖
      2. 5.3.2. 5.3.2 配置文件
      3. 5.3.3. 5.3.3 HystrixDashboardApplication
      4. 5.3.4. 5.3.4 简单测试
  6. 6. 6. Turbine 聚合监控
    1. 6.1. 6.1 搭建 Eureka 注册中心
    2. 6.2. 6.2 搭建用户服务
    3. 6.3. 6.3 搭建 Hystrix 示例项目
    4. 6.4. 6.4 搭建 Hystrix Dashboard + Turbine
      1. 6.4.1. 6.4.1 引入依赖
      2. 6.4.2. 6.4.2 配置文件
      3. 6.4.3. 6.4.3 HystrixDashboardApplication
      4. 6.4.4. 6.4.4 简单测试
  7. 7. 7. 集成到 Zuul
  8. 8. 8. 集成到 Spring Cloud Gateway
  9. 9. 9. 集成到 Feign
    1. 9.1. 9.1 搭建用户服务
    2. 9.2. 9.2 搭建 Hystrix 示例项目
      1. 9.2.1. 9.2.1 引入依赖
      2. 9.2.2. 9.2.2 配置文件
      3. 9.2.3. 9.2.3 UserServiceFeignClient
      4. 9.2.4. 9.2.4 UserServiceFeignClientFallbackFactory
      5. 9.2.5. 9.2.5 FeignDemoController
      6. 9.2.6. 9.2.6 DemoApplication
    3. 9.3. 9.3 简单测试
  10. 10. 10. 集成到 Dubbo
    1. 10.1. 10.1 用户服务 API
      1. 10.1.1. 10.1.1 引入依赖
      2. 10.1.2. 10.1.2 UserService
    2. 10.2. 10.2 用户服务 Provider
      1. 10.2.1. 10.2.1 引入依赖
      2. 10.2.2. 10.2.2 配置文件
      3. 10.2.3. 10.2.3 UserServiceImpl
      4. 10.2.4. 10.2.4 UserServiceApplication
    3. 10.3. 10.3 搭建 Hystrix 示例项目
      1. 10.3.1. 10.3.1 引入依赖
      2. 10.3.2. 10.3.2 配置文件
      3. 10.3.3. 10.3.3 DemoController
      4. 10.3.4. 10.3.4 DemoApplication
    4. 10.4. 10.4 简单测试
  11. 11. 666. 彩蛋