undertow运行一段时间后CPU过高

系统运行一段时间后CPU会升高,升高后不会下降,只有重启服务CPU才会回归正常。经过top -H P,发现CPU过高的线程ID基本不变,CPU使用率接近100%。通过jstack快照查看是CPU过高的线程ID快照,发现全是XNIO线程,无业务在处理,快照信息如下:

"XNIO-1 I/O-4" #77 prio=5 os_prio=0 tid=0x00007fd5141ec800 nid=0x433e runnable [0x00007fd513dfc000]
   java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000005d3c01e38> (a sun.nio.ch.Util$3)
- locked <0x00000005d3c01e28> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000005d3c01de0> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101)
at org.xnio.nio.WorkerThread.run(WorkerThread.java:532)

网上查了好多听说这是undertow使用NIO上的BUG,当某种未知的情况下会触发空跑,进入while(true)的空循环。
目前只有netty解决,求问在undertow下有什么解决办法,

“Devil组”引证GPT后的撰写:

  • 根据你提供的信息,CPU高占用的线程ID都是XNIO线程,这可能是因为某些问题导致Undertow使用NIO上的BUG,从而导致空跑进入while(true)的空循环。虽然有人通过使用Netty来解决这个问题,但在Undertow下也有一些可能的解决方案:
    升级Undertow版本
    可以尝试升级Undertow的版本,以确保使用的是最新版本的Undertow,并且该版本已经修复了该问题。
  • 调整Undertow线程池配置
    可以尝试调整Undertow线程池配置,以确保线程池大小和最大线程数与实际需要的匹配。此外,还可以尝试将I/O线程池的大小减少到1,并逐步增加以观察是否会影响性能。
  • 使用Undertow的Blocking I/O模式
    如果可能,可以尝试使用Undertow的Blocking I/O模式,以避免使用NIO导致的问题。
  • 调整JVM参数
    可以尝试调整JVM参数,如-Xmx、-Xms、-Xmn等,以确保JVM有足够的内存,并尝试禁用逃逸分析和JIT编译器,以避免某些与优化有关的问题。

该回答引用ChatGPT

您提到的问题可能是由于Undertow使用NIO线程池时遇到了一个已知的bug所导致的。根据您提供的信息,似乎是由于EPollSelectorImpl进入了无限循环状态,导致了CPU占用率的增加。这种情况下,只有重启服务才能恢复正常。

目前,这个问题已经被Undertow的开发人员确认,并已经在最新的版本中进行了修复。如果您的应用程序使用的是较旧的版本,建议升级到最新版本以解决此问题。

如果您无法升级到最新版本,可以尝试以下解决方法:

尝试在undertow的配置文件中设置worker-thread的数量,例如:


<http-listener name="default" socket-binding="http" worker-threads="50"/>

这将限制NIO线程池中的线程数量,并可能有助于减少CPU占用率。

尝试在启动应用程序时设置以下JVM参数:

-Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.PollSelectorProvider

这将使用旧的PollSelectorProvider而不是EPollSelectorProvider,这可能会避免EPollSelectorImpl进入无限循环状态,但也可能会对性能产生一些影响。

由于Undertow是JBOSS的Web服务器,因此这个问题可能也会影响到您的应用程序。解决这个问题的一个可能的方法是升级您的Undertow版本。

如果您的Undertow版本已经是最新的,那么您可以尝试使用以下方法来解决这个问题:

1、调整Undertow的线程池配置
尝试调整Undertow的线程池配置。通过增加工作线程的数量,可以减轻线程的压力,从而减少CPU的使用率。
例如,在undertow-core模块中,您可以找到org.xnio.nio.WorkerThread类。在这个类中,您可以尝试增加工作线程的数量。
2、调整JVM的参数
您可以尝试调整JVM的参数。例如,尝试增加GC的频率、减少堆的大小等。这可能会降低CPU的使用率。
例如,您可以尝试增加以下参数:

-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSInitiatingOccupancyOnly
-Xmx4g
-Xms4g

这些参数可能需要根据您的应用程序的需求进行调整。

3、尝试使用Netty
如果您仍然无法解决问题,那么您可以尝试使用Netty来替换Undertow。Netty是一个高性能的NIO框架,它比Undertow更稳定、更可靠。如果您的应用程序需要高性能的Web服务器,那么Netty可能是一个更好的选择。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
针对这个问题,可以尝试以下解决方案:

  1. 升级Undertow版本,升级到最新版本或者比较稳定的版本,看看是否有改善。

  2. 修改Undertow的配置文件,增加worker threads数量。可参考如下配置:

Undertow.builder()
              .addHttpListener(8080, "localhost")
              .setWorkerThreads(200)
              .build(); 
  1. 禁用NIO,使用传统的BIO。可参考如下配置:
Undertow.builder()
                .addHttpListener(8080, "localhost")
                .setIoThreads(Runtime.getRuntime().availableProcessors())
                .setWorkerThreads(200)
                .setHandler(handler)
                .setServerOption(UndertowOptions.BLOCKING_IO_THREADS, 200)
                .setServerOption(UndertowOptions.IOSHUTDOWN, false)
                .build();
  1. 通过自定义XnioWorker,实现对线程池进行监控,当线程池负载过高时,自动进行调整。可参考如下代码:
Xnio xnio = Xnio.getInstance();
    XnioWorker xnioWorker = xnio.createWorker(OptionMap.builder().set(Options.WORKER_TASK_CORE_THREADS, 200)
        .set(Options.WORKER_TASK_MAX_THREADS, 400)
        .set(Options.TCP_NODELAY, true)
        .set(Options.CORK, true)
        .set(Options.BACKLOG, 20000)
        .set(Options.TCP_OOB_INLINE, true)
        .set(Options.KEEP_ALIVE, true)
        .set(Options.ALLOW_BLOCKING, true)
        .getMap());

希望这些解决方案能对你有所帮助。
如果我的回答解决了您的问题,请采纳!

参考GPT和自己的思路,您的问题描述与Undertow中已知的一个问题类似,可能是由于NIO处理器的问题导致的空跑现象,导致CPU占用率过高。这个问题可能是由于操作系统中的某些限制或不足引起的,比如EPoll的限制,或者是Undertow中的某些配置问题。
以下是几个可能的解决方案:

1 升级Undertow版本
如果您的Undertow版本比较老,可以尝试升级到最新版本,看是否可以解决问题。Undertow的最新版本可以从官方网站上下载。

2 调整线程池大小
您可以尝试调整Undertow线程池的大小,以减少NIO处理器的压力。您可以通过修改Undertow的配置文件或者在代码中设置相关参数来完成这个操作。具体而言,可以通过修改Worker和Accept线程池大小、阻塞队列长度等参数来实现。

3 使用Netty代替Undertow
如果上述两种方法都无法解决问题,您可以考虑使用Netty代替Undertow。Netty是另一个流行的Java网络框架,具有类似的功能,并且也是基于NIO的。与Undertow不同,Netty已经在处理NIO上面的问题上有一定的经验和成熟的解决方案,因此可能会更加稳定。

希望以上几个方法能够对您有所帮助,祝您好运!

可以尝试升级Undertow版本,或者调整相关Undertow参数,例如增加处理器线程池大小、减少空闲超时时间等;另外,排查是否存在Undertow的配置问题或者网络IO问题。如果以上方法仍然无法解决问题,可以考虑使用其他框架替换Undertow。