
Tomcat 服务频繁崩溃是常见的服务器问题,可能由内存泄漏、线程阻塞、配置错误或资源耗尽等原因引起。以下是系统化的排查与解决方法:
**一、快速诊断步骤**
- **检查日志文件**
- 查看 `catalina.out` 和 `localhost.log`:
```bash
tail -n 100 /var/log/tomcat/catalina.out
grep -i "error\|exception" /var/log/tomcat/catalina.out
```
- 重点关注 `OutOfMemoryError`、`StackOverflowError` 或线程死锁信息。
- **监控资源使用**
- 实时查看内存和CPU:
```bash
top -p $(pgrep -f tomcat)
```
- 检查线程数:
```bash
ps -eLf | grep tomcat | wc -l
```
**二、常见原因及解决方案**
**1. 内存不足(OOM)**
-
**现象**:`java.lang.OutOfMemoryError: Java heap space`
-
**解决方法**:
-
调整JVM内存参数(在 `setenv.sh` 中设置):
```bash
export JAVA_OPTS="-Xms512m -Xmx1024m -XX:MaxMetaspaceSize=256m"
```
-
建议:
-
`Xms` 和 `Xmx` 设为相同值避免动态调整开销。
-
不超过系统物理内存的70%。
**2. 线程池耗尽**
-
**现象**:`java.util.concurrent.TimeoutException` 或请求卡死
-
**解决方法**:
-
修改 `conf/server.xml` 的Connector配置:
```xml
<Connector
executor="tomcatThreadPool"
maxThreads="200" <!-- 默认200,根据负载调整 -->
minSpareThreads="20"
acceptCount="100" <!-- 等待队列长度 -->
/>
```
- 监控线程使用:
```bash
jstack $(pgrep -f tomcat) | grep "http-nio" | wc -l
```
**3. 应用内存泄漏**
-
**排查工具**:
-
生成堆转储文件分析:
```bash
jmap -dump:format=b,file=/tmp/heap.hprof $(pgrep -f tomcat)
```
-
使用 `jvisualvm` 或 `Eclipse MAT` 分析泄漏对象。
-
**常见泄漏源**:
-
静态集合未清理、未关闭的数据库连接、第三方库Bug。
**4. 文件描述符耗尽**
-
**现象**:`Too many open files`
-
**解决方法**:
-
检查限制:
```bash
ulimit -n
```
- 修改系统限制(`/etc/security/limits.conf`):
```
tomcat soft nofile 65535
tomcat hard nofile 65535
```
**5. 数据库连接池问题**
-
**排查**:
-
检查连接池配置(如 `maxActive` 是否过高)。
-
监控数据库连接泄漏:
```sql
SHOW STATUS LIKE 'Threads_connected';
```
**三、高级排查工具**
- **JVM监控**
- 使用 `jstat` 观察GC情况:
```bash
jstat -gcutil $(pgrep -f tomcat) 1000
```
- 频繁Full GC(`FGC`列高)表明内存问题。
- **线程转储分析**
- 生成线程转储:
```bash
kill -3 $(pgrep -f tomcat) # 输出到catalina.out
```
- 使用 `fastthread.io` 在线分析死锁。
**四、预防措施**
- **定期维护**
-
启用Tomcat自带的 `Manager App` 监控应用状态。
-
配置日志轮转(`logrotate`)避免日志占满磁盘。
- **安全配置**
-
禁用不必要的Web应用(如 `examples`、`docs`)。
-
更新Tomcat至最新稳定版本。
- **健康检查**
- 添加启动脚本检测Tomcat状态,崩溃后自动重启:
```bash
while true; do
if ! pgrep -f tomcat; then
/opt/tomcat/bin/startup.sh
fi
sleep 60
done
```
**五、典型错误案例**
- **案例1**:部署的WAR包包含内存泄漏的第三方库(如旧版Apache POI)。
**解决**:升级库版本或移除冗余依赖。
- **案例2**:`maxThreads="500"` 但服务器仅2核,导致线程争抢。
**解决**:根据CPU核心数调整(推荐 `maxThreads = 核心数 * 200`)。
通过以上方法,可系统性定位Tomcat崩溃根源。若问题持续,建议结合APM工具(如SkyWalking)进行深度监控。