4Hystrix 线程隔离 · SpringCloud微服务实战 · 看云
4. Hystrix 线程隔离
导航
前面说了Hystrix 隔离机制中的一种信号量机制,现在我们来说一下线程隔离的机制。
4.1 线程池隔离的优缺点
本节代码地址
4.1.2 线程池的好处
- 应用程序会被完全保护起来,即使依赖的一个服务的线程池满了,也不会影响到应用程序的其他部分。
- 我们给应用程序引入一个新的风险较低的客户端lib的时候,如果发生问题,也是在本lib中,并不会影响到其他内容,因此我们可以大胆的引入新lib库。
- 当依赖的一个失败的服务恢复正常时,应用程序会立即恢复正常的性能。
- 如果我们的应用程序一些参数配置错误了,线程池的运行状况将会很快显示出来,比如延迟、超时、拒绝等。同时可以通过动态属性实时执行来处理纠正错误的参数配置。
- 如果服务的性能有变化,从而需要调整,比如增加或者减少超时时间,更改重试次数,就可以通过线程池指标动态属性修改,而且不会影响到其他调用请求。
- 除了隔离优势外,hystrix拥有专门的线程池可提供内置的并发功能,使得可以在同步调用之上构建异步的外观模式,这样就可以很方便的做异步编程(Hystrix引入了Rxjava异步框架)
注意:尽管有单独的线程提供了隔离,但您的基础客户端代码也应具有超时和/或对线程中断的响应,因此它不能无限期地阻塞并使Hystrix线程池饱和。
4.1.2 线程池的缺点
线程池的主要缺点是它们增加了计算开销。每个命令执行都涉及在单独的线程上运行命令所涉及的队列,调度和上下文切换。
Netflix在设计此系统时,决定接受此方式,以换取其提供的好处,并认为它很小,不会对成本或性能造成重大影响。
4.1.3 线程成本
Hystrix测量在子线程上执行construct()orrun()方法时的延迟以及父线程上的总的端到端时间。这样,您可以看到Hystrix开销(线程,度量,日志记录,断路器等)的成本。
Netflix API使用线程隔离每天处理10+亿次Hystrix Command执行。每个API实例有40多个线程池,每个线程池中有5-20个线程(大多数设置为10)。
下图表示一个HystrixCommand在单个API实例上以每秒60个请求的速度执行的情况(每个服务器每秒约350个线程执行总数):
4.2 新建FwHystrixCommondThread 类
在这里我们需要设置隔离级别为THREAD,并且为线程池的大小为3,但是在代码里面运行了6个线程,所以只可能有3个成功,剩下的回退。
@Slf4j
public class FwHystrixCommondThread extends HystrixCommand<String> {
private final String name;
protected FwHystrixCommondThread(String name) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("myGroup"))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter().withExecutionIsolationStrategy(
HystrixCommandProperties.ExecutionIsolationStrategy.THREAD
)
).andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter()
.withCoreSize(3)
));
this.name = name;
}
@Override
protected String getFallback() {
log.info(this.name+":"+Thread.currentThread().getName()+"异常");
return this.name+":"+Thread.currentThread().getName();
}
@Override
protected String run() throws Exception {
log.info(this.name+":"+Thread.currentThread().getName()+"成功");
return this.name + ":" + Thread.currentThread().getName();
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
for (int i = 0; i <6 ; i++) {
final int index=i;
Thread t =new Thread() {
@Override
public void run() {
FwHystrixCommondThread test = new FwHystrixCommondThread("test" + index);
test.execute();
}
};
t.start();
}
Thread.sleep(5000);
}
}
4.3 运行main方法
可以看到如下日志输出,跟我们预想的一样。
13:49:12.782 [Thread-0] INFO com.yisu.hystrix.without.FwHystrixCommondThread - test0:Thread-0异常
13:49:12.782 [Thread-1] INFO com.yisu.hystrix.without.FwHystrixCommondThread - test1:Thread-1异常
13:49:12.782 [Thread-2] INFO com.yisu.hystrix.without.FwHystrixCommondThread - test2:Thread-2异常
13:49:12.798 [hystrix-myGroup-2] INFO com.yisu.hystrix.without.FwHystrixCommondThread - test4:hystrix-myGroup-2成功
13:49:12.798 [hystrix-myGroup-1] INFO com.yisu.hystrix.without.FwHystrixCommondThread - test3:hystrix-myGroup-1成功
13:49:12.798 [hystrix-myGroup-3] INFO com.yisu.hystrix.without.FwHystrixCommondThread - test5:hystrix-myGroup-3成功
4.4 设置的参数
上线我设置了线程池的大小,当然其他的参数也可以设置,在这里就不介绍了,感兴趣的话自己试试,如下截图

