首页 > 其他分享 >记几次 [线上环境] Dubbo 线程池占满原因分析(第二次:CompletableFuture)

记几次 [线上环境] Dubbo 线程池占满原因分析(第二次:CompletableFuture)

时间:2023-04-04 18:36:07浏览次数:42  
标签:Dubbo 池占满 dubbo 线程 应用 CompletableFuture 日志

转载:https://blog.csdn.net/wsmalltiger/article/details/124236189

文章目录
[线上环境] Dubbo 线程池占满原因排查系列
前言
一、问题分析
1、分析日志
2、定位原因
二、解决方案
三、总结
前言
  某天早上9点左右收到线上故障报警,超过3个商家反馈“无法正常进入功能页面,点击相关操作提示报错”。
  经过排查定位,故障应用线上部署了30台机器(4c8g),由于代码中使用 CompletableFuture不规范引起部分机器(8/30台)dubbo 线程池耗尽出现故障。而我们的dubbo框架采用随机负载均衡策略,导致故障机器还会有流量过去,打在故障机器的请求都会出现异常。

一、问题分析
1、分析日志
  商家反馈的是“无法正常进入页面,点击操作报错”,所以第一反应就是去看看线上是否有ERROR日志,如果能够找到报错日志那么就能很快定位到问题的原因,先看前端node应用系统日志:

根据上面日志信息很快得到两个结论:
1、在9:09至9:23期间出现了较多的error日志,目前已经逐步平稳;
2、问题期间后端接口出现了dubbo线程池占满的情况。

继续查看下游后端应用日志,发现dubbo线程池占满的还是更底层的一个应用(底层应用dubbo线程池占满引起了雪崩效应):

根据上游日志traceId(调用链ID,上下游所有相关系统都会打印,方便查找整条请求链路的日志)继续排查底层应用日志:

这里发现同一个请求在底层应用中产生了大量的日志,这明显不正常。继续查看dubbo服务监控,发现底层应用确实出现了大量的dubbo线程池占满的情况,线程队列堆积较多:

底层应用接口RT情况统计,可以看到由于dubbo线程池出现排队,RT普遍增高:

这里基本已经定位到问题应用了,接下来需要继续排查下具体的原因。


2、定位原因
  根据上面定位到的应用和日志,分析发现 ForkJoinPool.commonPoll-worker 线程日志有明显增高:

   review 日志相关的代码逻辑,发现内部有较多地方使用 CompletableFuture 并发处理业务请求,且使用了默认线程池 ForkJoinPool。(CompletableFuture 是java 8 JUC库新增的主要工具,同传统的Future相比,其支持流式计算、函数式编程、完成通知、自定义异常处理等很多新的特性)
   问题代码截图:

这里调用了 CompletableFuture.supplyAsync 方法,查看方法源码:

这里使用了 asyncPool,继续查看定义,发现默认会使用 ForkJoinPool 线程池:

   CompletableFuture.supplyAsync 方法有两个,我们出问题的代码使用了第一个方法,就会使用默认的线程池,而另一个方法的第二个参数支持自定义线程池。由于这个应用业务的复杂性还有很多代码都使用到了CompletableFuture,并且都使用默认的线程池。

这里已经确认了问题原因:
1、应用多处使用了 CompletableFuture.supplyAsync 方法,但是都使用的是默认线程池,所以当多个业务并发过大时会引起线程阻塞,由于入口是dubbo请求过来,进而也会导致dubbo线程出现阻塞;
2、代码在调用 CompletableFuture.allOf(…).get() 方法时,入参没有传超时时间,也就是说如果线程产生阻塞会一直等待,直到有结果返回,这里再次把问题放大了。


编写测试代码,模拟线上场景运行相关业务代码,确实能够复现线程池出现堆积的情况:

 

二、解决方案
1、对问题代码 CompletableFuture 的线程池进行了自定义,不在使用默认的线程池,避免影响其他业务;

2、对 CompletableFuture.allOf(…).get() 方法增加了超时时间参数,如果在一定时间内没有返回结果,则抛出超时异常,避免长时间占用系统资源,优化后代码;

CompletableFuture.allOf(futureList.toArray(new CompletableFuture[]{})).get(timeOut,TimeUnit.MILLISECONDS);
1
3、举一反三,我们统一梳理了应用中使用到 CompletableFuture 的地方,根据业务使用场景 自定义了线程池和超时时间参数设置。这样能够保证一个业务发生性能瓶颈时不会影响其他业务或者一定范围缩小问题的影响面;


