【深入理解SpringCloud微服务】Hystrix作用与原理剖析
前面三篇文章,我们已经了解了微服务的熔断、限流、降级,并且也手写了一个熔断限流框架。从本篇文章开始,我们了解一下相关的开源框架Hystrix与Sentinel,本篇文章先解析Hystrix,后面的文章解析Sentinel。
Hystrix其实已经算是一个过期了的技术,说实话不学也没什么问题,毕竟现在都有Sentinel了,但是我们简单了解一下,有助于与Sentinel作对比。
Hystrix的作用
Hystrix是Netflix开发的用于服务容错保护的开源框架,然后Spring Cloud Netflix在此基础上做了些包装,添加了自动配置的功能,使得Hystrix的配置和使用变得更加简单。Hystrix提供了熔断、降级和隔离等功能。
熔断
熔断的作用在之前的文章已经介绍过了,它类似于电路中的保险丝。
熔断的功能由断路器实现,在Hystrix中断路器是HystrixCircuitBreaker。当断路器处于闭合状态时,请求可以被正常处理;如果断路器处于打开状态,请求将不会被正常处理,而是被降级处理或抛出异常(如果没有设置降级逻辑的话)。
除此以外,断路器还有一个半开状态。半开状态是指当断路器打开了一段时间后,会允许一个请求通过,测试一下服务是否恢复正常。如果服务恢复正常,那么断路器状态切换为闭合状态;否则再次切换为打开状态。
Hystrix中断路器的状态切换如下图:
降级
降级是指当断路器处于打开状态,或者接口的调用本身出现异常或超时时,转而执行的备用逻辑。Hystrix的降级处理也是如此。
只要我们的方法被 @HystrixCommand 注解修改,并在注解的 fallbackMethod 属性设置降级处理方法的方法名,当断路器打开、接口执行超时或失败等情况发生时,Hystrix就会执行我们指定的那个降级处理方法。
隔离
隔离是指不同接口间的资源隔离,这个被隔离的资源一般是线程资源。由于每个接口的请求都需要当前服务开辟一个线程去处理,如果接口间没有资源隔离的话,一旦某个接口由于某种原因导致请求处理长时间无响应,该接口就有可能吃光当前服务的所有线程资源(特别是接口并发量比较高时),进而影响到别的接口也无法处理请求,那么整个服务就瘫痪了。
解决这种问题的办法就是实现资源隔离。资源隔离使用的是“仓壁模式”,就像Docker那样,Docker通过舱壁模式,实现进程间的资源隔离,把每个进程包裹在一个容器里面,并为他配置一定的资源上限,使得进程与进程之间不会互相影响。
Hystrix则是通过线程池(默认)进行资源隔离。Hystrix为每一个受保护的接口或方法都配备一个独立的线程池,并限定池内的线程数。如此一来,即使一个接口有问题,它也只能耗光自己线程池内的所有线程资源,其他接口不会受影响。
当然,这种为每一个受保护的接口或方法单独分配一个线程池的方式,会给系统带来一定的负载和开销,但是这种消耗是微乎其微的。如果接口的延迟本身非常小,相对而言这部分的开销有点大,那么可以改用信号量隔离的方式,信号量默认值是10。
线程池隔离与信号量隔离有一个不同点在于,使用线程池隔离时,请求处理是在线程中异步执行的,而信号量隔离则是在当前线程。
Hystrix有限流的功能吗?
Hystrix没有直接提供限流的功能,但是它通过线程池隔离或信号量隔离的方式间接实现了限流。
比如我们使用线程池隔离,每个为某个接口或方法而独立配备的线程池都有一个线程数的上限,一旦达到了这个线程数上限,请求就会被拒绝,这就达到了限流的效果。
比如现在有一个接口,我们设置了该接口的线程池最大线程数是3,那么该接口最多只能同时处理3个请求。
如果此时有第4个请求到达,那么该请求将会被拒绝处理,如此也就达到了限流的效果。
通过信号量隔离的方式,也可以实现限流,只要设置信号量的最大数量即可。
Hystrix的原理
@HystrixCommand注解是如何起作用的
Hystrix的使用就是在接口或方法上声明@HystrixCommand(当然还有引入maven依赖,在启动类上添加注解等前置工作),那这个@HystrixCommand是如何起作用的呢?
除了在接口上添加@HystrixCommand注解外,我们还有在启动类上添加 @EnableHystrix 或 @EnableCircuitBreaker注解,实际上@EnableHystrix里面就是@EnableCircuitBreaker注解。
@Target(ElementType.TYPE)
@Retention