SpringBoot-Undertow应用waitting状态线程异常增加的问题探究

1、大量线程增加

正在运行的程序,突然上午出现了用户大量反馈,数据加载不出来了,并且一直在转圈,我登录系统查看,确实有一个主要接口请求一直在pending状态,然后我们一看接口是调用了外部接口,告警袭来也是调用外部接口出现了超时,我们找到了对应的接口对接人,查询了接口问题,原因在于查询ES阻塞了,具体原因未知。

2、可视化监控分析

找到原因之后,我们开始打开GrafanaJVM监控,查看下应用运行情况,发现今天出现接口超时问题之后,等待线程超出了以前的两倍的大小,

image_249e0d98.png

waiting线程出现了569,平时一般都在240左右

正好增长的时候是出现超时的时候出现的问题

非堆内存出现了一点点的增长

在想因为堵塞,所以用户在不断刷新,然后线程不断创建,创建之后,等过了这段时间,线程数空闲的就少了,然后就能降下来,但是过了一天后,线程数量基本没有太大的变化,一直维持在600左右

然后开始排查是什么线程创建了这么多,通过jstack pid > stack.log 拿到本地来用可视化工具

IBM出的线程监控工具查看 stack.log文件

image_f1534cff.png

有大量的 Waiting on condition 状态的线程,然而通过查看虽然好多线程池创建的线程都有该状态的,但是只有XNIO-2线程池创建的任务线程处于此状态的最多,查询一看有300多,然后减去这300多正好是以前的线程数量,所以说这次增长的线程都是XNIO-2这个线程池创建的。

3、多谋善断 - 本地复现进一步判断

在本地启动程序,先设置

undertow:
    io-threads: 16
    worker-threads: 1024

与线上一样,同样的api接口加入sleep睡上永久,表示调用外部接口超时

然后利用JMeter进行压力测试,然后使用 Visual VM进行可视化查看应用变化情况

image_f7aa82a0.png image_8b3767dc.png

你有木有看到,蹭就上来了

300多个线程啊

然后改为

undertow:
    io-threads: 2
    worker-threads: 16

image_8c8f658a.png image_479e1aee.png

最后一张图,还可以看一下,我等待了一天了,这个线程也是不会自动停掉的,因为就是限制状态了,所以怀疑是不是核心线程数量,然后继续排查

4、源码探究

然后进一步排查问题

image_e15814ad.png

导出的线程堆栈里面总是出现的是这个类并且是这个行数

at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1482)

所以我就搜索这个类,找到对应行,查看下具体代码情况

因为看到XNIO 就知道是undertow的的线程池,因为undertow内部实现的IO就是叫做XNIO,

undertow源码内是与JBoss是有联系的,然后找到对应的Jar包

现在Idea中找到对应jboss的jar,然后再查看哪一个jar包中的package是包含org.jboss.threads的

image_d90cff91.png

发现jboss-threads的单独包

image_035e4e56.png

然后再jar包找到对应的类

image_c9ede9c6.png

因为EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1482)

有一个$符号,这个符号是指代 EnhancedQueueExecutor 有一个子类是 ThreadBody 并且有一个方法run

然后查看后面括号中有1482行

所以就很容易定位到该行代码了

image_109570c1.png

发现这行代码上面有一行注释(这行注释只有下载源码之后才可以看到呀)

image_343431c4.png

然后说明了现在创建了很多的XNIO-2-task-xxx的线程全部都是核心线程

点击newNode进入对应的类中,查看到了task这个线程名字

image_7dd1a173.png

5、探究Undertow与SpringBoot怎么结合的

在spring-boot-x.x.x-release包中的这个接口 org.springframework.boot.web.server.WebServer

是Spring嵌入式Web容器的一个规范接口,适配器模式

所有的适配的Tomcat、Undertow、JBoss等Web容器,进行实现这个类,实现start方法,在start方法中进行创建容器的实例

