iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Dubbo线程池事故排查的方法步骤
  • 468
分享到

Dubbo线程池事故排查的方法步骤

2024-04-02 19:04:59 468人浏览 薄情痞子
摘要

这篇文章主要介绍“dubbo线程池事故排查的方法步骤”,在日常操作中,相信很多人在Dubbo线程池事故排查的方法步骤问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Dubbo线

这篇文章主要介绍“dubbo线程池事故排查的方法步骤”,在日常操作中,相信很多人在Dubbo线程池事故排查的方法步骤问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Dubbo线程池事故排查的方法步骤”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

问题

在一天早上突然手机收到公司服务告警短信,线程池耗尽了?在去公司的路上首先回想的就是最近公司有活动?流量突增?大早上就有人在发布系统?还是某歪趁我不在又点坏了我的系统?

怀着种种思考在公司的群里看着同步信息,以上种种可能都被反驳!!!

以下就是当时的告警信息:

RejectedExecutionException:Thread pool is EXHAUSTED (线程池耗尽了)! Thread Name: DubboServerHandler-xx.xx.xxx:2201, Pool Size: 300 (active: 283, core: 300, max: 300, largest: 300)

Q:这个问题怎么出现的呢?是不是我们扩大线程池就能解决问题呢?dubbo里面线程池默认实现是什么呢?

A:我们在排查问题的时候一定要有一种必须查出因果关系的思想才能对自己有一定的提升,凭借着这种思想我们一步一步向下揭开谜底。

带着问题,接下来我们去查看dubbo的代码配置,了解dubbo底层实现,只有了解底层实现我们才能更加准确的发现问题,处理问题,提升自己......

首先我们看下我们代码配置:

<dubbo:protocol name="dubbo" port="${service.protocol.dubbo.port}" threads="${service.protocol.dubbo.threads}" reGISter="${service.protocol.dubbo.register}" />

从抛出的异常上我们已经设置的线程池的大小为300了

  • 这里我说明一个点,不是线程池配置的越大就越好,这个是授我们系统层面,以及配置JVM参数相关的。一般我们都是默认配置200  大致可以从这几方面去做考虑:

  • 1.JVM参数:-Xms 初始堆大小 -Xmx 最大堆大小 -Xss 每个线程栈大小2.系统层面1.系统最大可创建的线程 2.公式线:程数量 =  (机器本身可用内存 - (JVM分配的堆内存+JVM元数据区)) / Xss的值

言归正传我们开始看下撸点源码,这里我们以 2.7.19的版本为例

Dubbo线程池事故排查的方法步骤

我们可以看到ThreadPool接口是个扩展点,然后默认实现是fixed,然后里面有个getExecutor方法,被@Adaptive注解修饰。

在dubbo中ThreadPool有4个实现类

Dubbo线程池事故排查的方法步骤

1.CachedThreadPool 缓存线程池,超过keepAliveTime时间删除,使用的时候再创建

2.FixedThreadPool 固定线程数量线程池,一旦建立,一直持有。

3.LimitedThreadPool 可伸缩线程池,线程只增长不收缩。

4.EagerThreadPool 当core线程数忙的时候,创建新线程,而不是将任务放入阻塞队列。这个使用自己队列TaskQueue。

这里我们就直接看默认实现FixedThreadPool

Dubbo线程池事故排查的方法步骤

异常处理机制

Dubbo线程池事故排查的方法步骤

从代码中我们可以发现:

dubbo线程池采用jdk的ThreadPoolExecutor,默认threads数为200,并且默认采用了SynchronousQueue队列,而如果用户配置的队列长度大于0时,则会采用LinkedBlockingQueue队列。

如果某个线程因为执行异常而结束,那么线程池会添加一个新的线程。

所以由于dubbo默认采用了直接提交的SynchronousQueue工作队列,所以,所有的task会直接提交给线程池中的某一worker线程,如果没有可用线程,那么会拒绝任务的处理然后抛出我们当前现在遇到的问题

以下说明下我们创建一个线程池的必要参数 :

  • corePoolSize - 池中所保存的线程数,包括空闲线程。

  • maximumPoolSize-池中允许的最大线程数。

  • keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

  • unit - keepAliveTime 参数的时间单位。

  • workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute方法提交的 Runnable任务。

  • threadFactory - 执行程序创建新线程时使用的工厂。

  • handler 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。ThreadPoolExecutor是Executors类的底层实现。

好,看了这么多源码,从上面我们已经了解这个异常来的来源了,那是什么原因导致我遇到的这次的线程池耗尽呢?

排查思路

第一阶段:

由于10.33.xx.xxx这台机器出现线程池耗尽的时候,伴随出现了一次时间比较久的yGC;所以怀疑是因为ygc时间较长,导致了机器资源紧张,从而拖垮了线程池;

2021-03-26T10:14:45.476+0800: 64922.846: [GC (Allocation Failure) 2021-02-24T11:17:45.477+0800: 64922.847: [ParNew: 1708298K->39822K(1887488K), 3.9215459 secs] 4189242K->2521094K(5033216K), 3.9225545 secs] [Times: user=12.77 sys=0.00, real=3.92 secs]

