应用启动卡了 30 秒、跑命令显示半天没动静、systemd 报 timeout —— 不知道
卡在哪步时,strace 能直接告诉你进程在做什么 syscall。
90% 的"卡"是某个 syscall 在等待:DNS / 网络连接 / 文件锁 / 互斥锁 /
fsync。
基本用法
# 跑一个新进程,观察所有 syscall
strace -f -tt -o /tmp/trace.log ./myapp
# attach 到正在运行的进程
strace -f -tt -p <PID> -o /tmp/trace.log
# Ctrl-C 停(被 attach 的进程继续跑)
关键参数:
-f:跟踪 fork 出来的子进程(多线程 / 多进程应用必选)-tt:每行加微秒时间戳(看延迟必备)-o file:写文件而不是混进 stdout-T:每个 syscall 的耗时(找慢调用神器)-e trace=...:只看某类 syscall
常见过滤:
# 只看网络相关
strace -f -e trace=network -p <PID>
# 只看文件 I/O
strace -f -e trace=file -p <PID>
# 只看慢的(> 100ms)
strace -f -T -p <PID> 2>&1 | awk '/<[0-9]+\.[0-9]+>/{
split($NF, a, "<|>"); if (a[2]+0 > 0.1) print
}'
案例 1:应用启动卡 30 秒
strace -f -tt -T -o /tmp/start.log ./myapp
# ... 30 秒后启动完成
sort -k1 /tmp/start.log | grep -E '\<[0-9]\.[0-9]+\>' | sort -k2 -t'<' -nr | head
或者直接看时间戳跳变:
awk '{print $1, $0}' /tmp/start.log | awk '
NR==1{prev=$1; next}
{
diff=$1-prev
if (diff > 1) print "*** gap " diff "s at " $0
prev=$1
}' /tmp/start.log
常见根因:
connect(... 192.168.x.x:53 ...)后 timeout 几秒 → DNS 配置错或者
resolv.conf 第一个 server 不可达openat(... /etc/...locked) = -1 EAGAIN反复重试 → 文件锁等其它进程futex(... FUTEX_WAIT ...)长时间不返回 → 库内部 mutex 死锁read(socket, ...)长时间阻塞 → 下游响应慢
案例 2:DNS 慢
strace -f -e trace=network -tt curl http://api.example.com/ 2>&1 | head -30
# 11:23:45.001 socket(AF_INET, SOCK_DGRAM, 0) = 5
# 11:23:45.002 connect(5, {sa_family=AF_INET, sin_addr=8.8.8.8, ...}, 16) = 0
# 11:23:45.003 sendto(5, ...) = 32 # DNS query
# 11:23:50.003 sendto(5, ...) = 32 # 5 秒后重试,第一次超时了
5 秒间隙说明第一个 nameserver 不响应。改 /etc/resolv.conf:
nameserver 1.1.1.1
nameserver 8.8.8.8
options timeout:1 attempts:2
timeout:1 把单次 DNS 超时从默认 5 秒降到 1 秒。
案例 3:找文件被打开了多少次
strace -f -e trace=openat -o /tmp/o.log ./myapp
grep -oE '"[^"]+"' /tmp/o.log | sort | uniq -c | sort -rn | head
# 832 "/etc/ld.so.cache"
# 412 "/usr/lib/x86_64-linux-gnu/libc.so.6"
# 158 "/proc/self/maps"
# ...
发现某个文件被 open 几百上千次 → 可能是配置文件没缓存、或者插件加载死循环。
strace vs ltrace vs perf
| 工具 | 看什么 | 典型场景 |
|---|---|---|
| strace | syscalls | I/O 慢、卡 syscall、文件路径错 |
| ltrace | 动态库函数调用 | 怀疑某个 libc 函数 / glib 函数行为 |
| perf | CPU 采样 | CPU 100% 找热点函数 |
| bpftrace | 几乎一切 | 复杂的内核态行为 |
性能影响
strace 会 大幅 拖慢被跟踪进程(每个 syscall 加上 ptrace 上下文切换)。
高并发服务上用 -e ... 严格限制范围,或者用 bpftrace 这种基于 eBPF
的"无停顿"工具。
高级:只在某行附近抓
# 进程已经卡 5 分钟了,attach 抓 30 秒
strace -f -tt -p <PID> -o /tmp/probe.log &
sleep 30
kill %1
踩过的坑
- 容器内可能没装 strace;
apt install strace在精简镜像装不上时,
从宿主nsenter进容器跑也行:
bash sudo nsenter -t <PID> -p -m -n strace -f -p <PID> - strace 输出的字符串默认截断 32 字符,要看完整路径加
-s 256。 - 多线程进程 attach 时
-f会顺带跟所有线程,量大可能淹掉日志,
缩小范围用-e trace=...。 - 不要在生产数据库上 attach strace —— 可能把 IO 慢到触发副节点切换 /
超时回滚。先看 perf / eBPF。
登录后参与评论。