@HystrixCommand
(
//熔断回调方法
fallbackMethod = "fallBack02",
//给provider提供的服务进行线程池分组,如果groupKey一样,运行在同一个线程池
groupKey = "products-provider",
//指定需要调用的provider接口的方法名字
commandKey = "getProductTreadIsolution",
//给线程池起名字
threadPoolKey = "products-provider",
threadPoolProperties = {
//线程池大小
@HystrixProperty(name = "coreSize", value = "30"),
//最大队列长度,正数表示阻塞队列
@HystrixProperty(name = "maxQueueSize", value = "100"),
//线程存活时间
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
//拒绝请求
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15")
}
)
@Override
public Product getProductTreadIsolution(Long id) {
System.out.println("=== getProductTreadIsolution:"+Thread.currentThread().getName());
return restTemplate.getForObject("http://PRODUCT-PROVIDER/product/" + id, Product.class);
}
@HystrixCommand
(
//熔断回调方法
fallbackMethod = "fallBack02",
//给provider提供的服务进行线程池分组,如果groupKey一样,运行在同一个线程池
groupKey = "products-provider2",
//指定需要调用的provider接口的方法名字
commandKey = "getProductTreadIsolution2",
//给线程池起名字
threadPoolKey = "products-provider2",
threadPoolProperties = {
//线程池大小
@HystrixProperty(name = "coreSize", value = "30"),
//最大队列长度,正数表示阻塞队列
@HystrixProperty(name = "maxQueueSize", value = "100"),
//线程存活时间
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),
//拒绝请求
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15")
}
)
@Override
public Product getProductTreadIsolution2(Long id) {
System.out.println("=== getProductTreadIsolution:"+Thread.currentThread().getName());
return restTemplate.getForObject("http://PRODUCT-PROVIDER/product/" + id, Product.class);
}
public Product fallBack02(Long id) {
System.out.println(LocalTime.now() + " =========fallBack02");
Product product = new Product();
product.setId(-1111L);
product.setNote("系统繁忙稍后再试......");
return product;
}
参数 | 作用 | 默认值 | 备注 |
---|---|---|---|
groupKey | 服务名(相同服务用同一个名称,如商品、用户等) | getClass().getSimpleName(); | 在consumer里面为每个provider服务,设置group标识,一个group使用一个线程池 |
commandKey | 接口(服务下面的接口,如购买商品) | 当前执行方法名 | consumer的接口名称 |
threadPoolKey | 线程池的名称:配置全局唯一标识线程池的名称,相同名称的线程池是同一个 | 默认是分组名groupKey | 配置全局唯一标识线程池的名称,相同名称的线程池是同一个 |
coreSize | 线程池大小:最大的并发执行数量 | 10 | 设置标准:每秒最大支撑的请求数(99%平均响应时间+一个桓冲值) 比如:每秒能处理1000个请求,99%的响应时间是60ms,那么公式是:1000*(0.060 + x) |
maxQueueSize | 最大队列长度 | 设置BlockingQueue的最大长度 | -1 |
queueSizeRejectionThreshold | 拒绝请求:设置拒绝请求的临界值 | 5 | 此属性是不用于maxQueueSize = -1时;设置这个值的原因是maxQueueSize运行时不能改变,我们可以通过这个变量动态修改允许排队的长度 |
keepAliveTimeMinutes | 线程存活时间:设置存活时间,单位分钟 | 1 | 控制一个线程从使用完成到释放的时间 |
postman分别调用
http://localhost:8001/hystrixproduct/1
http://localhost:8001/hystrixproduct2/1
从控制台日志的线程名称可以看到,这是在两个线程池分别占用了一个线程完成的
信号隔离也可以用于限制并发访问,防止阻塞扩散, 与线程隔离最大不同在于执行依赖代码的线程依然是请求线程(该线程需要通过信号申请)
如果客户端是可信的且可以快速返回,可以使用信号隔离替换线程隔离,降低开销。
//fallbackMethod当前请求数在一个窗口期内容达到阈值,会调用fallBack02
@HystrixCommand(fallbackMethod = "fallBack02", commandProperties = {
@HystrixProperty(
// SEMAPHORE表示信号量隔离
name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY,
value = "SEMAPHORE"),
@HystrixProperty(
// 信号量最大限度,当请求达到或超过该设置值后,其其余就会被拒绝。默认值是10。
name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,
value = "5")
})
@Override
public Product getProductSemaphoreIsolution(Long id) {
return restTemplate.getForObject("http://PRODUCT-PROVIDER/product/" + id, Product.class);
}
参数 | 作用 | 默认值 | 备注 |
---|---|---|---|
execution.isolation.strategy | 隔离策略配置项 | THREAD | 只有两种:THREAD和SEMAPHORE |
execution.isolation.thread.timeoutInMilliseconds | 超时时间 | 1000ms | 1.在THREAD模式下,达到超时时间自动中断 2.在SEMAPHORE模式下,会等待执行完成后,再去判断是否超时 |
execution.isolation.thread.interruptOnTimeout | 是否打开超时线程中断 | TRUE | THREAD模式有效 |
execution.isolation.semaphore.maxConcurrentRequests | 信号量最大并发数 | 10 | SEMAPHORE模式有效 |
fallback.isolation.semaphore.maxConcurrentRequests | fallback最大并发数 | 10 | SEMAPHORE模式有效 |
- | 线程池隔离 | 信号量隔离 |
---|---|---|
线程 | 请求线程和调用provider不是同一条线程 | 请求线程和调用provider是同一条线程 |
开销 | 排队、调度、上下文开销等 | 无线程切换、开销低 |
异步 | 支持 | 不支持 |
并发支持 | 支持(最大线程池大小) | 支持(最大信号量上线) |
传递HttpHeader | 不支持 | 支持 |
支持超时 | 支持 | 不支持 |
请求并发量大,并且耗时短(请求耗时短可能是计算量小,或读缓存):
采用信号量隔离策略,因为这类服务返回通常会非常快,不会占用容器太长时间,而且也减少了线程切换的一些开销,提高了缓存服务的效率。