Hystrix - 资源隔离模式 (线程池模式+信号量模式)

总结

1. 线程池模式 vs 信号量模式

 

 线程池隔离信号量隔离
线程 与调用线程非相同线程 与调用线程相同(tomcat/jetty线程)
开销 排队、调度、上下文开销等 无线程切换,开销低
异步 可以是异步,也可以是同步。看调用的方法 同步调用,不支持异步
并发支持 支持(最大线程池大小hystrix.threadpool.default.maximumSize) 支持(最大信号量上限maxConcurrentRequests)  
是否超时  支持,可直接返回 不支持,如果阻塞,只能通过调用协议(如:socket超时才能返回)
是否支持熔断

支持,当线程池到达maxSize后,并且工作队列也满,再请求会触发fallback接口进行熔断

支持,当信号量达到maxConcurrentRequests后。再请求会触发fallback
隔离原理 每个服务单独用线程池 通过信号量的计数器
资源开销   大,大量线程的上下文切换,容易造成机器负载高 小,只是个计数器 
使用场景 当请求的服务网络开销比较大的时候,或者是请求比较耗时的时候。为了保证可以大量的容器(tomcat)线程可用,不会由于服务原因,一直处于阻塞或等待状态,会pick this 当请求不耗时,返回通常很快,不会占用容器线程太长的时间;pick this 同时也减少了线程切换的开销。

 

下图的左边2/3是线程池资源隔离示意图,右边的1/3是信号量资源隔离示意图,我们先来看左边的示意图。

 

 

我们先来看左边的示意图。

当用户请求服务A和服务I的时候,tomcat的线程(图中蓝色箭头标注)会将请求的任务交给服务A和服务I的内部线程池里面的线程(图中橘色箭头标注)来执行,tomcat的线程就可以去干别的事情去了,当服务A和服务I自己线程池里面的线程执行完任务之后,就会将调用的结果返回给tomcat的线程,从而实现资源的隔离,当有大量并发的时候,服务内部的线程池的数量就决定了整个服务的并发度,例如服务A的线程池大小为10个,当同时有12请求时,只会允许10个任务在执行,其他的任务被放在线程池队列中,或者是直接走降级服务,此时,如果服务A挂了,就不会造成大量的tomcat线程被服务A拖死,服务I依然能够提供服务。整个系统不会受太大的影响。

 

线程池模式的优缺点

优点:

  • 一个依赖可以给予一个线程池,这个依赖的异常不会影响其他的依赖。
  • 使用线程池模式可以完全隔离第三方代码,请求线程(客户端的线程)可以快速放回。
  • 当一个失败的依赖再次变成可用时,线程池将清理,并立即恢复可用,而不是一个长时间的恢复。
  • 可以完全模拟异步调用,方便异步编程。
  • 使用线程池,可以有效的进行实时监控、统计和封装。

缺点:

  • 使用线程池的缺点主要是增加了计算的开销。每一个依赖调用都会涉及到队列,调度,上下文切换,而这些操作都有可能在不同的线程中执行。
  • Netflix 更偏向于使用线程池来隔离依赖服务,因为经过计算,线程切换的消耗在可接受范围之内。并且能支持包括超时在内的所有功能。

 

2. 设置隔离模式:线程池/信号量

execution.isolation.strategy: "THREAD"/"SEMAPHORE"

@HystrixCommand(
        commandProperties = { //利用commandProperties更改线程池的一些默认配置
            //选择“线程池”模式、"信号量"模式
            @HystrixProperty(name="execution.isolation.strategy",value = "THREAD"/"SEMAPHORE"), 
            //超时
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
            //信号量大小为10,那么同时只允许10个tomcat的线程(此处是tomcat的线程,而不是服务的独立线程池里面的线程)来访问服务,其他的请求就会被拒绝,从而达到限流保护的作用
            @HystrixProperty(name="execution.isolation.semaphore.maxConcurrentRequests",value = "10"),
        },
)
public List<License> getLicensesByOrg(String organizationId){
    //....
}

 

 

3. 设置隔离线程池、线程数量、队列长度、fallback方法

默认情况下,Hystrix不做线程隔离,因此容易造成服务雪崩...

如果想设置隔离线程池,需要:

@HystrixCommand(
        //设置一个隔离的线程池
        threadPoolKey = "licenseByOrgThreadPool",
        threadPoolProperties = {
            //设置该线程池的线程数
            @HystrixProperty(name = "coreSize",value="30"),
            //设置队列的容量,该队列的作用是当线程池中的线程都处于工作状态,接下来的请求会进入该队列
            @HystrixProperty(name="maxQueueSize", value="10")
        }
        //一旦队列中也满了,再来的请求就执行“服务降级”fallback方法
        fallbackMethod = "buildFallbackLicenseList"
)
public List<License> getLicensesByOrg(String organizationId){
    //...
}

 

 

参考文献

服务容错保护断路器Hystrix之八:Hystrix资源隔离策略

 

posted on 2021-02-28 18:11  frank_cui  阅读(1700)  评论(0编辑  收藏  举报

导航

levels of contents