从日志入手定位 Tomcat 性能瓶颈的实操指南
一 准备与关键日志
- 确认日志目录与文件:Tomcat 常用日志位于 $CATALINA_HOME/logs,核心包括 catalina.out、localhost.yyyy-MM-dd.log、host-manager.yyyy-MM-dd.log、manager.yyyy-MM-dd.log,以及按应用配置的访问日志(Access Log)。这些日志分别承载 JVM/容器运行输出、应用本地日志、管理应用日志 和 HTTP 请求记录。
- 启用与规范输出:确保开启并规范 Access Log(记录响应时间、状态码、方法、URI 等),保留 GC 日志(用于停顿与频次分析),并在应用中输出关键业务阶段耗时(便于定位慢点)。
- 日志轮转与保留:使用 logrotate 按日/大小切分,避免单文件过大影响分析与采集;统一时间格式与字符集,便于关联与检索。
二 从访问日志识别吞吐与延迟问题
- 指标与阈值:关注 吞吐量(RPS)、P95/P99 响应时间、错误率。当 RPS 接近或超过处理能力、P95/P99 明显抬升、错误率上升,通常意味着瓶颈出现。
- 快速命令行分析示例(假设字段顺序为:客户端IP、时间、请求方法、URI、协议、状态码、响应时间ms):
- 统计总请求数、RPS 与错误率
- 总请求数:
wc -l access.log
- RPS(10 秒窗口):
awk '{t=$2; gsub(/:/,"",t); if(t>=start&&t<start+10) c++;} END {print c/10}' start=$(date -d '10 seconds ago' +%H:%M:%S) access.log
- 5xx 比例:
awk '$9>=500 {err++;} END {print err/NR}' access.log
- Top N 慢 URI(按响应时间字段,假设第 8 列为 ms)
sort -k8 -nr access.log | head -n 20 | awk '{print $4,$8}'
- 高峰时段识别
awk -F: '{h[$2]++;} END {for(i in h) print i,h[i]}' access.log | sort -n
- 可视化与聚合:将访问日志送入 ELK(Elasticsearch + Logstash + Kibana) 或 Grafana Loki,构建 P95/P99 趋势、Top URI、错误率 等面板,便于对比与告警。
三 从 Catalina 与 JVM 日志定位容器与运行时瓶颈
- 线程池饱和与排队:在 Catalina.out 或 localhost 日志中检索线程池相关输出,关注线程创建失败、拒绝任务、长时间排队等迹象;结合 server.xml Executor/Connector 的 maxThreads、minSpareThreads、acceptCount 等配置判断是否不足。
- 内存与 GC:开启并分析 GC 日志(如
-Xlog:gc*,gc+heap=debug:file=gc.log:time),若出现 频繁 Full GC 或 长暂停,多为 堆内存不足/泄漏 或对象生命周期不当。
- 异常与资源限制:检索 OutOfMemoryError(堆/元空间/无法创建线程)、SocketException: Too many open files 等,分别对应 JVM 内存、线程/文件描述符 限制问题。
- 线程转储深挖:在性能异常时抓取 3–5 次 jstack(间隔 5–10 秒),分析 RUNNABLE/BLOCKED/WAITING 线程栈,定位 锁竞争、外部依赖阻塞、I/O 等待 等根因。
四 从应用与数据库日志定位慢点与依赖瓶颈
- 应用耗时埋点:在关键路径(如 Controller → Service → DAO)输出 阶段耗时 与 traceId,便于把 Access Log 的响应时间 与 业务阶段 对齐,快速识别慢的业务逻辑。
- 数据库慢查询:若使用 JDBC/MySQL,开启 慢查询日志 并用 pt-query-digest 分析,定位 缺失索引、全表扫描、复杂子查询 等;结合 连接池监控(如等待线程、获取连接耗时)判断是否 连接不足/泄漏。
- 外部服务:在调用 HTTP/RPC/消息队列 前后打点,统计 RT 与错误率,识别 下游超时/抖动 造成的整体变慢。
五 系统化排查流程与优化建议
- 排查流程
- 定义窗口:选取 性能异常时段(如高峰或故障时段)。
- 访问日志快诊:计算 RPS、P95/P99、错误率,找出 Top 慢 URI。
- Catalina/JVM:检索 线程池饱和、OOM、Too many open files,分析 GC 暂停 与 线程转储。
- 应用与 DB:核对 业务阶段耗时、慢 SQL、连接池等待。
- 关联与验证:用 traceId 将 Access Log ↔ 应用日志 ↔ 线程转储 串联,复现实锤。
- 优化与回归:实施优化后,持续观测 相同口径指标 验证收益。
- 常见优化方向(按需)
- Tomcat/连接器:合理设置 maxThreads、minSpareThreads、acceptCount,必要时启用 压缩/缓存 降低传输与后端压力。
- JVM:根据负载调整 -Xms/-Xmx,优化 GC 策略,修复 内存泄漏。
- 数据库:建立 合适索引、优化 SQL、调整 连接池(如最大/最小连接、超时)、考虑 缓存(Redis/Memcached)。
- 系统资源:提升 文件描述符限制(ulimit -n),检查 磁盘 I/O(iostat) 与 网络带宽(iftop/nload)。
- 可观测性:接入 ELK/Grafana,设置 阈值告警,形成 常态化巡检 与 容量评估 机制。