开发者

Linux进程排查实战之strace和lsof命令使用指南

开发者 https://www.devze.com 2025-12-24 09:56 出处:网络 作者: 嘻哈baby
价值2999元 Java视频教程限时免费下载
专为Java开发者设计,涵盖核心技术、架构设计、性能优化等
立即下载
目录strace:跟踪系统调用基本用法案例一:服务启动卡住案例二:文件读写问题案例三:网络问题常用参数统计分析lsof:列出打开的文件基本用法案例一:端口被占用案例二:文件句柄泄漏案例三:删除的文件还在占用空间
目录
  • strace:跟踪系统调用
    • 基本用法
    • 案例一:服务启动卡住
    • 案例二:文件读写问题
    • 案例三:网络问题
    • 常用参数
    • 统计分析
  • lsof:列出打开的文件
    • 基本用法
    • 案例一:端口被占用
    • 案例二:文件句柄泄漏
    • 案例三:删除的文件还在占用空间
    • 案例四:网络连接分析
  • 组合使用
    • 排查思路
    • 实战:服务假死排查
    • 实战:CPU 100%排查
  • 远程排查
    • 常用命令速查
      • 总结

        服务起不来,日志没报错。进程在跑,但就是不干活。

        这种问题最恶心,看日志看不出问题,看监控也没异常。

        这时候就需要strace和lsof这两个神器了。

        strace:跟踪系统调用

        strace能看到进程在做什么系统调用,相当于给进程装了个监控摄像头。

        基本用法

        # 跟踪一个命令
        strace ls
        
        # 跟踪正在运行的进程
        strace -p <pid>
        
        # 跟踪子进程
        strace -f -p <pid>
        

        案例一:服务启动卡住

        现象:Java服务启动后卡住,不打印任何日志。

        # 找到进程号
        ps aux | grep java
        # 假设是12345
        
        # strace跟踪
        strace -p 12345
        

        输出:

        futex(0x7f8a8c000000, FUTEX_WAIT_PRIVATE, 0, NULL

        卡在futex,说明在等锁。

        进一步看是什么锁:

        strace -p 12345 -e trace=futex -T
        

        结合jstack看线程栈:

        jstack 12345 > thread.dump
        grep -A 20 "blockED" thread.dump
        

        发现是启动时连接数据库,数据库连不上,超时时间设太长了。

        案例二:文件读写问题

        现象:服务很慢,但CPU和内存都不高。

        # 只看文件相关的调用
        strace -p 12345 -e trace=file
        
        # 或者看所有IO
        strace -p 12345 -e trace=read,write,open,close
        

        输出:

        open("/data/logs/app.log", O_WRONLY|O_APPEND) = 3

        write(3, "2024-12-23 10:00:00 INFO...", 1024) = 1024

        close(3) = 0

        open("/data/logs/app.log", O_WRONLY|O_APPEND) = 3

        write(3, "2024-12-23 10:00:00 INFO...", 1024) = 1024

        close(3) = 0

        ...

        每次写日志都open-write-close,频繁的文件操作导致性能差。

        改成保持文件句柄打开,或者用异步日志。

        案例三:网络问题

        现象:服务偶尔超时。

        # 只看网络相关
        strace -p 12345 -e trace=network -T
        

        输出:

        connect(5, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("10.0.0.1")}, 16) = -1 ETIMEDOUT (Connection timed out) <30.001234>

        连接数据库超时30秒,问题找到了。

        常用参数

        # -f:跟踪子进程
        strace -f -p 12345
        
        # -T:显示每个调用耗时
        strace -T -p 12345
        
        # -t:显示时间戳
        strace -t -p 12345
        
        # -c:统计系统调用次数和耗时
        strace -c -p 12345
        
        # -o:输出到文件
        strace -o trace.log -p 12345
        
        # 组合使用
        strace -f -T -t -o trace.log -p 12345
        

        统计分析

        strace -c -p 12345
        

        输出:

        % time     seconds  usecs/call     calls    errors syscall

        ------ ----------- ----------- --------- --------- ----------------

         45.23    2.345678         234     10000           write

         30.12    1.234567        1234      1000           read

         20.11    0.987654          98     10000           futex

          4.54    0.234567          23     10000           clock_gettime

        ------ ----------- ----------- --------- --------- ----------------

        100.00    4.802466                 31000           total

        一眼就能看出时间花在哪了。

        lsof:列出打开的文件

        linux里一切皆文件,lsof能看到进程打开了什么文件、网络连接、设备等。

        基本用法

        # 查看进程打开的所有文件
        lsof -p <pid>
        
        # 查看某个文件被谁打开
        lsof /var/log/app.log
        
        # 查看某个端口
        lsof -i :8080
        
        # 查看某个用户的所有打开文件
        lsof -u root
        

        案例一:端口被占用

        # 谁占用了8080端口
        lsof -i :8080
        

        输出:

        COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

        java    12345 root  123u  IPv6 123456      0t0  TCP *:8080 (LISTEN)

        进程12345占用了8080端口。

        案例二:文件句柄泄漏

        现象:服务运行一段时间后报"Too many open files"。

        # 查看进程打开的文件数
        lsof -p 12345 | wc -l
        
        # 按文件类型分组统计
        lsof -p 12345 | awk '{print $5}' | sort | uniq -c | sort -rn
        

        输出:

        5000 IPv4

           3000 REG

           1000 DIR

        5000个网络连接?明显有连接泄漏。

        # 看看都连了谁
        lsof -p 12345 -i | head -20
        

        输出:

         COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME

        java    12345 root  123u  IPv4 123456      0t0  TCP 10.0.0.1:54321->10.0.0.2:3306 (ESTABLISHED)

        java    12345 root  124u  IPv4 123457      0t0  TCP 10.0.0.1:54322->10www.devze.com.0.0.2:3306 (ESTABLISHED)

        java    12345 root  125u  IPv4 123458      0t0  TCP 10.0.0.1:54323->10.0.0.2:3306 (ESTABLISHED)

        ...

        全是连数据库的,连接池用完没归还。

        案例三:删除的文件还在占用空间

        # 查看已删除但仍被引用的文件
        lsof +L1
        

        输出:

        COMMAND   PID USER   FD   TYPE DEVICE    SIZE/OFF NLINK  NODE NAME

        java    12345 root   10w   REG  253,1 10737418240     0 12345 /var/log/app.log (deleted)

        日志文件被删了,但进程还引用着,10G空间释放不掉。

        解决:重启服务,或者truncate文件:

        # 找到文件描述符路径
        ls -l /proc/12345/fd/10
        # 清空内容但不关闭句柄
        : > /proc/12345/fd/10
        

        案例四:网络连接分析

        # 查看所有网络连接
        lsof -i
        
        # 只看TCP
        lsof -i tcp
        
        # 只看某个状态
        lsof -i | grep ESTABLISHED
        
        # 统计连接数
        lsof -i | grep ESTABLISHED | wc -l
        
        # 按目标地址分组
        lsof -i | grep ESTABLISHED | awk '{print $9}' | cut -d'>' -f2 | cut -d':' -f1 | sort | uniq -c | sort -phprn
        

        组合使用

        排查思路

        • 先用top/htop看整体
        • 用ps看进程状态
        • 用lsof看打开了什么
        • 用strace看在做什么

        实战:服务假死排查

        现象:服务进程在,但不响应请求。

        # 1. 看进程状态
        ps aux | grep java
        # 状态是Sl,正常
        
        # 2. 看打开的文件和连接
        lsof -p 12345 | wc -l
        # 8000+js,有点多
        
        # 3. 看网络连接
        lsof -p 12345 -i | grep -c ESTABLISHED
        # 5000+,太多了
        
        # 4. 看连接状态分布
        ss -tnp | grep 12345 | awk '{print $4}' | sort | uniq -c
        # 大量CLOSE_WAIT
        
        # 5. strace看在做什么
        strace -p 12345 -e trace=network
        # 卡在accept上,但新连接进不来
        

        根因:连接池满了,CLOSE_WAIT状态的连接没有正确关闭。

        实战:CPU 100%排查

        # 1. top找到占用CPU的进程
        top -c
        # PID 12345 CPU 99%
        
        # 2. 看线程CPU使用
        top -H -p 12345
        # TID 12346 CPU 99%
        
        # 3. 把线程ID转成16进制
        printf "%x\n" 12346
        # 303a
        
        # 4. jstack看线程栈(Java)
        jstack 12345 |python grep -A 30 "0x303a"
        
        # 5. 或者用strace看系统调用
        strace -p 12346 -c
        

        远程排查

        有时候问题机器在远程,需要登录排查。

        我们有几台服务器在不同机房,之前用跳板机一层层跳很麻烦。现在用星空组网把所有机器组到一起,直接SSH过去就能用strace、lsof排查,效率高多了。

        常用命令速查

        # strace速查
        strace -p <pid>                    # 跟踪进程
        strace -f -p <pid>                 # 跟踪包括子进程
        strace -e trace=network -p <pid>   # 只看网络
        strace -e trace=file -p <pid>      # 只看文件
        strace -c -p <pid>                 # 统计
        strace -T -p <pid>                 # 显示耗时
        
        # lsof速查
        lsof -p <pid>                      # 进程打开的文件
        lsof -i :<port>                    # 谁占用端口
        lsof -i tcp                        # 所有TCP连接
        lsof www.devze.com+L1                           # 已删除但仍占用的文件
        lsof -u <user>                     # 用户打开的文件
        

        总结

        工具用途典型场景
        strace跟踪系统调用卡死、慢、报错看不出原因
        lsof看打开的文件/连接端口占用、文件泄漏、连接泄漏

        排查原则:

        • 从宏观到微观
        • 从现象到根因
        • 不确定就多看几遍

        这两个工具用熟了,大部分疑难杂症都能查出来。

        以上就是Linux进程排查实战之strace和lsof命令使用指南的详细内容,更多关于Linux strace和lsof命令的资料请关注编程客栈(www.devze.com)其它相关文章!

        0
        价值2999元 Java视频教程限时免费下载
        专为Java开发者设计,涵盖核心技术、架构设计、性能优化等
        立即下载

        精彩评论

        暂无评论...
        验证码 换一张
        取 消