image_12bd38cc.png

org.springframework.boot.web.embedded.undertow.UndertowWebServer#start

spring-boot实现了undertow服务器,然后在start方法中并创建了一个undertow实例

image_57a40599.png

创建服务器的方法主要看一下176行的创建HTTP

image_c6ec82a6.png

获取了关于路径匹配的处理,获取springboot的配置文件中的配置

image_a60a65db.png

我们进入build直接看undertow创建的时候线程数量是怎么获取来的

image_329c9dc4.png

这个就是配置文件中的配置的数量

image_502526ba.png image_93e24dd7.png

可以根据代码,是可以追溯到的,直接点击worker-threads找到对应的方法,和从上一个截图中的方法往回找,能找到同一个方法,加入断点调试也可以找到的就是这个方法

org.springframework.boot.autoconfigure.web.ServerProperties.Undertow#setWorkerThreads

1529行

-------------------------------------------------------------------------------------------

继续往下走代码

image_941f8075.png

可以进入启动undertow服务的代码

work 线程池的名称

image_e6150446.png

这里就可以看到我们配置中的io线程和worker线程数量都配置到了哪里,可以通过名字很清楚的看到,workerthreads是核心线程和最大线程的值,那就是说worker-threads (新API中脚thread.worker)设置的数量是核心线程数量,核心线程数有一个规则就是一旦创建了,并且为空闲了,则是一直存在于线程池中,不会被回收的,也是还可以被复用的。

也就是说这里如果写了1024,那也就是1024如果都创建了,则在重启之前会一致存在的。

image_d1e7a47f.png

注释中写明了,WORKER_TASK_CORE_THREADS 为核心线程数

6、浪子回头 - 再到官方文档中查看

[https://undertow.io/undertow-docs/undertow-docs-2.0.0/index.html#xnio-workers][https_undertow.io_undertow-docs_undertow-docs-2.0.0_index.html_xnio-workers]

image_18e03517.png

翻译过来的意思是:

XNIO 工人

所有侦听器都绑定到一个 XNIO Worker 实例。通常只有一个 worker 实例在侦听器之间共享,但是可以为每个侦听器创建一个新的 worker。

工作实例管理侦听器 IO 线程,以及默认的阻塞任务线程池。有几个主要的 XNIO 工作选项会影响侦听器的行为。这些选项可以在 Undertow 构建器上指定为工作器选项,或者如果您手动引导服务器,则可以在工作器创建时指定。这些选项都驻留在org.xnio.Options类中。

WORKER_IO_THREADS

要创建的 IO 线程数。IO 线程执行非阻塞任务,永远不应该执行阻塞操作,因为它们负责多个连接,因此当操作阻塞时,其他连接基本上会挂起。每个 CPU 内核两个 IO 线程是合理的默认值。

WORKER_TASK_CORE_THREADS

worker 阻塞任务线程池中的线程数。当执行阻塞操作时,例如 Servlet 请求,将使用来自该池的线程。一般来说,很难为此给出合理的默认值,因为它取决于服务器的工作负载。通常,这应该相当高,每个 CPU 核心大约 10 个。

7、总结

所以在与线程数量的飙升是正常,并且一致存在也是正常的,所以,合理设置worker的数量还是非常重要的。

为了高并发,需要多设置多的核心线程,这样可以有效的提高并发,但是线程的设定也与CPU的核心数有直接关系,根据需求而进行设计。

注意: 先启动undertow的主线程,处理spring事情,然后最后再启动undertow的工作线程去启动服务

8、文中工具下载地址

IBM线程查看工具:[https://www.ibm.com/support/pages/ibm-thread-and-monitor-dump-analyzer-java-tmda][https_www.ibm.com_support_pages_ibm-thread-and-monitor-dump-analyzer-java-tmda]

Oracle Visual VM: [https://visualvm.github.io/download.html][https_visualvm.github.io_download.html]

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值