背景:

有一次在生产环境,突然出现了很多笔还款单被挂起,后来排查原因,发现是内部系统调用时出现了Hystrix调用异常。在开发过程中,因为核心线程数设置的比较大,没有出现这种异常。放到了测试环境,偶尔有出现这种情况,后来在网上查找解决方案,网上的方案是调整maxQueueSize属性就好了,当时调整了一下,确实有所改善。可没想到在生产环境跑了一段时间后却又出现这种了情况,此时我第一想法就是去查看maxQueueSize属性,可是maxQueueSize属性是设置值了。当时就比较纳闷了,为什么maxQueueSize属性不起作用,后来通过查看官方文档发现Hystrix还有一个queueSizeRejectionThreshold属性,这个属性是控制队列最大阈值的,而Hystrix默认只配置了5个,因此就算我们把maxQueueSize的值设置再大,也是不起作用的。两个属性必须同时配置

先看一下正确的Hystrix配置姿势。

application.yml:

hystrix:
threadpool:
default:
coreSize: 200 #并发执行的最大线程数,默认10
maxQueueSize: 1000 #BlockingQueue的最大队列数,默认值-1
queueSizeRejectionThreshold: 800 #即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝,默认值5

接下来编写一个测试类,来验证几种错误配置,看看会出现什么情况。

测试类代码(A调用方):


/**
* @Author: XiongFeng
* @Description:
* @Date: Created in 11:12 2018/6/11
*/
public class RepaymentHelperTest extends FundApplicationTests { @Autowired
RepaymentHelper repaymentHelper;
@Autowired
private RouterFeign routerFeign; @Test
public void hystrixTest() throws InterruptedException { for (int i = 0; i < 135; i++) {
new Thread(new Runnable() {
@Override
public void run() {
job();
}
}).start();
} Thread.currentThread().join();
} public void job() {
String repaymentNo = "xf1002";
String transNo = "T4324324234";
String reqNo = "xf1002";
String begintime = "20180831130030";
String endtime = "20180831130050"; TransRecQueryReqDto transRecQueryReqDto = new TransRecQueryReqDto();
transRecQueryReqDto.setTransNo(transNo);
transRecQueryReqDto.setBeginTime(begintime);
transRecQueryReqDto.setEndTime(endtime);
transRecQueryReqDto.setReqNo(reqNo); Resp<List<TransRecDto>> queryTransRecListResp = routerFeign.queryTransRec(new Req<>(repaymentNo, "2018080200000002", null, null, transRecQueryReqDto)); System.out.println(String.format("获取结果为:【%s】", JsonUtil.toJson(queryTransRecListResp)));
}
}
  • 这个测试类的作用就是创建135个线程,通过RouterFeign类并发请求B服务方,看看请求结果是否出现异常。

Feign调用代码:


@FeignClient(value = "${core.name}", fallbackFactory = RouterFeignBackFactory.class, path = "/router")
public interface RouterFeign { /**
* 代扣结果查询
* @param transRecQueryReqDtoReq
* @return
*/
@PostMapping("/queryTransRec")
Resp<List<TransRecDto>> queryTransRec(@RequestBody Req<TransRecQueryReqDto> transRecQueryReqDtoReq); }
  • 这个类,就是通过Feign方式去调用B服务方的客户端

服务提供方代码(B服务方):

/**
* @Author: XiongFeng
* @Description:
* @Date: Created in 16:04 2018/5/24
*/
@Api("还款服务")
@RefreshScope
@RestController
@RequestMapping("/router")
public class TestController { private static Logger logger = LoggerFactory.getLogger(TestController.class); // 计数器
private static AtomicInteger count = new AtomicInteger(1); @ApiOperation(value = "代扣结果查询")
@PostMapping("/queryTransRec")
Resp<List<TransRecDto>> queryTransRec(@RequestBody Req<TransRecQueryReqDto> transRecQueryReqDtoReq) throws InterruptedException {
System.out.println(String.format("查询支付结果......计数: %s", count.getAndAdd(1)));
Thread.sleep(500);
return Resp.success(RespStatus.SUCCESS.getDesc(), null);
}
  • 这个类的作用,就是一个服务提供方,计数并返回结果。

下面我们看一下几种错误的配置。

案例一(将核心线程数调低,最大队列数调大一点,但是队列拒绝阈值设置小一点):
hystrix:
threadpool:
default:
coreSize: 10
maxQueueSize: 1000
queueSizeRejectionThreshold: 20
此时的结果:

  • 左窗口是B服务方,右窗口是A调用方。从结果可以看出,调用135次,成功32次左右,其余线程全部抛异常。
案例二(将核心线程数调低,最大队列数调小一点,但是队列拒绝阈值设置大一点):
hystrix:
threadpool:
default:
coreSize: 10
maxQueueSize: 15
queueSizeRejectionThreshold: 2000
此时的结果:
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@7d6d472b rejected from java.util.concurrent.ThreadPoolExecutor@17f8bcb7[Running, pool size = 3, active threads = 3, queued tasks = 15, completed tasks = 0]

  • 左窗口是B服务方,右窗口是A调用方。从结果可以看出,调用135次,成功25次左右,其余线程全部抛异常。。
案例三(将核心线程数调低,最大队列数调大一点,但是队列拒绝阈值不设置值):
hystrix:
threadpool:
default:
coreSize: 10
maxQueueSize: 1500
此时的结果:
java.util.concurrent.RejectedExecutionException: Rejected command because thread-pool queueSize is at rejection threshold.

  • 左窗口是B服务方,右窗口是A调用方。此时的结果和案例一的情况一样,调用135次,成功47次左右,其余线程全部抛异常。报错跟案例一一样
案例四(将核心线程数调低,最大队列数不设值,但是队列拒绝阈值设置的比较大):
hystrix:
threadpool:
default:
coreSize: 10
queueSizeRejectionThreshold: 1000
此时的结果:
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@23d268ea rejected from java.util.concurrent.ThreadPoolExecutor@66d0e2f4[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)

  • 左窗口是B服务方,右窗口是A调用方。此时的结果和案例二的情况一样,调用135次,成功10次左右,其余线程全部抛异常。报错跟案例二一样

下面来看一看正确的配置案例

案例一:将核心线程数调低,最大队列数和队列拒绝阈值的值都设置大一点):
hystrix:
threadpool:
default:
coreSize: 10
maxQueueSize: 1500
queueSizeRejectionThreshold: 1000
此时的结果:

  • 左窗口是B服务方,右窗口是A调用方。此时的结果就完全正常了,并发请求了135次,全部成功!
结论:官方默认队列阈值只有5个, 如果要调整队列,必须同时修改maxQueueSize和queueSizeRejectionThreshold属性的值,否则都会出现异常!
参考文档:

Spring Hystrix 官方文档

