用 strace 排查应用启动卡死 / 慢

应用启动卡了 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。
精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。