什么是Hystrix
Hytrix是微服务的中的熔断器,用来保护服务,当一个服务请求量过大导致服务不可用的时候,称为服务雪崩,hystrix提供服务熔断与降级功能,保证服务可用,提高用户体验。
服务雪崩
一般来说每个服务都是一个独立的应用,服务请求由tomcat进行接收并处理,tomcat通过一个线程池来处理这些请求,但是线程池是由最大线程数限制的,当请求量过大,服务器响应不过来就会造成阻塞,后面的请求就会一直处于等待状态,此时,不仅仅是这个接口,该应用的其他接口也会因此无法响应,如果该服务同时还调用了其他的服务,那么也会导致其他的服务不可用,由此可造成连锁效应,造成一系列的服务崩溃,此为服务雪崩现象。
举例:服务A调用服务B,服务B调用服务C,当服务A请求量过大超过其处理能力的时候,此时再去请求服务A的时候就必须等待前面的请求处理完才能处理当前的请求,那这个时候服务A,B,C都是不可用的。
服务隔离
服务隔离是hystrix的核心,实际上就是通过一些手段限制资源的使用,使得一个服务的调用不会影响其他的服务。服务隔离有两种模式:线程池隔离(默认),信号量隔离
线程池隔离
上面说到一般应用处理请求是通过tomcat的线程池去处理的,线程池隔离的意思就是除了tomcat的线程池,服务还有自己的线程池来处理请求,比如有服务A和服务B,当A和B都开启了hystrix,那么A和B服务都有自己的线程池,此时A发生服务雪崩,由于A有自己的线程池,这时访问B是不会受到影响的,由此将A和B隔离开来。
由于是使用线程池,通过多线程异步的方式进行调用,需要进行线程切换,会有系统开销,所以一般情况下只在关键核心的服务接口使用hystrix,若大规模的使用,对系统的性能造成影响。如果是网络开销比较大,服务处理本身比较耗时的情况下,使用线程池隔离比较好,可以保证tomcat的线程可用,不会一直等待。
信号量隔离
信号量隔离不使用线程池,而是使用一个计数器实现的,请求的时候会先获取信号量,有了信号量才可以处理,处理完释放信号量,当并发请求量超过信号量最大值时,发生熔断,但是信号量隔离模式不是异步的,是以同步线程的方式进行,也就是说会造成阻塞,所以响应没有线程池隔离好,但是由于不需要进行线程的切换,所以开销也比线程池隔离小的多。如果是内部的服务调用,可以使用信号量隔离,例如缓存请求,一般来说请求处理快,不会长时间阻塞,系统开销也比较小。
服务熔断与降级
为了提高服务的可用性,在发生服务雪崩的时候,服务器就必须学会拒绝,不再去处理这些过多的请求,告诉用户服务器处理不过来了,需要缓一下,这就是hystrix的熔断和降级功能,是搭配使用的,如果只是熔断,那么用户不知道发生了什么,所以需要有降级功能告诉用户,一般会给出提示或者跳转到一个降级页面。
一般来说有两种情况会触发服务降级,但是动作是不一样的:
1.并发请求量超过设定的阈值
默认并发是10,可以通过设置hystrix.threadpool.default.maximumSize 设置默认最大并发数,也可以设置@HysrixCommand的参数对某个服务接口设置,并发超过这个阈值的服务将不会被处理,而是转发到fallback指定的方法处理。
2.服务超过一定时间没有响应
hystrix默认的响应超时时间是1s,当超过这个时间还没有响应,服务也会做降级处理,但是该服务并没有中止,会在后台运行,比如说服务A处理逻辑需要10s,浏览器发送请求之后过了1s服务A还没有处理完,这个时候会进行服务降级,执行fallback方法,但是服务A的处理逻辑仍然在后台进行,没有中断。实际使用中需要调大hystrix的响应超时时间,通过参数hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds设置
关于服务降级的两种写法
1.通过fallbackMethod指定降级方法
@HystrixCommand注解通过参数fallbackMethod指定降级方法名,这种方法不太友好,如果有多个服务需要指定,就要写多个降级方法。
@RequestMapping("/hystrixToGetMember")
@HystrixCommand(fallbackMethod = "fallback")
public String hystrixToGetMember() {
System.out.println("调用服务:"+Thread.currentThread().getName());
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return iFeignClient.getMember();
}
2.通过指定降级类实现
通过降级类实现就是定义统一的降级接口,简单来说就是只要调用这个接口然后发生服务降级都会以统一的方式进行降级处理,不需要每个调用的类里面都写一个降级方法。一般使用这种方式
两步操作实现:
(1)定义降级类并通过@Component注入到spring容器中,降级类要继承Feign客户端,实现需要降级的方法,内容就是降级的处理方法
(2)Feign客户端通过fallback参数指定降级类
//注入到spring容器当中,作用与@Bean一样,@Bean是用在配置当中,@Component是用在类上面
@Component
public class Fallback implements IFeignClient{
@Override
public String getMember() {
return "以类方式服务降级";
}
}
//如果使用类的方式做服务降级,需要指定服务降级的类
@FeignClient(name = "eureka-client",fallback = Fallback.class)
public interface IFeignClient extends IFeignService{
}
如何开启Hystrix
1.启动类添加@EnableHystrix
2.配置文件添加feign.hystrix.enabled:true
3.需要进行限流的接口添加@HystrixCommand注解,默认线程池隔离模式
4.为@HystrixCommand指定fallback方法,默认无指定方法