Tomcat 服务频繁崩溃的排查方法
Tomcat 服务频繁崩溃通常是由于资源不足、配置问题、应用程序本身的缺陷或外部压力导致的。以下是系统化的排查和解决方法,涵盖常见问题的分析与修复。
1. 检查 Tomcat 的日志文件
Tomcat 的日志是排查问题的第一步,通常日志文件位于 logs
目录下:
- 主日志文件:
catalina.out
- 错误日志:
localhost.yyyy-mm-dd.log
、host-manager.yyyy-mm-dd.log
- 访问日志:
access_log.yyyy-mm-dd.log
1.1 检查 catalina.out
使用以下命令查看日志尾部:
bash
tail -f /path/to/tomcat/logs/catalina.out
- 常见错误及排查方向:
错误日志内容 可能原因 解决方法 OutOfMemoryError: Java heap space
JVM 堆内存不足 增加堆内存(见 2.1 部分)。 OutOfMemoryError: GC overhead limit
GC 无法回收内存,导致资源耗尽 调优垃圾回收器(见 2.2 部分)。 Too many open files
文件描述符过多,超过系统限制 增加文件描述符限制(见 3.2 部分)。 Connection refused
或Timeout
数据库或外部服务连接失败 检查数据库或服务状态,优化连接池配置(见 4.3 部分)。 ClassNotFoundException
或NoClassDefFoundError
缺少必要的类或依赖 检查 WEB-INF/lib
下的依赖是否完整,或升级依赖版本。PermGen space
(旧版本 Java)永久代(PermGen)内存不足 增加 PermGen
内存大小,或升级到 Java 8 使用 Metaspace(见 2.1 部分)。
2. 检查和调整 JVM 配置
Tomcat 使用的 JVM 参数会直接影响性能和稳定性。
2.1 检查和调整堆内存
编辑 Tomcat 的启动脚本(如 setenv.sh
或 catalina.sh
),确认或调整 JVM 参数:
bash
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m"
-Xms
和-Xmx
:设置堆内存的最小值和最大值。-XX:PermSize
和-XX:MaxPermSize
:设置永久代大小(仅适用于 Java 7 及以下)。- 推荐值:
- 小型应用:
-Xms512m -Xmx1024m
- 中型应用:
-Xms1024m -Xmx2048m
- 大型应用:
-Xms2048m -Xmx4096m
- 小型应用:
2.2 调优垃圾回收器
默认垃圾回收器可能不适合高并发或大内存场景,可以尝试以下 JVM 参数:
- 使用 G1 垃圾回收器(推荐 Java 8+):
bash
export JAVA_OPTS="-Xms1024m -Xmx2048m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
- 设置 GC 日志以便分析:
bash
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*:gc.log:time,uptime,level,tags"
检查 GC 日志中的停顿时间,如果过多且过长,需进一步优化。
2.3 检查线程配置
Tomcat 的线程池配置可能不足或过多:
- 检查
server.xml
中的连接器配置:xml<Connector port="8080" protocol="HTTP/1.1" maxThreads="200" minSpareThreads="10" acceptCount="100" ... />
- 参数说明:
maxThreads
:最大线程数,建议根据并发量调整(如 200-500)。acceptCount
:请求队列长度,超过后会拒绝连接。
3. 检查系统资源限制
3.1 检查 CPU 和内存
使用 top
或 htop
查看 Tomcat 的资源占用:
bash
top -p $(pgrep -d',' java)
- 如果 CPU 占用过高,可能是应用逻辑问题(如死循环)。
- 如果内存不足,可能需要增加服务器内存或优化 JVM 配置。
3.2 增加文件描述符限制
Linux 系统默认的文件描述符限制可能不足,尤其在高并发场景下。
- 查看当前限制:
bash
ulimit -n
- 临时增加限制(仅当前会话有效):
bash
ulimit -n 65535
- 永久增加限制:
编辑/etc/security/limits.conf
,添加:plaintext* soft nofile 65535 * hard nofile 65535
3.3 检查磁盘 I/O
- 使用
iostat
检查磁盘 I/O:bashiostat -x 1 5
- 如果磁盘 I/O 过高,可能是日志写入频繁或文件操作过多。
4. 检查应用程序和外部依赖
4.1 检查应用程序代码
- 是否存在内存泄漏:
- 使用工具如 Eclipse MAT 或 VisualVM 分析堆转储文件(
heap dump
)。
- 使用工具如 Eclipse MAT 或 VisualVM 分析堆转储文件(
- 是否存在死锁:
- 使用
jstack
查看线程堆栈:bashjstack <Tomcat_PID>
- 使用
4.2 检查数据库连接池
- 数据库连接未正确关闭可能导致连接耗尽。
- 检查
server.xml
中的连接池配置:xml<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" />
- 参数说明:
maxActive
:最大连接数。maxIdle
:空闲连接数。maxWait
:等待连接的最大时间(毫秒)。
4.3 检查外部服务
- 如果 Tomcat 依赖其他服务(如 API 网关、第三方接口),检查其可用性和响应时间。
- 使用工具如
curl
或ping
测试服务连通性。
5. 检查并优化网络配置
5.1 检查端口占用
- 查看 Tomcat 是否占用指定端口:
bash
netstat -tulnp | grep 8080
5.2 配置连接超时
- 检查 Tomcat 的连接器超时配置:
xml
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" ... />
connectionTimeout
:连接超时时间(毫秒),可根据实际需要调整。
6. 总结与排查流程
步骤 | 检查内容 | 参考工具 / 配置文件 |
---|---|---|
1. 检查日志 | 查看错误日志、异常堆栈 | catalina.out 、localhost.log |
2. JVM 调优 | 堆内存、GC 配置、线程池 | JAVA_OPTS 、server.xml |
3. 系统资源 | CPU、内存、文件描述符、磁盘 I/O | top 、ulimit 、iostat |
4. 应用检查 | 内存泄漏、线程死锁、数据库连接池 | jstack 、VisualVM 、server.xml |
5. 网络配置 | 端口占用、连接超时 | netstat 、server.xml |
通过以上方法,您可以系统地排查 Tomcat 服务频繁崩溃的问题,并采取针对性的优化措施。