Undertow阻塞排查思路

前言

某次组织线上性能压测,发现接口超时,通过skywalking查看调用链发现服务内所有的接口都在undertow耗时严重,特此记录排查流程。


一、Undown是什么?

Undertow 是一个轻量、高性能的 Java Web 服务器,由 JBoss 开发并作为 WildFly 应用服务器的默认 Web 容器。它基于非阻塞的异步 IO(NIO)模型,支持 HTTP/1.1、HTTP/2 和 WebSocket,同时具备低内存占用和高吞吐量的特点,适合嵌入式场景或作为独立服务器使用。


Undertow 的核心特点

  1. 非阻塞 IO:基于 NIO 实现高并发处理能力。
  2. 模块化设计:可自由选择功能模块(如 Servlet、WebSocket)。
  3. 嵌入式支持:轻松集成到 Java 应用中(如 Spring Boot)。
  4. 灵活的编程模型:支持 Servlet 4.0 和低级 Handler API(直接操作 HTTP 请求/响应)。
  5. 低资源消耗:默认内存占用远低于 Tomcat/Jetty。

XNIO 线程池

Undertow 的底层依赖 XNIO(一个高性能 IO 框架),其线程池模型是 Undertow 高性能的关键。XNIO 的线程池分为两类:

1. Worker 线程池

  • 职责:处理阻塞任务(如 Servlet 业务逻辑、数据库操作)。
  • 配置参数
    • core-pool-size:核心线程数(默认 = CPU 核心数 × 8)。
    • max-pool-size:最大线程数(默认 = core-pool-size × 8)。
    • keepalive-time:空闲线程存活时间。
  • 特点:适用于需要阻塞操作的场景,通过多线程避免阻塞 IO 线程。

2. IO 线程池

  • 职责:处理非阻塞 IO 操作(如请求解析、响应写入)。
  • 线程数:默认等于 CPU 核心数(每个线程绑定一个 NIO Selector)。
  • 特点:完全非阻塞,线程数通常较少,避免上下文切换开销。

线程池配置示例(Spring Boot)

application.properties 中调整线程池参数:

# 调整 Worker 线程池
server.undertow.threads.worker=200
server.undertow.threads.io=16

最佳实践

  1. IO 密集型场景(如微服务网关):

    • 增加 Worker 线程池 的大小(例如 200-500)。
    • 保持 IO 线程池 默认值(通常等于 CPU 核心数)。
  2. 计算密集型场景

    • 控制 Worker 线程池 大小,避免过多线程导致上下文切换。
    • 确保业务逻辑不阻塞 IO 线程。
  3. 避免阻塞 IO 线程

    • 在 Servlet 或 Handler 中,长时间任务应提交到 Worker 线程池。

为什么选择 Undertow?

  • 性能优势:在同等资源下,Undertow 的吞吐量通常高于 Tomcat/Jetty(Techempower 基准测试)。
  • 灵活性:通过 Handler 机制可深度定制请求处理流程。
  • 轻量化:适合云原生和容器化部署。

如果需要进一步优化,可通过 XNIO 的 OptionMap 调整高级参数(如缓冲区大小、连接超时)。

二、排查步骤

1.jstack导出线程快照

执行命令:

jstack [进程ID] > thread-dump.txt

2.通过第三方工具分析

在线分析线程快照工具
threadanalyzer.online
spotify
fastthread
以fastthread为例,上传线程快照后发现,XNIO线程池包含大量线程。其中存在慢接口导致线程耗时过长,调用该接口的大量线程等待,导致其他正常接口排队。


总结

使用jstack 在压测的时候导出线程快照,找到等待线程中的方法。

posted @ 2025-04-29 09:45  HBOrea  阅读(320)  评论(0)    收藏  举报