外观
strace / ltrace:看进程在等什么
进程"卡住"但日志没输出、CPU 不高、连接也没断——这时要知道它卡在哪个系统调用上。strace 是唯一能直接给出答案的工具。
场景
- 应用启动卡住,没有任何日志。
- 请求超时,但不知道卡在 DNS、连接、还是读数据。
- 文件"打不开",但权限看着没问题。
一、attach 到运行中的进程
bash
strace -p 28441text
strace: Process 28441 attached
futex(0x7f2c1e9a2b40, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, FUTEX_BITSET_MATCH_ANY) = 0
epoll_wait(42, [{EPOLLIN, {u32=183, u64=183}}], 1024, 1000) = 1
read(45, "\x16\x03\x03\x01\x2b", 16384) = 5
write(46, "HTTP/1.1 200 OK\r\n", 17) = 17读法:进程阻塞在某个调用上不动(比如一直 futex、read 没返回),那就是卡点。
按 Ctrl+C 脱离,进程不受影响(Ctrl+Z 才会让它停)。
attach 需要权限
普通用户只能 attach 自己的进程。attach 别人的进程要 root,或者满足 ptrace_scope 的规则:
bash
cat /proc/sys/kernel/yama/ptrace_scope值为 1 时只能 attach 子进程。临时放开(重启失效):
bash
echo 0 > /proc/sys/kernel/yama/ptrace_scope二、按类别过滤
strace 默认输出所有调用,量非常大。用 -e trace= 过滤:
bash
# 文件相关(启动卡住最常用)
strace -p 28441 -e trace=file
# 网络相关
strace -p 28441 -e trace=network
# 指定具体调用
strace -p 28441 -e trace=openat,read,write,close
# 排除某些
strace -p 28441 -e trace=!futex,epoll_waitfile 等价于 openat,stat,access,readlink,... 一整组。查"到底在找哪个配置文件"特别有效:
bash
strace -f -e trace=openat ./app 2>&1 | grep -v ENOENT | head -20text
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/opt/app/config/application.yml", O_RDONLY) = 4= -1 ENOENT 表示文件不存在。Java 启动时会有大量 ENOENT(类路径扫描),属正常,别被吓到。
三、看耗时
bash
strace -p 28441 -T -e trace=networktext
connect(7, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("10.0.0.32")}, 16) = 0 <0.000214>
sendto(7, "\x2f\x00\x00\x00\x03SELECT 1", 15, 0, NULL, 0) = 15 <0.000018>
recvfrom(7, "\x07\x00\x00\x01", 16384, 0, NULL, NULL) = 7 <2.014211><2.014211> 是这次调用花了 2.01 秒。recvfrom 花了 2 秒,说明在等数据库响应。
-T 是单次调用耗时,-tt 是绝对时间戳,两个常一起用:
bash
strace -tt -T -p 28441 -e trace=networktext
22:20:11.114221 connect(7, {...}, 16) = 0 <0.000214>
22:20:11.114402 sendto(7, "...", 15, 0) = 15 <0.000018>
22:20:13.128613 recvfrom(7, "...", 16384, 0) = 7 <2.014211>四、-y:显示文件描述符对应的路径
bash
strace -y -p 28441 -e trace=read,writetext
read(45</etc/nginx/nginx.conf>, "user nginx;\n", 4096) = 13
write(46</var/log/app/app.log>, "started\n", 8) = 8不加 -y 只会显示 read(45, ...),你还得去 /proc/28441/fd/45 查它是什么。-y 能省大量时间。
五、-c:统计各调用
bash
strace -c -f -p 28441text
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
78.42 4.213004 421300 10 epoll_wait
12.11 0.650881 81 8021 read
5.02 0.269441 33 8102 write
2.34 0.125772 15 8401 futex
------ ----------- ----------- --------- --------- ----------------
100.00 5.372210 24612 total看两列:% time 和 errors。
- 某个调用占比特别高 → 瓶颈在这里。
errors特别多 → 在反复重试(比如connect大量ECONNREFUSED)。
六、常用排查模板
启动卡住
bash
strace -f -tt -T -o /tmp/start.trace /opt/app/bin/start.sh
tail -50 /tmp/start.trace看最后几行卡在哪个调用。常见:
| 卡在 | 原因 |
|---|---|
connect 无返回 | 网络不通(防火墙 DROP,不是 REJECT) |
read 无返回 | 对端没发数据 |
openat 大量 ENOENT 后极慢 | 在遍历不存在的路径(配置错) |
futex 长时间 | 等锁(死锁或线程池耗尽) |
poll/epoll_wait | 正常空闲,不是卡住 |
请求超时
bash
# 先确认是不是在等网络
strace -f -p $(pgrep -f app.jar | head -1) -e trace=network -T -tt如果看到 connect 直接 EINPROGRESS 然后超时,是 TCP 层不通;如果 sendto 成功但 recvfrom 超时,是下游处理慢。
文件打不开
bash
strace -e trace=openat,access -y ./app 2>&1 | grep -E 'ENOENT|EACCES'text
openat(AT_FDCWD, "/opt/app/conf/app.yml", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/data/app/logs", O_WRONLY|O_CREAT, 0644) = -1 EACCES (Permission denied)ENOENT 是路径错,EACCES 是权限问题——比应用日志里的"配置文件加载失败"精确得多。
七、ltrace:看库函数调用
bash
ltrace -p 28441
ltrace -c -p 28441text
malloc(4096) = 0x55d3c1e2a010
strcmp("prod", "prod") = 0
snprintf("/data/app/logs/app.log", 256, "%s/%s.log", "/data/app/logs", "app") = 24ltrace 拦的是动态库函数(libc 的 malloc、strcmp、snprintf)。用途比 strace 窄,主要是:
- 确认某个库函数被调用了。
- 看参数(比如
snprintf拼出来的路径对不对)。
对 Java 这类自己管理内存的程序,ltrace 帮助不大。
八、性能影响
strace 会让被跟踪进程慢几十倍,因为每次系统调用都要陷入内核两次。
text
正常 QPS 5000 → strace 后 80不要长时间在生产上 strace 高流量进程
两个后果:
- 应用直接超时。
strace输出文件能几分钟写满磁盘。
正确做法:
bash
# 限定时间
timeout 10 strace -f -p 28441 -e trace=network -T -o /tmp/t.trace
# 限定类别
strace -e trace=connect -p 28441
# 写到 tmpfs
strace -o /dev/shm/t.trace ...九、和 perf / bpftrace 的分工
| 工具 | 看什么 | 开销 |
|---|---|---|
strace | 具体某次系统调用的参数和耗时 | 高 |
perf top/trace | 函数级 CPU 分布 | 中 |
bpftrace | 自定义探针,聚合统计 | 低 |
strace 适合"单个进程卡住"的定性排查;要看"整体哪个函数最热"用 perf;要长期低开销观测用 bpftrace。
十、踩过的坑
| 现象 | 根因 | 处置 |
|---|---|---|
strace: attach: ptrace(PTRACE_ATTACH...): Operation not permitted | 权限/ptrace_scope | 用 root,或调 ptrace_scope |
| 输出刷屏,找不到重点 | 没加 -e trace= | 按类别过滤 |
| 找不到 fd 对应文件 | 没加 -y | 加 -y |
| 进程被 strace 拖死 | 系统调用太频繁 | timeout 5 限时 |
-c 统计里 futex 占比高 | 等锁 | 结合 jstack/perf 看锁竞争 |
| Java 进程没有有用的库调用 | JIT 后不经过 libc 调用点 | 用 perf/async-profiler |
| 输出的字符串被截断 | 默认 -s 32 | -s 200 |