strace -t 看不到“超时”字样,只显示耗时和返回值(如-1 etimedout),关键依据是末尾的是否接近配置的超时阈值。

strace 能直接看到系统调用级的超时行为,但必须配合 -T、-tt 和精准的 trace 过滤,否则会被海量输出淹没。
为什么 strace -T 看不到超时,只看到返回 -1?
系统调用超时(如 connect、epoll_wait、poll)在内核中是“阻塞等待 + 超时返回”的组合。strace 不会打印“超时”字样,只会显示调用耗时和返回值:-1 ETIMEDOUT 或 -1 EAGAIN。关键要看末尾的 <x.xxxs></x.xxxs> —— 如果这个时间接近你配置的超时阈值(比如 3.002s),基本就是它了。
-
epoll_wait(12, [], 512, 1000) = 0:设置 timeout=1000ms,但实际等了 1.002s 才返回,说明事件没来,已超时 -
connect(15, ..., 16) = -1 ETIMEDOUT:连接在 3 秒整附近失败,对应应用层 connect timeout 设置 - 注意:
read/write在非阻塞 fd 上可能返回-1 EAGAIN,不等于超时;只有阻塞 fd 上的长时间<x.xxxs></x.xxxs>才是真超时
如何精准捕获 Web 服务的网络超时调用?
Web 服务(Nginx、Apache、Gunicorn 等)常 fork 子进程或线程,且网络调用密集。盲目 strace -f 会产生巨量噪音,必须聚焦。
- 先用
pgrep -f nginx或systemctl show -p MainPID nginx拿到主 worker PID(不是 master) - 用
-e trace=network,io限定范围(network包含connect/accept/sendto/recvfrom;io包含read/write/poll/epoll_wait) - 加
-tt -T获取微秒时间戳和单次耗时,避免靠肉眼估算 - 生产环境慎用
-f:worker 进程频繁 fork 会导致输出爆炸,优先 attach 到单个 worker(如strace -tt -T -e trace=network,io -p 12345)
常见误判:把阻塞 I/O 当成超时
很多“卡住”的现象其实是正常阻塞,而非配置错误导致的超时。区分的关键是看耗时是否稳定、是否匹配预期。
- 数据库连接池空闲连接的
read可能阻塞数秒——这是连接保活心跳未触发前的正常等待,不是 bug -
epoll_wait返回= 0且耗时 ≈ timeout 参数值,属于设计行为,不是故障;只有当它反复出现且伴随业务 504 错误,才需调整 timeout 或后端响应速度 - 如果看到大量
read(3, ...)耗时 0.000xxx s 但频次极高(如每毫秒一次),更可能是日志/本地化文件反复加载(见 locale-archive 案例),和网络超时无关 - 用
-y参数可将 fd 数字还原为路径(如read(3/log/nginx/access.log>, ...)),快速排除磁盘 I/O 干扰
别忘了检查超时源头是否在用户态
strace 只能看到系统调用层,但 Web 服务的“超时”常常由用户态逻辑控制。例如:
- Nginx 的
proxy_read_timeout是在收到第一个字节后开始计时,strace 看不到这个 timer,只能看到后续recv是否因底层 socket 关闭而立即返回-1 ECONNRESET - Gunicorn 的
--timeout是 Python 层 signal.alarm 实现,strace 不会捕获 alarm 触发,但你能看到它 kill 掉 worker 前最后一条write或close - 真正要定位完整链路,得把 strace 输出和应用日志时间戳对齐(用
-tt微秒时间戳),再结合lsof -p PID看 fd 状态,否则容易在 kernel 和 userspace 之间来回猜











