当你在启动 Tomcat 服务时,发现进程看似启动却无法正常提供服务,翻遍日志文件又找不到任何明显的错误信息,这种“沉默的失败”无疑让人头疼。本文将通过一个实际案例,分享三个行之有效的排查思路,帮助你快速定位并解决这类问题。
问题现象与日志分析
以下是典型的场景:执行启动脚本后,catalina.out 日志打印了一些初始化信息,然后就停滞了。
[root@m001 logs]# /data/tomcat/crm/bin/startup.sh
[root@m001 logs]# tail -f catalina.out
26-Feb-2026 15:59:44.338 信息 [main] org.apache.catalina.startup.Catalina.load 服务器在[443]毫秒内初始化
26-Feb-2026 15:59:44.356 信息 [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
26-Feb-2026 15:59:44.357 信息 [main] org.apache.catalina.core.StandardEngine.startInternal 正在启动 Servlet 引擎:[Apache Tomcat/9.0.31]
26-Feb-2026 15:59:44.369 信息 [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/data/tomcat/crm/webapps/datahubServer.war]
26-Feb-2026 15:59:44.729 信息 [main] org.apache.jasper.servlet.TldScanner.scanJars 至少有一个JAR被扫描用于TLD但尚未包含TLD。 为此记录器启用调试日志记录,以获取已扫描但未在其中找到TLD的完整JAR列表。 在扫描期间跳过不需要的JAR可以缩短启动时间和JSP编译时间。
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/data/tomcat/shared-libs/log4j-slf4j-impl-2.12.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/data/tomcat/shared-libs/slf4j-log4j12-1.7.30.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
从日志看,Tomcat 容器本身的初始化是成功的,但随后便卡在了部署应用 datahubServer.war 的阶段。日志最后停留在 SLF4J 绑定声明,这是一个关键信号:日志框架已经完成了初始化并接管了后续输出。程序没有崩溃,也没有抛出异常,那它究竟在做什么呢?通常,此时应用正处在 Spring 框架或业务代码的初始化 过程中,可能因为某些资源无法获取或执行了耗时操作而“卡住”。
面对这种局面,可以按照以下三种思路进行系统性 排查。
思路一:使用 jstack 强制打印线程堆栈(最快定位工具)
既然程序不声不响地停在那里,最直接的方法就是看看它内部所有线程当前正在执行什么代码。jstack 是 Java 开发者的“手术刀”,能够立刻揭示进程的内部状态。
操作步骤:
- 找到 Tomcat 进程的 PID (进程 ID):
ps -ef | grep tomcat
- 使用
jstack 命令导出所有线程的堆栈信息:
jstack <PID> > /tmp/stack.txt
分析技巧:
打开生成的 /tmp/stack.txt 文件,重点查看那些处于 RUNNABLE (正在运行) 或 WAITING/TIMED_WAITING (等待) 状态的线程。
- 等待网络I/O:如果看到大量线程卡在
SocketInputStream.read 或类似调用上,很可能是在等待数据库连接或远程接口响应。
- 熵池阻塞:如果发现线程在
SecureRandom 相关方法上等待,这是 Linux 新服务器上一个经典问题,因随机数熵池不足导致。
- 数据库连接问题:线程可能卡在数据库连接池获取连接的地方。
实战案例:
在本次问题中,执行 jstack 后,发现了明确的线索。
jstack pid >/tmp/stack.txt
分析堆栈文件,一眼就能看到有线程正在等待 Oracle 数据库连接池的资源,状态是 TIMED_WAITING。

根据这个线索,立即检查 Oracle 数据库状态,发现数据库实例已关闭,并且系统日志 (/var/log/messages) 中存在因内存不足 (OOM) 而终止进程的记录。

问题根源就此锁定:后端数据库不可用导致应用启动时初始化数据库连接池超时、挂起。
思路二:解决日志框架冲突(SLF4J Multiple Bindings)
回过头看最初的日志,其实已经给出了一个警告:Class path contains multiple SLF4J bindings。这表明类路径中包含了多个 SLF4J 的实现绑定(如 log4j-slf4j-impl 和 slf4j-log4j12)。
这种冲突可能导致:
- 日志输出行为不可预测,真正的错误日志可能被重定向到某个不为人知的文件,甚至被“吞掉”。
- 在极端情况下,可能引发类加载死锁,导致应用卡在初始化阶段。
解决方案:
进入日志中提示的目录(例如 /data/tomcat/shared-libs/),移除或重命名其中一个冲突的 JAR 包。通常建议保留更新、更主流的绑定(如 Log4j2 的 log4j-slf4j-impl),移除旧的绑定(如 slf4j-log4j12-1.7.30.jar)。
cd /data/tomcat/shared-libs/
mv slf4j-log4j12-1.7.30.jar slf4j-log4j12-1.7.30.jar.bak
然后重启 Tomcat,观察 catalina.out 是否能有更清晰的错误输出。
思路三:调整应用内部日志级别
Tomcat 的 logging.properties 只控制 Tomcat 自身的日志级别。你的 Web 应用(如 datahubServer.war)通常使用独立的日志框架,如 Log4j2 或 Logback。
操作步骤:
- 找到配置文件:解压或进入应用目录,查找日志配置文件。
# 通常路径如下
/data/tomcat/crm/webapps/datahubServer/WEB-INF/classes/log4j2.xml
或
/data/tomcat/crm/webapps/datahubServer/WEB-INF/classes/logback.xml
- 修改日志级别:将根日志级别从
INFO 改为 DEBUG,以便在初始化阶段打印更详细的信息。
<!-- 以Log4j2为例 -->
<Root level="DEBUG"> <!-- 原来是 INFO -->
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
- 检查日志路径:仔细查看配置文件中配置的
File 或 RollingFile Appender 的路径。很可能错误日志被输出到了应用专属的日志文件(如 logs/app.log),而不是 Tomcat 的 catalina.out。修改级别后,去正确的日志文件里寻找线索。
其他常见“卡死”原因速查
结合 jstack 和日志调整,你还可以快速排查以下高频问题:
- 数据库/远程服务连接超时:检查应用配置(如
application.properties 或 spring 配置文件)中的数据库连接串、用户名密码、网络可达性。
- Linux熵池不足导致SecureRandom阻塞:
如果 jstack 显示大量线程卡在 java.security.SecureRandom 相关方法,可在 tomcat/bin/catalina.sh 的 JAVA_OPTS 中添加参数解决:
JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"
- 内存溢出(OOM)但未生成日志:应用可能被操作系统直接终止。
- 检查系统日志:
dmesg | grep -i kill 或 grep -i oom /var/log/messages。
- 检查 Tomcat 日志目录下是否有 Java 生成的堆转储文件(
java_pidXXXX.hprof)。
通过以上“三板斧”——线程堆栈分析、日志冲突清理、日志级别调整,你就能系统性地攻克 Tomcat “启动不成功也不报错”的疑难杂症。在实际运维中,养成结合多种工具进行排查的习惯至关重要。希望这个案例能为你提供清晰的解决路径。欢迎在 云栈社区 分享你在实践中遇到的其他有趣案例或问题。