写点什么

记一次故障引发的线程池使用的思考

  • 2020-03-15
  • 本文字数:2621 字

    阅读完需:约 9 分钟

记一次故障引发的线程池使用的思考

一、悬案

某日某晚 8 时许,一阵急促的报警电话响彻有赞分销员技术团队的工位,小虎同学,小峰同学纷纷打开监控平台一探究竟。分销员系统某核心应用,接口响应全部超时,dubbo 线程池被全部占满,并堆积了大量待处理任务,整个应用无法响应任何外部请求,处于“夯死”的状态。



正当虎峰两位同学焦急的以各种姿势查看应用的各项指标时,5 分钟过去了,应用居然自己自动恢复了。看似虚惊一场,但果真如此吗?

二、勘查线索

2.1 QPS

“是不是又有商家没有备案就搞活动了啊”,小虎同学如此说道。的确,对于应用突然夯死,大家可能第一时间想到的就是流量突增。流量突增会给应用稳定性带来不小冲击,机器资源的消耗的增加至殆尽,就像我们去自助餐厅胡吃海喝到最后一口水都喝不下,当然也就响应不了新的请求。我们查看了 QPS 的状况。



事实让人失望,应用的 QPS 指标并没有出现陡峰,处于一个相对平缓的上下浮动的状态,小虎同学不禁一口叹气,看来不是流量突增导致的.

2.2 GC

“是不是 GC 出问题了”,框架组一位资深的同学说道。JVM 在 GC 时,会因为 Stop The World 的出现,导致整个应用产生短暂的停顿时间。如果 JVM 频繁的发生 Stop The World,或者停顿时间较长,会一定程度的影响应用处理请求的能力。但是我们查看了 GC 日志,并没有任何的异常,看来也不是 GC 异常导致的。


2.3 慢查

“是不是有慢查导致整个应用拖慢?”,DBA 同学提出了自己的看法。当应用的高 QPS 接口出现慢查时,会导致处理请求的线程池中(dubbo 线程池),大量堆积处理慢查的线程,占用线程池资源,使新的请求线程处于线程池队列末端的等待状态,情况恶劣时,请求得不到及时响应,引发超时。但遗憾的是,出问题的时间段,并未发生慢查。

2.4 TIMEDOUT

问题至此已经扑朔迷离了,但是我们的开发同学并没有放弃。仔细的小峰同学在排查机器日志时,发现了一个异常现象,某个平时不怎么报错的接口,在 1 秒内被外部调用了 500 多次,此后在那个时间段内,根据 traceid 这 500 多次请求产生了 400 多条错误日志,并且错误日志最长有延后好几分钟的。



这是怎么回事呢?这里有两个问题让我们疑惑不解:


  1. 500 QPS 完全在这个接口承受范围内,压力还不够。

  2. 为什么产生的错误日志能够被延后好几分钟。


日志中明显的指出,这个 http 请求 Read timed out。http 请求中读超时设置过长的话,最终的效果会和慢查一样,导致线程长时间占用线程池资源(dubbo 线程池),简言之,老的出不去,新的进不来。带着疑问,我们翻到了代码。



但是代码中确实是设置了读超时的,那么延后的错误日志是怎么来的呢?我们已经接近真相了吗?

三、破案

我们不免对这个 RestTemplateBuilder 起了疑心,是这个家伙有什么暗藏的设置嘛?机智的小虎同学,针对这个工具类,将线上的情况回放到本地进行了模拟。我们构建了 500 个线程同时使用这个工具类去请求一个 http 接口,这个 http 接口让每个请求都等待 2 秒后再返回,具体的做法很简单就是 Thread.sleep(2000),然后观察每次请求的 response 和 rt。



我们发现 response 都是正常返回的(没有触发 Read timed out),rt 是规律的 5 个一组并且有 2 秒的递增。看到这里,大家是不是感觉到了什么?对!这里面有队列!通过继续跟踪代码,我们找到了“元凶”。



这个工具类默认使用了队列去发起 http 请求,形成了类似 pool 的方式,并且 pool active size 仅有 5。


现在我们来还原下整个案件的经过:


  1. 500 个并发的请求同时访问了我们应用的某个接口,将 dubbo 线程池迅速占满(dubbo 线程池大小为 200),这个接口内部逻辑需要访问一个内网的 http 接口

  2. 由于某些不可抗拒因素(运维同学还在辛苦奋战),这个时间段内这个内网的 http 接口全部返回超时

  3. 这个接口发起 http 请求时,使用队列形成了类似 pool 的方式,并且 pool active size 仅有 5,所以消耗完 500 个请求大约需要 500/5*2s=200s,这 200s 内应用本身承担着大约 3000QPS 的请求,会有大约 3000*200=600000 个任务会进入 dubbo 线程池队列(如悬案中的日志截图)。PS:整个应用当然就凉凉咯。

  4. 消耗完这 500 个请求后,应用就开始慢慢恢复(恢复的速率与时间可以根据正常 rt 大致算一算,这里就不作展开了)。

四、思考

到这里,大家心里的一块石头已经落地。但回顾整个案件,无非就是我们工作中或者面试中,经常碰到或被问到的一个问题:“对象池是怎么用的呢?线程池是怎么用的呢?队列又是怎么用的呢?它们的核心参数是怎么设置的呢?”。答案是没有标准答案,核心参数的设置,一定需要根据场景来。拿本案举例,本案涉及两个方面:

4.1 发起 http 请求的队列

