隔离分为线程池隔离和信号量隔离,通过判断线程池或者信号量是否已满,超出容量的请求直接降级,从而达到限流的作用
线程池隔离:
给每个接口提供一个独立的线程池:
优点:
- 任何的服务都会被隔离在自己的线程池内,即使自己的线程池资源被填满,也不会影响其他服务
- 当依赖的服务重新恢复时,可通过清理线程池,瞬间恢复服务的调用,但是如果是tomcat线程池被填满,再恢复就会很麻烦
- 由于线程池中线程个数有限制,所以也就解决了限流的问题
缺点:
增加了cpu的开销,不仅仅有tomcat线程池,还需要有hystrix线程池
代码:
//---------------------线程隔离
//groupKey 一组command,如果没有配这个,相同的groupkey会使用同一个线程池
@HystrixCommand(groupKey = "thread1-group",commandKey = "thread1",threadPoolKey = "thread1-group",threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "8"),
@HystrixProperty(name="maxQueueSize",value="5")
})
public void thread1(){
System.out.println(Thread.currentThread().getName());
}
@HystrixCommand(groupKey = "thread2-group",commandKey = "thread1",threadPoolKey = "thread2-group",threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "8"),
@HystrixProperty(name="maxQueueSize",value="5")
})
public void thread2(){
System.out.println(Thread.currentThread().getName());
}
如果多个api使用同一个线程池,那么coreSize如何设置?
答: 走第一个api设置的
代码:cloud-provider-hystrix-payment8001
线程隔离代码:
1.不加Hystrix线程隔离,默认的使用tomcat线程池
public void thread1(){
System.out.println(a++);
try {
Thread.sleep(20000);
}catch (Exception e){
System.out.println(111);
}
System.out.println(Thread.currentThread().getName());
}
public void thread2(){
System.out.println(Thread.currentThread().getName());
}
2.添加Hystrix线程池分组
@HystrixCommand(groupKey = "thread1-group",commandKey = "thread1",threadPoolKey = "thread1-group",commandProperties={
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="40000")
},threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "8"),
// @HystrixProperty(name="allowMaximumSizeToDivergeFromCoreSize",value = "true"),
// @HystrixProperty(name = "maximumSize",value="10"),
@HystrixProperty(name="maxQueueSize",value="5")
})
public void thread1(){
System.out.println(a++);
try {
Thread.sleep(20000);
}catch (Exception e){
System.out.println(111);
}
System.out.println(Thread.currentThread().getName());
}
@HystrixCommand(
groupKey = "thread2-group",commandKey = "thread2",threadPoolKey = "thread2-group",threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "8"),
// @HystrixProperty(name="maxQueueSize",value="5")
})
public void thread2(){
System.out.println(Thread.currentThread().getName());
}
结论: 他们之间的线程来自不同的线程池,不会互相受影响,
由于设定的排队的队列为 5 所以 8+ 5 最多有 13个请求
否则就报错了,但是在 13个以内的请求是不会报错的
另外一点就是允许的延时时间
3.threadPoolKey 相同的 用同一个线程池,如果threadPoolKey不写 默认是 groupKey的值
@HystrixCommand(groupKey = "thread1-group",commandKey = "thread1",threadPoolKey = "hyf111",commandProperties={
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="40000")
},threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "8"),
@HystrixProperty(name="maxQueueSize",value="5")
})
public void thread1(){
System.out.println(a++);
try {
Thread.sleep(20000);
}catch (Exception e){
System.out.println(111);
}
System.out.println(Thread.currentThread().getName());
}
@HystrixCommand(groupKey = "thread2-group",commandKey = "thread1",threadPoolKey = "hyf111",threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "8"),
@HystrixProperty(name="maxQueueSize",value="5")
})
public void thread2(){
System.out.println(Thread.currentThread().getName());
}
信号量隔离:
其实就是一个计数器,加入设定为5 那么就是最多同时有5个来访问
由于Hystrix默认使用线程池做线程隔离,使用信号量隔离需要显示地将属性execution.isolation.strategy设置为ExecutionIsolationStrategy.SEMAPHORE,同时配置信号量个数,默认为10。客户端需向
依赖服务发起请求时,首先要获取一个信号量才能真正发起调用,由于信号量的数量有限,当并发请求量超过信号量个数时,后续的请求都会直接拒绝,进入fallback流程
线程池和信号量都支持熔断和限流。相比线程池,信号量不需要线程切换,因此避免了不必要的开销。但是信号量不支持异步,也不支持超时,也就是说当所请求的服务不可用时,信号量会控制超过限制的请求立即返回,但是已经持有信号量的线程只能等待服务响应或从超时中返回,即可能出现长时间等待。线程池模式下,当超过指定时间未响应的服务,Hystrix会通过响应中断的方式通知线程立即结束并返回。