从日志入手定位并发瓶颈的思路
- 明确并发问题的典型症状:连接被拒绝或排队、线程耗尽、响应时间飙升、出现连接/线程类异常、CPU或GC异常。
- 准备三类关键日志与指标:
- 访问日志(记录请求频率、耗时、状态码),用于发现热点接口与慢请求;
- catalina.out 与 localhost 日志(记录线程池、连接、异常堆栈),用于发现线程阻塞、死锁、资源竞争;
- GC 日志与 JMX 指标(线程数、队列、连接数、GC 暂停),用于判断资源与垃圾回收压力。
- 建议在生产启用访问日志与GC 日志,并接入ELK/Graylog或Prometheus+Grafana做集中化与可视化,便于快速检索与告警。
关键日志与并发指标的对应关系
| 现象与日志线索 |
可能根因 |
快速验证 |
处置要点 |
| 访问日志中大量5xx/超时,且响应时间显著上升 |
线程池或后端资源饱和 |
对比线程池活跃数与队列长度 |
调整线程池与队列、优化慢请求 |
| catalina.out 出现**“too many open files”** |
文件描述符/连接数超限 |
查看系统 ulimit -n 与连接数 |
提升系统 fd 上限、优化连接复用 |
| 出现**“unable to create new native thread”** |
线程创建失败(资源/配置不足) |
检查线程数与内存 |
降低线程占用时长、优化线程配置 |
| 访问日志显示连接数激增、队列堆积 |
连接池或后端瓶颈 |
对比数据库/外部依赖连接数 |
调整连接池与超时、削峰限流 |
| GC 日志Full GC 频繁/停顿长 |
堆内存压力或对象生命周期问题 |
分析 GC 原因与对象分配 |
调整堆大小、优化代码与缓存策略 |
| 线程转储中大量线程BLOCKED或检测到deadlock |
锁竞争/死锁 |
jstack 多次采样定位阻塞链 |
减少锁粒度、避免嵌套锁、使用超时/尝试锁 |
上述线索与处置方向可结合访问日志、错误日志、GC 日志与 JMX 指标联动确认。
从日志到根因的排查步骤
- 采集与对齐时间线
- 同步抓取访问日志、catalina.out、GC 日志,确保时间一致;必要时开启访问日志耗时字段与MDC 请求ID,便于串联全链路。
- 访问日志定位“慢”和“热”
- 统计Top N 慢接口、错误率与峰值 QPS,找出并发压力下的长尾请求。
- 错误日志快速筛查
- 检索关键词:“too many open files”、“unable to create new native thread”、“timeout”、“deadlock”、**“pool exhausted”**等,优先处理可快速恢复的问题。
- 线程与连接瓶颈验证
- 通过 JMX 查看Catalina:type=ThreadPool,name="http-nio-8080"与Catalina:type=Executor,name="tomcatThreadPool"的currentThreadsBusy、maxThreads、acceptCount、queueSize;
- 使用jstack -l 抓取线程转储,关注RUNNABLE/BLOCKED/TIMED_WAITING比例与阻塞链;多次采样比对是否稳定复现。
- 外部依赖瓶颈排查
- 检查数据库连接池(如 maxActive/maxIdle)与慢 SQL;结合数据库监控(如 MySQL 的 SHOW STATUS)确认是否连接不足或锁等待。
- 资源与系统层检查
- 使用iostat观察磁盘 I/O、iftop/nload观察带宽,排除磁盘/网络成为并发瓶颈。
- 复现与回归
- 在测试环境以相同日志与指标复现问题,验证优化有效性后再上线。
常见并发问题与日志特征对照
- 线程饥饿/队列堆积:访问日志显示排队与超时,JMX 中currentThreadsBusy≈maxThreads且acceptCount用尽;线程转储可见大量线程在等待队列/后端。
- 死锁:catalina.out 或线程转储中出现**“Found one Java-level deadlock”**;堆栈中多个线程互相等待对方持有的锁。
- 连接/文件描述符耗尽:错误日志出现**“java.net.SocketException: Too many open files”;系统层面ulimit -n**偏低或连接未及时释放。
- 内存与 GC 压力:错误日志**“Java heap space”或 GC 日志Full GC 频繁/停顿长**;并发时响应抖动明显。
- 数据库/外部依赖瓶颈:访问日志慢请求集中在少数接口;数据库监控显示连接数打满/锁等待;线程转储多在JDBC/远程调用处阻塞。
配置与代码层面的优化建议
- 线程与连接器调优(server.xml)
- I/O 模型与协议
- 使用NIO/APR等异步非阻塞 I/O 提升并发处理能力。
- 连接池与超时
- 优化数据库连接池与外部依赖的最大连接数、超时;避免长事务与慢查询占用线程。
- 代码与锁优化
- 减少synchronized大块临界区,优先使用并发容器与ReadWriteLock/ReentrantLock;避免嵌套锁与不一致的加锁顺序,必要时使用tryLock与超时。
- 稳定性增强
- 启用GC 日志与必要的HeapDumpOnOutOfMemoryError;接入集中日志平台与监控告警,持续观察线程、队列、连接与 GC 指标。