问题现象
客户反馈 TongWeb7 启动速度较慢,完整启动接近两分钟。
刚开始接收到这个问题时,不能直接判断是 TongWeb 本身启动慢。
因为 Java 应用启动过程比较复杂,除了中间件自身初始化,还可能受到外部环境影响,例如:
- JVM参数配置
- 服务器DNS解析
- 应用部署耗时
- 磁盘IO
- 安全软件
- Java Agent
所以排查重点需要确认:
启动时间到底消耗在哪里。
是 TongWeb 自身组件初始化慢,还是 JVM 启动过程中被其他组件影响。
一、为什么选择jstack排查?
对于 Java 应用启动慢的问题,日志只能看到启动过程中的一些事件,但是无法直接看到 JVM 当前正在执行什么。
例如:
日志显示:
TongWeb starting...
但是不知道:
- 当前卡在哪个线程?
- 正在执行哪个类?
- 是否一直停留在某个方法?
这时候可以使用 JDK 自带工具 jstack。
jstack是什么?
jstack 是 JDK 提供的 JVM 线程诊断工具。
它可以打印 Java 进程当前所有线程的信息,包括:
- 线程名称
- 线程状态
- 当前执行方法
- 锁等待情况
- 调用链
简单理解:
jstack就是查看Java程序当前"正在做什么"的工具。
在启动慢、CPU异常、线程死锁等问题排查中,经常使用 jstack 分析。
二、jstack常用使用方式
1. 获取Java进程PID
首先查看 TongWeb JVM 进程:
bash
ps -ef | grep java
例如:
tongweb 12345 java com.tongweb.server.ThorBootstrap
其中:
12345
就是 JVM 的 PID。
2. 生成线程dump
执行:
bash
jstack 12345 > tongweb_dump.log
生成的文件中包含当前 JVM 所有线程信息。
例如:
"main" #1
java.lang.Thread.State: RUNNABLE
at xxx.xxx.xxx
可以通过调用链判断线程当前执行位置。
3. 为什么需要连续抓取?
单次 jstack 只能代表某一个时间点。
如果是启动卡顿,需要连续抓取多次。
例如:
jstack PID > dump1.log
sleep 5
jstack PID > dump2.log
sleep 5
jstack PID > dump3.log
然后对比三个文件。
如果发现某个线程:
几秒甚至十几秒一直停留在同一个方法,
说明启动耗时可能就在这里。
三、编写自动抓取脚本
由于客户环境不方便重复操作,所以编写了:
bash
#!/bin/bash
# TongWeb启动卡顿自动抓取线程dump脚本
DUMP_DIR=$(pwd)
WAIT_TIMEOUT=120
INTERVAL=1
DUMP_TIMES=3
SLEEP_BETWEEN_DUMP=3
echo "停止正在运行的TongWeb"
sh stopserver.sh
sleep 2
echo "后台启动TongWeb"
sh startservernohup.sh
START_TIME=$(date +%s)
PID=""
while true
do
NOW=$(date +%s)
ELAPSED=$((NOW - START_TIME))
if [ ${ELAPSED} -ge ${WAIT_TIMEOUT} ];then
echo "超过等待时间,未检测到TongWeb进程"
exit 1
fi
PID=$(ps -ef | grep ThorBootstrap | grep -v grep | awk '{print $2}')
if [ -n "${PID}" ];then
echo "成功获取TongWeb PID=${PID}"
break
fi
echo "等待TongWeb启动 ${ELAPSED}s"
sleep ${INTERVAL}
done
i=1
while [ $i -le ${DUMP_TIMES} ]
do
FILE="${DUMP_DIR}/tongweb_start_dump_$(date +%Y%m%d_%H%M%S)_${i}.log"
echo "生成dump文件:${FILE}"
jstack ${PID} > ${FILE}
sleep ${SLEEP_BETWEEN_DUMP}
i=$((i+1))
done
echo "抓取完成"
脚本主要作用:
- 停止当前 TongWeb
- 重新后台启动 TongWeb
- 自动获取 TongWeb PID
- 连续抓取3次 jstack
- 保存线程快照方便分析
执行:
bash dump_start_block.sh
核心逻辑:
PID=$(ps -ef | grep ThorBootstrap | grep -v grep | awk '{print $2}')
jstack ${PID} > tongweb_start_dump.log
通过自动化方式,避免客户手动操作导致采集信息不完整。
四、分析客户提供的jstack
客户提供了三个时间点的 dump:
第一次:
2026-07-30 15:25:51
第二次:
2026-07-30 15:25:59
第三次:
2026-07-30 15:26:07
三个 dump 间隔约8秒。
重点查看 JVM 主线程。
三个文件中都出现:
"main" #1
java.lang.Thread.State: RUNNABLE
at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
at java.net.InetAddress.getLocalHost(InetAddress.java:1507)
at sun.management.VMManagementImpl.getVmId(VMManagementImpl.java:140)
at com.moresec.loader.agent.IastLoaderAgent.getProcessId(IastLoaderAgent.java:239)
at com.moresec.loader.agent.IastLoaderAgent.premain(IastLoaderAgent.java:43)
五、关键调用分析
重点关注:
com.moresec.loader.agent.IastLoaderAgent
继续向上看调用关系:
IastLoaderAgent
↓
获取Java进程信息
↓
InetAddress.getLocalHost()
↓
主机名解析
这里可以发现:
当前线程执行的并不是 TongWeb 内部代码。
而是在加载:
MoresecAgent
IastLoaderAgent
这说明 JVM 启动阶段存在外部 Java Agent。
六、什么是Java Agent?
Java Agent 是一种 JVM 扩展机制。
它可以在 Java 应用启动之前,通过:
-javaagent
参数加载。
常见用途:
- 安全检测
- 应用监控
- 链路追踪
- 字节码增强
例如:
服务器安装漏洞扫描工具后,可能会自动给 Java 服务增加 Agent。
此时:
Java应用启动流程变成:
JVM启动
↓
加载Java Agent
↓
Agent初始化
↓
TongWeb启动
↓
应用加载
如果 Agent 初始化耗时,就会影响整体启动时间。
七、三次dump对比定位问题
三个时间点中:
main线程一直停留:
com.moresec.loader.agent.IastLoaderAgent.getProcessId
说明:
经过多个时间点采样,线程没有明显推进。
如果是 TongWeb 自身部署慢,通常会看到:
Deployer
ApplicationLoader
WebContainer
EJB
等相关调用。
但是本次没有出现 TongWeb 初始化相关调用。
反而一直停留:
MoresecAgent
IastLoaderAgent
InetAddress.getLocalHost
因此判断:
TongWeb启动慢不是TongWeb自身原因,而是外部安全Agent影响。
八、最终定位结果
继续和客户确认服务器环境。
客户反馈:
服务器安装了漏洞检测工具。
该工具通过 Java Agent 方式注入 TongWeb JVM。
启动过程中:
- JVM加载安全Agent
- Agent获取Java进程信息
- Agent获取服务器主机信息
- 执行安全检测逻辑
其中:
InetAddress.getLocalHost()
涉及主机名解析。
如果服务器DNS或者hosts配置不合理,会进一步增加耗时。
最终确认:
TongWeb7启动慢主要由于服务器漏洞扫描工具加载Java Agent导致。
九、处理建议
1. 查看Java启动参数
执行:
ps -ef | grep java
确认是否存在:
-javaagent
参数。
2. 检查hosts解析
执行:
hostname
cat /etc/hosts
确认服务器 hostname 可以正常解析。
3. 验证安全工具影响
可以临时关闭漏洞扫描工具,再重新启动 TongWeb。
如果启动时间恢复正常,则可以进一步确认。
十、这次排查学到了什么
以前遇到中间件启动慢的问题,容易关注:
- TongWeb启动日志
- 应用部署情况
- JVM内存参数
但是实际生产环境中:
Java应用启动链路并不只有中间件本身。
很多外部组件都会参与 JVM 启动:
- 安全扫描工具
- 监控Agent
- 链路追踪工具
这些组件通过 Java Agent 进入 JVM 后,也可能影响启动速度。
通过这次问题排查,最大的收获:
排查Java应用问题,不能只看应用本身,需要站在整个JVM启动链路分析。
使用连续多个时间点的 jstack,可以快速判断:
到底是 TongWeb 卡住了,
还是外部组件影响了启动流程。