定位 Tomcat 中的慢请求(slow request)日志,可以从日志配置、访问日志、请求耗时统计、线程堆栈等多个层面入手。下面按“由浅入深”的方式说明。
Tomcat 默认使用 AccessLogValve 记录每次请求。
在 conf/server.xml 中:
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b %D" />
重点关注:
%D:请求处理时间(毫秒)%r:请求行(方法 + URI)%t:时间示例日志:
127.0.0.1 - - [10/Oct/2024:10:00:00 +0800] "GET /api/list HTTP/1.1" 200 1024 3500
表示 /api/list 耗时 3500ms
awk '$NF > 1000' logs/localhost_access_log.*.txt
找出 >1s 的请求。
RequestDumperValve(调试用)<Valve className="org.apache.catalina.valves.RequestDumperValve" />
会打印完整请求信息,但性能影响大,不建议生产。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
long cost = System.currentTimeMillis() - (Long) request.getAttribute("startTime");
if (cost > 1000) {
log.warn("Slow request: {} {} cost={}ms", request.getMethod(), request.getRequestURI(), cost);
}
}
如果慢请求频繁,但日志看不出原因:
jstack <tomcat_pid> > thread.log
grep -A 30 "http-nio" thread.log
常见现象:
WAITING on database connectionBLOCKED on synchronizedSocket read → 外部接口慢trace com.xxx.controller.ApiController list
| 现象 | 可能原因 |
|---|---|
| 偶发慢 | GC、锁竞争 |
| 固定接口慢 | SQL、外部调用 |
| 全部变慢 | 线程池满、CPU、DB |
| 凌晨慢 | 备份、定时任务 |
✅ 最小成本方案:
开启
%D访问日志 + 阈值过滤
✅ 生产推荐:
应用层慢请求日志 + APM
如果你愿意,可以告诉我:
我可以给你更精确的配置示例。