三、总结
1、常用的开源框架大多都非常的成熟,但是业务代码开发同学如果使用姿势不当,也会引起比较大的问题。
2、在集群部署环境下如果出现线程池队列占满的情况,及时依次重启服务(清空队列)也是一种能够快速恢复问题的方法,但是问题的根因还是需要定位到并且彻底解决的。
3、学会举一反三,一个地方出现了问题,那么检查一下系统其他地方是否也有相同的问题。问题不暴露不代表它不存在,举一反三及时排掉“未爆炸的雷”,也是对系统稳定性的一种保障。

————————————————
版权声明:本文为CSDN博主「smatiger」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wsmalltiger/article/details/124236189

标签:Dubbo,池占满,dubbo,线程,应用,CompletableFuture,日志
From: https://www.cnblogs.com/ceshi2016/p/17287338.html

相关文章

  • 记几次 [线上环境] Dubbo 线程池占满原因分析(第一次:HttpClient)
    转载:https://blog.csdn.net/wsmalltiger/article/details/124236055前言  我们一个核心应用,线上部署了4台机器(4c8g),某天晚上8点左右线上忽然出现dubbo线程池占满告警,上游应用error日志也疯狂报警,整个过程持续了4分钟左右系统自动恢复正常。  dubbo默认200个线程池,报错日志信......
  • Dubbo——扩展(SPI)加载原理
    摘要Dubbo为了更好地达到OCP原则(即“对扩展开放,对修改封闭”的原则),采用了“微内核+插件”的架构。那什么是微内核架构呢?微内核架构也被称为插件化架构(Plug-inArchitecture),这是一种面向功能进行拆分的可扩展性架构。内核功能是比较稳定的,只负责管理插件的生命周期,不会因为系统功......
  • Dubbo——服务治理(dubbo-Admin)平台
    摘要本博文将介绍Dubbo最新的服务治理平台的实现原理。详细介绍服务治理中的路由规则、动态配置、访问控制、权重管理、负载均衡的实现原理。服务治理平台总体结构Dubbo有新旧两个服务治理平台,旧的服务治理平台在Dubbo2.6.0以后就从源码中被移除了,现在已经没有继续维护。新的服务......
  • dubbo 限制方法线程数_不可忽视的Dubbo线程池避坑指南
    转载:https://blog.csdn.net/weixin_39574140/article/details/110193195?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-110193195-blog-121764780.235%5Ev27%5Epc_relevant_recovery_v2&depth_1-ut......
  • dubbo线程池又被打爆(打满)了java.util.concurrent.RejectedExecutionException: Thread
    转载:https://blog.csdn.net/kevin_mails/article/details/121764780?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-121764780-blog-124236206.235%5Ev27%5Epc_relevant_recovery_v2&depth_1-utm_sourc......
  • 记几次 [线上环境] Dubbo 线程池占满原因分析(第三次:GC STW)
    转载:https://blog.csdn.net/wsmalltiger/article/details/124236206前言  某天晚上正在开开心心写代码,忽然收到了线上告警:dubbo线程池活跃线程数告警、应用错误日志告警、dubbo线程池队列长度告警;瞬间意识到要出大事情了,得赶紧定位到原因并解决问题,不然时间长了肯定会影响商......
  • Kotlin 协程真的比 Java 线程更高效吗?
    vivo互联网技术微信公众号 作者:吴越网上几乎全部介绍Kotlin的文章都会说Kotlin的协程是多么的高效,比线程性能好很多,然而事情的真相真是如此么?协程的概念本身并不新鲜,使用C++加上内嵌汇编,一个基本的协程模型50行代码之内就可以完全搞出来。早在2013年国内就有团队开源了号称支持......
  • 多线程任务怎么选 Thread,ThreadPoll,Task
    提问多线程任务怎么选Thread,ThreadPoll,Task回答Task原因Thread:创建销毁代价昂贵ThreadPoll:管理线程资源Task基于线程池......
  • Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了
    如何阻止JavaSpringBootTest单元测试中包括多线程时,没跑完就结束了使用CountDownLatchCountDownLatch、CyclicBarrier使用区别多线程ThreadPoolTaskExecutor应用JavaBasePooledObjectFactory对象池化技术@SpringBootTestpublicclassPoolTest{@Test......
  • 线程池之FutureTask、ThreadPoolExecutor源码分析
    前言在我们日常工作中,我们经常会用到多线程的来处理一些异步任务,提高系统吞吐量,但是线程毕竟是一种昂贵的系统的资源,我们不应该频繁的去申请销毁。在java的projectloom还未正式release的时候,我们常用池化的方式来使用线程。所以了解线程池的设计思想能够有助于我们更好的使用它,......