这个使用队列形成的 pool 的场景是侧重 IO 的操作,IO 操作的一个特性是需要有较长的等待时间,那我们就可以为了提高吞吐量,而适当的调大 pool active size(反正大家就一起等等咯),这和线程池的的 maximum pool size 有着异曲同工之处。那调大至多少合适呢?可以根据这个接口调用情况,平均 QPS 是多少,峰值 QPS 是多少,rt 是多少等等元素,来调出一个合适的值,这一定是一个过程,而不是一次性决定的。那又有同学会问了,我是一个新接口,我不知道历史数据怎么办呢?对于这种情况,如果条件允许的话,使用压测是一个不错的办法。根据改变压测条件,来调试出一个相对靠谱的值,上线后对其观察,再决定是否需要调整。

4.2 dubbo 线程池

在本案中,对于这个线程池的问题有两个,队列长度与拒绝策略。队列长度的问题显而易见,一个应用的负载能力,是可以通过各种手段衡量出来的。就像我们去餐厅吃饭一样,顾客从上桌到下桌的平均时间(rt)是已知的,餐厅一天存储的食物也是已知的(机器资源)。当餐桌满了的时候,新来的客人需要排队,如果不限制队列的长度,一个餐厅外面排上个几万人,队列末尾的老哥好不容易轮到了他,但他已经饿死了或者餐厅已经没吃的了。这个时候,我们就需要学会拒绝。可以告诉新来的客人,你们今天晚上是排不上的,去别家吧。也可以把那些吃完了,但是赖在餐桌上聊天的客人赶赶走(虽然现实中这么挺不礼貌,但也是一些自助餐限时 2 小时的原因)。回到本案,如果我们调低了队列的长度,增加了适当的拒绝策略,并且可以把长时间排队的任务移除掉(这么做有一定风险),可以一定程度的提高系统恢复的速度。


最后补一句,我们在使用一些第三方工具包的时候(就算它是 spring 的),需要了解其大致的实现,避免因参数设置不全,带来意外的“收获”。


总结了这么多,小虎和小峰同学,终于心满意足的走向了自助餐厅,开始享用他们的晚餐。


2020-03-15 20:19873

评论

发布
暂无评论
发现更多内容

用友发布业界首个企业服务大模型YonGPT

用友BIP

再获权威认可!MIAOYUN荣获中国信通院一云多芯优秀案例,荣登《云管理产品与服务图谱》

MIAOYUN

中国信通院 一云多芯解决方案 一云多芯 可信云大会 云管理产品与服务图谱

Java基础 日期和时间

java易二三

程序员 计算机 java 编程

Java一维数组是什么,怎么用?

java易二三

Java 编程 程序员 数组 计算机

并发编程-FutureTask解析 | 京东物流技术团队

京东科技开发者

并发编程 源码剖析 FutureTask 企业号 7 月 PK 榜

数仓现网案例丨超大结果集接收异常

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 7 月 PK 榜

HBase Compaction 原理与线上调优实践

vivo互联网技术

HBase 调优参数 Minor Compaction Compaction策略 Major Compaction

印刷行业MES系统解决方案

万界星空科技

开源 MES系统 印刷

长连接:ChatGPT流式响应背后的逻辑 | 京东物流技术团队

京东科技开发者

websocket 长连接 企业号 7 月 PK 榜 sse

直播程序源码开发建设:洞察全局,数据统计与分析功能-山东布谷科技创作

山东布谷科技

软件开发 直播 源码搭建 程序源码 mac数据分析统计软件

JAVA和JVM运行原理是什么?

java易二三

Java 编程 JVM 计算机 程序猿

Java Web应用开发案例|使用AJAX实现省市区三级联动效果

TiAmo

Java Java web 开发实例

英特尔合作埃森哲推出一套共计34个开源AI参考套件

E科讯

一文让你知道等保测评和渗透测试的区别与联系

行云管家

信息安全 渗透测试 等级保护 等保测评

在langchain中使用带简短知识内容的prompt template

程序那些事

人工智能 AI 程序那些事 AI大语言模型 大语言模型

暑期读书指南 | 用缤纷字体读精品好书,华为阅读上新啦!

最新动态

【观察】智能运维的“下半场”,看云智慧如何“开新局”

云智慧AIOps社区

算法 运维 智能运维 大模型 IT运维

视觉套件专项活动!与飞桨技术专家一起提升技术实力,更多荣誉奖励等你领取

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

开发语音APP源码的小知识

山东布谷网络科技

app源码

初探webAssembly | 京东物流技术团队

京东科技开发者

前端 webassembly JavaScrip Blazor WebAssembly 企业号 7 月 PK 榜

AREX:携程新一代自动化回归测试工具的设计与实现

AREX 中文社区

开源 测试工具 回归测试 流量回放

密集发布AI应用后,微软2023财报传递了什么信号|TE解读

TE智库

澜舟科技CEO周明:不过度追求AGI,更看重大模型语言理解能力和应用落地性 | 1号位

澜舟孟子开源社区

大文件传输过程中的网络拥塞控制方法研究

镭速

大文件传输 网络拥塞问题

用Rust生成Ant-Design Table Columns | 京东云技术团队

京东科技开发者

rust swagger 企业号 7 月 PK 榜 Columns

暑假提升休闲两不误,与华为阅读一起开启高质量听书

最新动态

Inpaint Anything:一键进行多种图像修补

华为云开发者联盟

人工智能 华为云 华为云开发者联盟 企业号 7 月 PK 榜

Java程序员常用的日志框架有哪些?

java易二三

Java 编程 程序员 计算机

NineData已支持「最受欢迎数据库」PostgreSQL

NineData

postgresql 客户端 数据源 NineData 集成AI

fastposter v2.16.0 让海报开发更简单

物有本末

图片处理 海报生成器 海报生成

Qualcomm WiFi7 Routerboard,IPQ9574,4X4,4XM.2,SFP,Industrial High Power|DR9574

wallyslilly

ipq9574

记一次故障引发的线程池使用的思考_文化 & 方法_陈阳_InfoQ精选文章