踩坑 Spring Cloud Hystrix 线程池队列配置的更多相关文章

  1. 危险的Hystrix线程池

    本文介绍Hystrix线程池的工作原理和参数配置,指出存在的问题并提供规避方案,阅读本文需要对Hystrix有一定的了解. 文本讨论的内容,基于hystrix 1.5.18: <dependen ...

  2. 基于Spring Boot的线程池监控方案

    前言 这篇是推动大家异步编程的思想的线程池的准备篇,要做好监控,让大家使用无后顾之忧,敬畏生产. 为什么需要对线程池进行监控 Java线程池作为最常使用到的并发工具,相信大家都不陌生,但是你真的确定使 ...

  3. 第五章 服务容错保护:Spring Cloud Hystrix

    在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...

  4. Spring Cloud Hystrix 服务容错保护

    目录 一.Hystrix 是什么 二.Hystrix断路器搭建 三.断路器优化 一.Hystrix 是什么 ​ 在微服务架构中,我们将系统拆分成了若干弱小的单元,单元与单元之间通过HTTP或者TCP等 ...

  5. 7、Spring Cloud Hystrix

    1.Spring Cloud Hystrix简介 (1).分布式问题 复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败. 多个微服务之间调用的时候,假设微服务A调 ...

  6. Spring Cloud 微服务笔记(六)Spring Cloud Hystrix

    Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...

  7. spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略

    spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略 某电子商务网站在一个黑色星期五 ...

  8. Spring Cloud Hystrix理解与实践(一):搭建简单监控集群

    前言 在分布式架构中,所谓的断路器模式是指当某个服务发生故障之后,通过断路器的故障监控,向调用方返回一个错误响应,这样就不会使得线程因调用故障服务被长时间占用不释放,避免故障的继续蔓延.Spring ...

  9. 分布式系统的延时和故障容错之Spring Cloud Hystrix

    本示例主要介绍 Spring Cloud 系列中的 Eureka,如何使用Hystrix熔断器容错保护我们的应用程序. 在微服务架构中,系统被拆分成很多个服务单元,各个服务单元的应用通过 HTTP 相 ...

随机推荐

  1. C++的 RTTI 观念和用途(非常详细)

    自从1993年Bjarne Stroustrup [注1 ]提出有关C++ 的RTTI功能之建议﹐以及C++的异常处理(exception handling)需要RTTI:最近新推出的C++ 或多或少 ...

  2. 【Web前端Talk】React-loadable 进行代码分割的基本使用

    随着项目功能的扩充.版本迭代,我们与Webpack捆绑起来的的项目越来越大,大到开始影响加载速度了.这时我们就该考虑如何对代码进行拆分了. 这次我们一起学习一下如何对React项目中的代码进行Code ...

  3. 用java打印日历

    来自<java核心技术卷一> /** * Created by wangbin10 on 2019/1/3. * 打印当月日历 */ public class CalendarTest { ...

  4. Redis 学习笔记(篇一):字符串和链表

    本次学习除了基本内容之外主要思考三个问题:why(为什么).what(原理是什么).which(同类中还有哪些类似的东西,相比有什么区别). 由于我对 java 比较熟悉,并且 java 中也有字符串 ...

  5. 程序代写, CS代写, 代码代写, CS编程代写, java代写, python代写, c++/c代写, R代写, 算法代写, web代写

    互联网一线工程师程序代写 微信联系 当天完成 查看大牛简介特色: 学霸代写,按时交付,保证原创,7*24在线服务,可加急.用心代写/辅导/帮助客户CS作业. 客户反馈与评价 服务质量:保证honor ...

  6. 《linux内核设计与实现》阅读笔记-进程与调度

      一.进程 process: executing program code(text section) data section containing global variables open f ...

  7. 曹工说Tomcat2:自己撸一个简易Tomcat Digester

    一.前言 框架代码其实也没那么难,大家不要看着源码就害怕,现在去看 Tomcat 3.0的代码,保证还是看得懂一半,照着撸一遍基本上很多问题都能搞定了.这次我们就模拟 Tomcat 中的 Digest ...

  8. 长春理工大学第十四届程序设计竞赛(重现赛)F

    F. Successione di Fixoracci 题目链接:https://ac.nowcoder.com/acm/contest/912/F 题目: 动态规划(Dynamic programm ...

  9. Java NIO学习系列三:Selector

    前面的两篇文章中总结了Java NIO中的两大基础组件Buffer和Channel的相关知识点,在NIO中都是通过Channel和Buffer的协作来读写数据的,在这个基础上通过selector来协调 ...

  10. kettle —— 从 oracle 到 oracle的坑

    公司有个项目,是使用kettle从oracle上统计,再将结果跟oracle中目标表进行对比更新.接手后,走了一些弯路,中间各种尝试都不尽如人意,也学了kettle的一些组件的用法.正好趁着机会记录 ...