所以就一直在思考什么原因导致YGC时间这么长:

这里给大家简单说明下为什么IO高会导致GC时间长

1.JVM GC需要通过发起系统调用write(),来记录GC行为。

2.write()调用可以被后台磁盘IO所阻塞。

3.记录GC日志属于JVM停顿的一部分,因此write()调用的时间也会被计算在JVM STW的停顿时间内。

通过GC日志可以看到新生代在进行垃圾回收的时候停顿时间是在3.92s;对于新生代空间在1.8G左右的显然是不正常的;ParNew收集器的工作过程中会出现以下步骤:

(1)标记-标记出来活着的对象 ----> (2) 将对象从eden区复制到survior区 -----> (3)清理eden区

理论上来说第三步的时间是一定的,那可能时间会比较久的要么在第一步,要么在第二步

如果是第一步标记时间过长,就意味着本次GC之前,eden区存在大量的小对象(因为eden区大小是一定的),量级应该是正常的对象数量的数十倍

如果是第二步时间过长的话,那么存在以下可能:

1.标记完之后,eden区还有大量的对象(表现是回收之后新生代的对象占用内存仍然很大),这个从gclog可以排除(回收之后新生代的大小还有39M)

2.标记完之后仍然有大量碎片化的小对象存在

3.YGC出发了fullGC,但是我们没有查看到有关日志

此时以上的情况都指向一种可能,那就是新生代存在大量的碎片化的小对象;

为了验证这个论据,那就只有一种办法就是去分析一下堆快照,但是我们那个时候刚好机器被重起,无法查明原因

在我们无法验证的时候,第二台机器出现了同样的问题,准备再次jump日志的时候,回过头来看了一下GC日志,发现GC正常。所以推翻阶段一结论

这里给大家介绍一些我们常用的服务器命令:

top : 这是最常用的,也是展示信息最全的,可以看到负载,内存,cpu等很多东西

比如使用top常见分析步奏:

1.top -Hp命令,查看具体是哪个线程占用率较高 2.使用printf命令查看这个线程的16进制  3.使用jstack命令查看当前线程正在执行的方法

Dubbo线程池事故排查的方法步骤

使用jmap查看内存情况,并分析是否存在内存泄露。

jmap -heap 3331:查看java 堆(heap)使用情况

jmap -histo 3331:查看堆内存(histogram)中的对象数量及大小

jmap -histo:live 3331:JVM会先触发gc,然后再统计信息

jmap -dump:fORMat=b,file=heapDump 3331:将内存使用的详细情况输出到文件

当然还有很多其他的命令比如 jstack,jinfo,uptime 等等很多命令。。。

开启阶段二的排查:

第二次出现异常的机器伴随着各种Redis查询超时,从而导致所有的查询 都走到了DB,从而导致数据库压力大增,慢sql告警等等。

所以又再次去查询什么原因导致我们的redis查询超时呢?

第一步肯定都是去查看redis服务的各项性能指标是不是出现异常,结果也没有很大的变化,那么问题肯定是在服务器本身.

查看本身指标发现:

那就是在报警时间段,cpu,cpu_iowait, 指标会飙升,磁盘IO则呈现不间断锯齿状,其余指标基本不存在波动

但是什么原因引起的CPU波动呢?cpu波动跟线程池耗尽之间又有什么因果关系呢?

因此似乎得到了答案磁盘IO较高,导致cpu_iowait变高,cpu等IO,瞬间分配不到时间片,rt就会抖动。

最后我们发现跟我们的磁盘IO较高的原因时又跟我们的日志采集系统有关,相信现在很大一部分的公司都会用TRACE作为服务的全程链路最终管理。

再采用异步方式把记录在内存中trace日志一次性写入磁盘,所以会出现IO抖动。

接下来我们看下trace 他到底是怎么工作的。

  • trace 是类似 strace 的动态跟踪工具,属于问题诊断和调试工具 1.trace 包括两部分:收集跟踪日志和解析跟踪日志。2.trace  收集跟踪日志实质上是运行跟踪模块时记录的控制流信息的日志

重点: trace 模块将上述信息组织成二进制格式写入内存中,直到停止 trace 跟踪,才将上述内存中的信息导出为二进制文件

这个只是给大家提供一个思路,每个人遇到问题或者场景都不一样那得到的结论也都不一样,只能是给大家作为一个参考吧!!!

到此,关于“Dubbo线程池事故排查的方法步骤”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Dubbo线程池事故排查的方法步骤

