简介
微服务中有很多个系统, 前端发送一个请求, 后端可能会有一连串的服务之间的调用, 如果一个服务出错了, 可能会引起调用链路上一连串的请求错误, 这个时候该如何解决呢? Spring Cloud 提供了 Hystrix 熔断机制. Hystrix 是一个针对分布式系统容错处理的开源组件 (Hystrix 是豪猪的意思, 浑身有刺保护自己), 用来隔离远程系统、服务和第三方库, 阻止级联故障, 在复杂的分布式系统中实现恢复能力
示例
对异常方法实现熔断
创建一个 app-server 工程
-
pom 配置, 引入 Hystrix 依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
-
入口类上添加 @EnableHystrix 注解开启熔断
@SpringBootApplication @EnableHystrix public class CommentServerApplication { public static void main(String[] args) { SpringApplication.run(CommentServerApplication.class, args); } }
-
定义一个接口, 模拟程序出现异常的时候, 触发熔断机制, 返回一个默认的结果
@HystrixCommand(fallbackMethod = "defaultUser") @GetMapping("/user/{name}") public String getUser(@PathVariable("name") String username) throws Exception{ if("spring".equals(username)){ return "spring"; } else{ throw new Exception(); } } public String defaultUser(String username){ return "This user doesn't exist"; }
-
测试
当 请求: http:// user/spring 的时候, 返回: spring. 当请求 http:// user/spriewrew 的时候, 服务抛出异常, 熔断机制发挥作用, 降级处理返回友好提示: This user doesn’t exist
Feign 对异常熔断处理
Feign 默认自带 Hystrix 的功能, 老的版本默认打开, 在最近的版本中需要手动打开
-
编写工程的配置文件: application.yml
feign: hystrix: enabled: true # 打开 feign hystrix 功能
-
定义一个 FeignClient 接口和 触发熔断时的回调函数
FeignClient 接口:
@FeignClient(name = "joke-server",url="${custom.feign.url}", path = "/jokes", fallback = JokeServiceFallBack.class) public interface JokeService { @GetMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE) String getJokeById(@PathVariable(name = "id") String id); }
FeignClient 回调函数:
@Component public class JokeServiceFallBack implements JokeService { @Override public String getJokeById(String id) { return "This joke doesn't exist"; } }
-
测试
把服务端关闭, 调用该接口, 会触发熔断返回: This joke doesn’t exist. 可以把 feign.hystrix.enabled 的值 改成 false 再重试一下, 发现返回服务器内部错误
Hystrix 什么时候触发降级
Hystrix 的异常处理中, 有5钟情况会被 fallback 截获, 从而触发 fallback:
条件 | 含义 |
---|---|
FAILURE | 执行失败, 抛出异常 |
TIMEOUT | 执行超时 |
SHORT_CIRCUITED | 断路器打开 |
THREAD_POOL_REJECTED | 线程池拒绝 |
SEMAPHORE_REJECTED | 信号量考量 |
注意: BAD_REQUEST 不会触发 fallback