服务器接口超时如何定位程序或服务器问题
学完这篇,你能按一套固定的排查顺序,把「接口超时」从客户端、网关、应用、依赖、系统资源逐层剥开,最后判断问题到底出在程序还是服务器。
第一步:在客户端复现,拿到耗时分解
这一步要拿到一次真实超时的耗时分布,做完你就知道是网络慢、连接慢,还是服务端处理慢。
用 curl 打同一接口,加 -w 输出各阶段耗时(curl 7.63 以上都支持):
curl -o /dev/null -s -w "dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} total:%{time_total}\n" https://api.example.com/v1/order
判读规则:connect 大说明 TCP 握手慢(网络或服务器 backlog 满);ttfb 大而 connect 小,说明请求已到服务端但服务端处理慢;全阶段都大,先查客户端出口网络。
注意:不要只看浏览器 F12 里那条红色 timeout 就下结论,浏览器会把重试、排队都算进去,curl 的单次数据更干净。
第二步:确认请求有没有到达服务端
这一步要在服务端日志里找到这次请求,做完就能区分「请求根本没进来」还是「进来了但没返回」。
先看 Nginx access log(Nginx 1.24 默认路径 /var/log/nginx/access.log):
tail -f /var/log/nginx/access.log | grep "/v1/order"
确认日志格式里带了耗时字段,在 http {} 中配置:
log_format timed '$remote_addr $request_uri $request_time $upstream_response_time $upstream_addr $upstream_status';
$request_time 是 Nginx 收到的总耗时,$upstream_response_time 是后端返回耗时。如果 request_time 大而上游耗时小,瓶颈在 Nginx 到客户端之间;如果上游耗时大,继续往下查应用。
注意:应用日志一定要打印一个 trace id,并且让 Nginx 通过
proxy_set_header X-Request-Id $request_id;透传,否则跨服务根本串不起来。
第三步:判断是线程/连接池耗尽,还是依赖慢
这一步要确认应用内部是不是卡在等资源,做完能判断是程序配置问题还是下游拖累。
Java 应用先打线程栈(JDK 8 及以上自带 jstack):
jstack -l 12345 > /tmp/jstack.txt
grep -c "java.lang.Thread.State: WAITING" /tmp/jstack.txt
如果大量线程 WAITING 在 HikariPool.getConnection,说明数据库连接池不够,调 spring.datasource.hikari.maximum-pool-size;如果卡在 HTTP 客户端读超时,说明下游接口慢。
数据库侧登录 MySQL 后执行:
SHOW FULL PROCESSLIST;
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW()) - TIME_TO_SEC(trx_started) > 10;
看有没有执行超过 10 秒的长事务锁住行。
第四步:查服务器资源瓶颈
这一步看机器本身有没有到极限,做完能排除 CPU、内存、磁盘、连接数四类问题。
top -H -p 12345 # 看进程内哪个线程吃 CPU
iostat -x 1 5 # 看 %util 是否接近 100
vmstat 1 5 # 看 si/so 是否有 swap 交换
ss -s # 看 TIME_WAIT 和总连接数
如果 CPU 不高、磁盘不高,但接口就是慢,八成在等锁、等下游或者等 DNS。
注意:
top里看到一个线程 CPU 100%,用printf "%x\n" <线程ID>转成十六进制,再去 jstack 里搜nid=0x...,才能定位到具体代码行。
第五步:核对全链路超时参数,写结论
这一步把每一层超时时间对一遍,做完就能给出「谁先超时、谁该改」的结论。
按调用方向依次检查:客户端 SDK、Nginx(proxy_connect_timeout、proxy_read_timeout、proxy_send_timeout)、网关、应用内 HTTP 客户端(Feign 的 feign.client.config.default.readTimeout)、JDBC(socketTimeout)、下游服务。原则是外层超时必须大于内层,否则会出现外层先断开、内层还在跑的浪费。
如果用阿里云 SLB,登录控制台走「负载均衡 > 实例 > 监控」,看 UpstreamResponseTime 和 StatusCode 曲线,能直接看出是哪段时间后端变慢。
最后写一句结论,例如:「应用线程池被下游订单接口拖满,P99 从 200ms 涨到 8s,属于依赖服务问题,不是本机资源问题」。
小结
- 先用 curl 拆耗时,分清网络慢还是服务端慢。
- 用 Nginx
$request_time与$upstream_response_time判断瓶颈在网关还是应用。 - 用 jstack 和数据库会话表区分连接池耗尽、锁等待、下游慢。
- 用 top、iostat、vmstat、ss 排除 CPU、磁盘、内存、连接数四类资源问题。
- 全链路超时参数必须由外到内逐层放大,结论要落到「哪一层、哪个依赖、什么时间点」。
原文链接:https://www.gj0.com/thread-1181.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。