本文链接: https://www.lsjlt.com/news/83144.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Dubbo线程池事故排查的方法步骤
    这篇文章主要介绍“Dubbo线程池事故排查的方法步骤”,在日常操作中,相信很多人在Dubbo线程池事故排查的方法步骤问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Dubbo线...
    99+
    2024-04-02
  • Java 线程池的性能优化与故障排查
    Java 线程池性能优化与故障排查 性能优化 调整线程池大小:根据应用程序的负载模式调整核心线程数和最大线程数,以避免过载或资源不足。使用 JMX 或其他监控工具监控线程池活动,并根据需要进行调整。 复用线程:当任务之间存在相似性时,可以...
    99+
    2024-03-13
    线程池
  • 线程池满Thread pool exhausted排查和解决方案
    目录发生{Thread pool is EXHAUSTED}时的服务器日志产生原因 大并发导致配置的线程不够用调用外部接口程序出现阻塞,等待时...
    99+
    2022-11-21
    线程池满 Thread pool exhausted 线程池满排查 线程池满解决
  • Node.js 子线程Crash 问题的排查方法
    前言:昨天碰到了一个 worker_threads crash 的问题,最终经过阅读源码和调试找到了具体原因。不得不说,阅读源码是解决问题的非常有效的方法。 代码例子如下。 inde...
    99+
    2024-04-02
  • @Async异步线程池以及线程的命名方式
    本文记录@Async的基本使用以及通过实现ThreadFactory来实现对线程的命名。 @Async的基本使用 近日有一个道友提出到一个问题,大意如下: 业务场景需要进行批量更新,...
    99+
    2024-04-02
  • Java线程池的实现方法
    本篇内容主要讲解“Java线程池的实现方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java线程池的实现方法”吧!以前做的东西,实现一个简单的多线程机制,开始之前,现说说原理性的东西吧,下面...
    99+
    2023-06-17
  • Python爬虫代理池搭建的方法步骤
    搭建Python爬虫代理池的方法步骤如下:1. 安装所需的依赖库:首先,确保你已经安装了Python和pip。然后使用pip安装所需的库,如requests、beautifulsoup、flask等。2. 获取代理IP:你可以从一些免费...
    99+
    2023-08-11
    Python
  • 小程序实现事件绑定的方法步骤
    目录1 事件1.1 小程序中常用的事件1.2 事件对象的属性列表1.2.1 target 和 currentTarget 的区别1.3 bindtap 的语法格式1.4 在事件处理函...
    99+
    2024-04-02
  • Python中多线程和线程池的使用方法
    Python是一种高级编程语言,它在众多编程语言中,拥有极高的人气和使用率。Python中的多线程和线程池是其强大的功能之一,可以让我们更加高效地利用CPU资源,提高程序的运行速度。本篇博客将介绍Py...
    99+
    2023-10-12
    python
  • C#线程池ThreadPool.QueueUserWorkItem接收线程执行的方法
    ThreadPool.QueueUserWorkItem方法接收一个委托(Delegate),用于指定要在线程池中执行的方法。委托的...
    99+
    2023-09-12
    C#
  • Java多线程 - 创建线程池的方法 - ThreadPoolExecutor和Executors
    文章目录 线程池(重点)线程池介绍实现线程池的方式方式一: 实现类ThreadPoolExecutorThreadPoolExecutor构造器的参数线程池处理Runnable任务线程池处理Callable任务 方式二: ...
    99+
    2023-08-30
    java jvm 开发语言
  • Python线程池的正确使用方法
    目录Python线程池的正确使用1、为什么要使用线程池呢?2、线程池怎么用呢?3、如何非阻塞的获取线程执行的结果4、线程池的运行策略Python线程池的正确使用 1、为什么要使用线程...
    99+
    2024-04-02
  • java中多线程与线程池的基本使用方法
    目录前言继承Thread 实现Runnale接口Callable线程池常见的4种线程池。总结前言 在java中,如果每个请求到达就创建一个新线程,开销是相当大的。在实际使用中,服务器...
    99+
    2024-04-02
  • MySQL故障排查的方法是什么
    MySQL故障排查方法主要包括以下几个步骤:1. 确认故障现象:通过观察数据库的表现和错误日志来判断故障的具体表现,比如错误代码、错...
    99+
    2023-10-20
    MySQL
  • java线程池创建的方法是什么
    在Java中,线程池可以使用以下两种方法来创建: 使用`Executors`类中的静态方法来创建线程池: ExecutorSer...
    99+
    2023-10-25
    java
  • spring配置线程池的方法是什么
    在Spring中配置线程池的方法有两种: 使用XML配置文件: 首先,在Spring的XML配置文件中添加一个元素,指定线程池...
    99+
    2023-10-25
    spring
  • Java线程池优化的方法是什么
    这篇文章主要介绍“Java线程池优化的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java线程池优化的方法是什么”文章能帮助大家解决问题。升级版线程池的优化新增了4种拒绝策略。分别为:M...
    99+
    2023-06-29
  • Java线程池的使用方法有哪些
    本文小编为大家详细介绍“Java线程池的使用方法有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java线程池的使用方法有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。线程池的创建⽅法总共有 7 种,但...
    99+
    2023-07-05
  • quartz线程池配置的方法是什么
    要配置Quartz线程池,可以使用以下方法:1. 在Quartz配置文件中配置线程池属性:可以在quartz.properties文...
    99+
    2023-09-18
    quartz
  • java线程池实现的方法是什么
    Java中线程池的实现方法是通过使用java.util.concurrent包中的ThreadPoolExecutor类来创建和管理...
    99+
    2023-10-11
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作