线程池资源优化演进
在生产环境中部署一个短路器,一开始需要将一些关键配置设置的大一些,比如timeout超时时长,线程池大小,或信号量容量,然后逐渐优化这些配置,直到在一个生产系统中运作良好。
(1)一开始先不要设置timeout超时时长,默认就是1000ms,也就是1s
(2)一开始也不要设置线程池大小,默认就是10
(3)直接部署hystrix到生产环境,如果运行的很良好,那么就让它这样运行好了
(4)让hystrix应用,24小时运行在生产环境中
(5)依赖标准的监控和报警机制来捕获到系统的异常运行情况
(6)在24小时之后,看一下调用延迟的占比,以及流量,来计算出让短路器生效的最小的配置数字
(7)直接对hystrix配置进行热修改,然后继续在hystrix dashboard上监控
(8)看看修改配置后的系统表现有没有改善
HystrixThreadPool线程数量设定计算公式
每秒的高峰访问次数 * 99%的访问延时 + 缓冲数量
假设一个依赖的服务的高峰访问次数30QPS,99%的请求延时实践在200ms,那么我们可以设定的线程数量=30*0.2+4=10个线程。
HystrixCommand线程超时timeout设定
结合线程池数量配置,设置能够完成执行高峰时QPS任务的timeout数值。
默认线程超时为1s。假设一个依赖服务的高峰访问时,99.5%的请求延时在250ms,假设再允许服务重试一次消耗50ms,那么这个依赖服务的延时设置为300ms就可以了,这样一个线程最多延时300ms,也就是这个线程每秒能执行三次依赖服务,线程池中10个线程,整好能处理30QPS。如果把延时设置为400ms,那么一个线程每秒最多执行2次请求,10个线程在1s内最多执行20个请求,剩余的10个请求就会被线程池阻塞住,再来新的请求也继续会被阻塞住,如果等待队列已满,那么新来的请求就会被直接Reject。所以400ms的超时设置就不能满足30QPS的请求次数要求。
生产环境中动态分配线程池资源
线程池动态配置选项
//允许线程池自动从coreSize扩容到maximumSize
.withAllowMaximumSizeToDivergeFromCoreSize(true)
//default 10,默认线程池大小
.withCoreSize(10)
//最大线程数
.withMaximumSize(30)
//空闲线程存活时间1分钟,超时后线程池数量自动恢复到coreSize大小
.withKeepAliveTimeMinutes(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
@Slf4j public class GetProductInfoWithDynamicThreadPoolCmmd extends HystrixCommand<ProductInfo> { private static final HystrixCommandKey KEY = HystrixCommandKey.Factory.asKey("GetProductInfoCmmd"); private Long productId; public GetProductInfoWithDynamicThreadPoolCmmd(Long productId) { super( Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup")) .andCommandKey(HystrixCommandKey.Factory.asKey("GetProductInfoCmmd")) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetProductInfoThreadPool")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD) //允许执行的最大并发数 .withExecutionIsolationSemaphoreMaxConcurrentRequests(30) //请求超时 .withExecutionTimeoutInMilliseconds(300)) .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() //允许线程池自动从coreSize扩容到maximumSize .withAllowMaximumSizeToDivergeFromCoreSize(true) //default 10,默认线程池大小 .withCoreSize(10) //最大线程数 .withMaximumSize(30) //空闲线程存活时间1分钟,超时后线程池数量自动恢复到coreSize大小 .withKeepAliveTimeMinutes(1) //default 5,没有被线程池执行的请求会放到队 //列中等待线程,如果队列已满,新来的请求会被降级被拒 .withQueueSizeRejectionThreshold(10) //withQueueSizeRejectionThreshold和withMaxQueueSize比较,queueSize取较小值 .withMaxQueueSize(8)) ); this.productId = productId; } @Override protected ProductInfo run() throws Exception { String url = "http://127.0.0.1:8082/product/get?productId="+productId; String s = HttpClientUtils.sendGetRequestWithException(url); log.info("product-ha response {}",s); ProductInfo productInfo = JSONObject.parseObject(s, ProductInfo.class); return productInfo; } /** * 从hystrix本地缓存中获取数据,而不是执行run方法 * @return */ @Override protected String getCacheKey() { return "product_key_"+productId; } /** * 清理hystrix缓存的数据 * @param productId */ public static void flushCache(Long productId){ HystrixRequestCache.getInstance(KEY,HystrixConcurrencyStrategyDefault.getInstance()).clear("product_key_"+productId); } /** * hystrix执行降级请求时返回的数据 * @return */ @Override protected ProductInfo getFallback() { return null; } } |