Hystrix 简单聊聊断路器/熔断器
什么是Hystrix
Hystrix 在SpringCloud中负责服务熔断服务降级的作用。
Hystrix 存在的目的也是为了防止过多超时导致系统瘫痪。比如多个服务之间的相互调用,如下图:
订单->商品->积分->日志
订单->支付->日志
商品->风控->日志
服务之间相互调用,假设某个链路上的某个服务比如日志服务超时了,不可被调用,那么其他的服务全部卡死,导致崩溃。
举一个生活中的例子:
在家里,我开了很多电器,这个时候如果没有一个保护装置的话,由于某个电器过载,最终会导致整个电路断掉,那么每户人家肯定会有一个装置叫做保险丝
,那么Hystrix断路器就起到了保险丝的作用,他可以保护整个系统。
Hystrix在分布式系统或者微服务中,一旦出现了超时或者依赖服务不可用调用失败异常等情况,他能够保证整个系统不会整体宕机崩溃,从而提高整个系统的健壮性。
Hystrix的原理就是当某一个服务发生故障的时候,这个时候是不会有任何的正常响应的,但是通过Hystrix可以返回一个备用响应,也就是所谓的backup,如此一来,发生异常的系统就不会造成不必要的超时等异常现象,这就好比打篮球,上场必须要5人,但是如果有人受伤要下场,这个时候就必须要有backup球员,如果没有,这个球队很难进行比赛了。
简单一句话总结,就是Hystrix可以保证在众多微服务中一个服务出现了问题不会引发整体系统奔溃的一个开源组件。
服务熔断
熔断是一种微服务链路的保护机制,当某个服务(依赖)不可用/宕机/超时/异常的时候,会进行服务的熔断(是一个开关,会开启),这个发生故障的节点就被熔断了
也就是不可用,不会再让用户调用到,那么此时就需要降级,来直接会返回一个错误的异常响应信息。当这个节点OK恢复了,hystrix会检测到,然后再把他恢复到整个链路。
熔断机制在很多行业里都有,比如股市,金融行业,都是为了更好更有效的控制,把损失控制在一定的范围内。
代码演示
- pom 中加入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 启动类开启熔断器
@EnableCircuitBreaker
- 编写错误的controller
// 一旦服务调用失败,发生异常,会调用@HystrixCommand中的[graceDisplay]方法,这个方法就是兜底方法
@HystrixCommand(fallbackMethod = "graceDisplay")
public String helloHystrix() {
Object o = "Hello hystrix~";
int a = 1 / 0;
return "Hello hystrix~";
}
public String graceDisplay() {
return "Hello another me~";
}
- 测试:
-
如果正常访问,显示
Hello hystrix~
-
发生异常熔断,则展示:
-
服务器降级
当某个服务资源不够的时候,可以启用降级处理。
举一个例子,如下图:
假设我们家里用很多电器,其他电器正在使用中并且占用的电流啊电压啥的很大,空调我这个时候可以不用,把资源给到其他的电器,这时我们是直接把空调插头拔出,区别于熔断,熔断的话是发生异常后和谐的响应信息,而降级是我把这个服务关停了,随后在响应给用户。需要注意,由于服务关闭了,所以响应是发生在调用方的,也就是客户端,比如图中的电热水壶
和微波炉
。当电压电流恢复后,我们再把空调插头插上即可,那么这就是降级的一种方式。
那么熔断和降级的异同点是啥呢?
- 相同点:
- 都是为了提升系统的可靠性
- 都为了正确的返回响应给用户
- 不同点:
- 熔断:被调用的服务方(下游)发生故障导致
- 降级:全局整体服务负载过高,有效调动资源服务,由调用方(上游)控制
熔断解耦分离
当使用@HystrixCommand
的时候,每有一个controller的接口api,就会有一个熔断方法,这是成倍的增长的,数量会很多,维护不方便,所以需要解耦开来。而且,当我们关闭不用的微服务时,上游还是会调用下游,所以我们需要在上游服务这块,去增加降级的方法,如果服务无法调用,则调用上游服务中的降级方法即可。并且下游服务如果被我们关闭,上游的调用还是可以有响应给用户的。
@Component
public class HystrixFactoryCallback implements FallbackFactory<HystrixFactoryControllerApi> {
@Override
public HystrixFactoryControllerApi create(Throwable throwable) {
return new HystrixFactoryControllerApi() {
@Override
public String helloFactory() {
return "优雅的处理,只在客户端直接返回,下游服务关闭不影响";
}
};
}
}
@FeignClient(value = EurekaServiceList.SERVICE_HYSTRIX, fallbackFactory = HystrixFactoryCallback.class)
public interface HystrixFactoryControllerApi {
// 当前类的所有接口只要有问题都会被HystrixFactoryCallback给处理
// 测试hystrix降级解耦
@GetMapping("/helloFactory")
public String helloFactory();
}
spring:
main:
allow-bean-definition-overriding: true # 允许 @FeignClient 同名
feign:
hystrix:
enabled: true # 开启@FeignClient的降级功能 fallbackFactory
上游:
@Autowired
HystrixFactoryControllerApi hystrixFactoryControllerApi;
@GetMapping("/testHystrixFactoryApi")
public Object testHystrixFactoryApi() {
String result = hystrixFactoryControllerApi.helloFactory();
return result;
}
下游:
@RestController
public class FactoryController implements HystrixFactoryControllerApi {
@Override
public String helloFactory() {
Object o = "Hello hystrix factory~";
int a = 1 / 0;
return "Hello hystrix factory~";
}
}
简单总结一下
熔断:当一个服务发生故障异常,这个时候熔断当前整个服务,把这个服务变的不可被访问,而不是客户端请求这个服务的时候一直处于超时。
降级:当服务熔断后,我们需要提供新的一个兜底接口返回响应数据,如此一来,客户端能够友好的接受到响应消息。