strace 网络与超时类系统调用过滤实战
更新时间:2026-09-19。基础用法见 strace,按系统调用统计耗时见 strace -c。这篇专注一类高频问题:「连不上 / 连接慢 / 请求卡住超时」时,怎么用 strace 看到底卡在哪一次系统调用。
一、最常用的跟踪组合
bash
# 只看网络相关系统调用,带时间戳和单次耗时,跟线程
strace -f -tt -T -e trace=network -p <pid>
# 聚焦连接建立(找「卡在 connect/DNS」)
strace -f -tt -T -e trace=connect,socket,getsockopt -p <pid>
# 跟踪所有「可能阻塞等待」的调用(连接慢、卡死最常用)
strace -f -tt -T -e trace=connect,poll,ppoll,select,pselect6,epoll_wait,futex,read,recvfrom -p <pid>
# 统计模式:哪类系统调用最耗时
strace -f -c -p <pid> # 跑一会 Ctrl+C,按时间排序| 选项 | 作用 |
|---|---|
-f | 跟踪子进程/线程(网络库常另起线程,必须加) |
-tt | 每行精确到微秒的绝对时间 |
-T | 行尾显示该次系统调用实际耗时(<…>),定位卡顿关键 |
-e trace=... | 只看指定类别/调用,降噪 |
-e status=failed | 只看失败的调用(快速找错误码) |
-s 200 | 打印更长的数据内容 |
二、连接建立过程怎么读
一次典型的 TCP 连接在 strace 里是:
bash
socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("10.0.0.9")}, 16)
= -1 EINPROGRESS (Operation now in progress) # 非阻塞连接:正常,后续靠 poll 等结果
poll([{fd=5, events=POLLOUT}], 1, 5000) = 1 ([{fd=5, revents=POLLOUT}]) <0.003124>
getsockopt(5, SOL_SOCKET, SO_ERROR, ...) = 0 # 0 = 连接成功判读关键在 poll 那行的 <耗时>:
<0.003>很快返回 + SO_ERROR=0:连接正常。- poll 一直等到接近超时值才返回,之后 SO_ERROR 是
ETIMEDOUT/EHOSTUNREACH:网络不通/对端无响应(对应连接超时),重点查网络、防火墙 DROP、路由。 - connect 立即返回
ECONNREFUSED:对端可达但端口没监听/被 REJECT(连接被拒绝),查服务进程和端口。 EINPROGRESS本身不是错误:非阻塞 socket 都这样,必须看后续 poll/getsockopt,不要看到它就误判。
三、DNS 解析慢:别只盯 connect
「数据库连接慢 2 秒」常常不是数据库问题,而是域名解析:
bash
strace -f -tt -T -e trace=openat,connect,sendto,recvfrom,poll -p <pid>会看到向 DNS 服务器(53 端口)的 sendto/recvfrom,若第一个 nameserver 要等到超时(5s)才回退第二个,卡顿就在这里。处理:检查 /etc/resolv.conf、options timeout/attempts、本地 hosts、连接池配置(直连 IP)。
四、请求卡住:分清是等网络、等锁还是等调度
bash
# 情况 A:等网络 IO
epoll_wait(3, ..., 1000) = -1 EINTR ... 或长时间阻塞在 poll/recvfrom <2.001>
→ 在等对端响应或网络,结合 ss 看重传/RTT:[ss 深入](/tools/network/ss-retrans-rtt-buffer-tuning.md)
# 情况 B:等锁/条件变量
futex(0x7f..., FUTEX_WAIT_BITLOCK..., 0, {5, 0}) = -1 ETIMEDOUT <5.000>
→ 线程在等另一线程持有的锁/唤醒(死锁或持锁线程卡住),结合 [jstack](/tools/code/jstack-thread-dump-analyze.md) 看线程栈
# 情况 C:阻塞在 read 管道/磁盘
read(fd, ... <0.8>) 大量出现
→ 等磁盘/子进程输出,看 [iostat](/quickstart/iostat.md)/[vmstat wa](/tools/proc/vmstat-si-so-context-switches.md)-T行尾耗时最大的那类调用,通常就是卡顿根因;先-c统计几秒拿到大类,再精确-e trace=复现细节。- 对 futex 长时间等待,strace 只能告诉你「在等地址」,进一步要线程栈(jstack/gdb)看持有者在干什么。
五、定位流程清单
bash
1) -c 统计几秒:时间主要花在 connect / poll / futex / 哪类?
2) connect 方向 → 看是 ECONNREFUSED(服务没起)还是 poll 超时 ETIMEDOUT(网络不通)
3) 先有 53 端口 sendto 长等待 → DNS 解析问题
4) poll/epoll_wait/recvfrom 长等待 → 等网络对端,ss 看重传 RTT、tcpdump 看包
5) futex 长等待 → 锁/线程协调问题,上 jstack/gdb
6) 大量 read/openat 慢 → 磁盘/配置反复读取,上 iostat抓包对照见 tcpdump 抓 HTTP/gRPC,服务超时/重试设计见 gRPC keepalive。
坑
- 不加
-f,连接实际在工作线程里发生,主线程什么都看不到。 - 把非阻塞连接的 EINPROGRESS 当错误,忽略后续 poll/SO_ERROR。
- 只看错误码不看
-T耗时,无法发现「没报错但每次等 2 秒」的超时。 - DNS 慢被误判为下游服务慢。
- 在高并发生产全程 attach,ptrace 会显著拖慢目标,只在复现窗口短时跟踪。
总结
排查网络与超时类问题时,用 strace -f -tt -T -e trace=network/poll/futex 跟踪连接并重点看行尾耗时:非阻塞 connect 返回 EINPROGRESS 属正常、需看随后 poll 与 SO_ERROR,SO_ERROR 为 ETIMEDOUT 且 poll 等到超时是网络不通,立即 ECONNREFUSED 是端口无监听;卡在 53 端口是 DNS 解析慢,卡在 poll/recvfrom 是等网络对端,卡在 futex 是等锁需配合 jstack。先用 -c 统计出耗时最大的系统调用类再精确复现,并短时 attach 以控制生产开销。