strace分析Linux系统调用的实战指南
strace分析Linux系统调用的实战指南
说到Linux系统调试,strace绝对是个神器。我平时排查问题的时候,经常遇到这样的情况:程序莫名其妙地慢了,或者某个服务突然不工作了,但从日志里又看不出什么端倪。这时候strace就派上用场了,它能帮你看到程序到底在底层做了什么。
strace到底是什么?
简单来说,strace就是个"偷听器"。它能监听你的程序和Linux内核之间的所有对话。每当你的程序想要读个文件、写个网络包、分配点内存,都得通过系统调用跟内核沟通。strace就把这些对话全部记录下来,让你一目了然。
比如你运行一个简单的ls
命令:
strace ls
你会看到一大堆输出,像这样:
execve("/bin/ls", ["ls"], 0x7fff8b8e2220) = 0
openat(AT_FDCWD, "/lib64/ld-linux-x86-64.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0"..., 832) = 832
...
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
getdents64(3, /* 8 entries */, 32768) = 240
write(1, "file1.txt file2.txt README.md\n", 33) = 33
strace能帮你解决什么问题?
strace在这几个场景特别有用:
1. 程序启动异常或性能问题
有次遇到一个Java程序启动特别慢,通过strace发现它在某个配置文件上卡了很久:
strace -f -e trace=openat java -jar myapp.jar 2>&1 | grep -v ENOENT
结果发现程序在尝试读取几百个不存在的配置文件,每次都要等超时。
2. 文件操作问题
经常有人说"我的程序找不到文件",但又不知道具体在找什么。用strace一看就清楚了:
strace -e trace=openat,access ./myprogram
3. 网络连接问题
程序连不上数据库或者API?看看它到底往哪里连:
strace -e trace=connect,socket ./network_app
4. 内存和进程问题
程序内存泄漏或者创建了太多进程?
strace -e trace=mmap,munmap,clone,fork ./memory_app
实际案例:排查一个Web服务响应慢的问题
有次一个Web服务响应特别慢,但CPU和内存看起来都正常。我们用strace来排查:
# 先找到进程ID
ps aux | grep web_service
# 开始跟踪
strace -p 12345 -f -e trace=read,write,openat,close -o web_service.strace
通过分析strace输出,发现每次请求都会读取一个巨大的配置文件,而且还是重复读取。问题找到了!
但是这里有个问题,strace的输出实在太多了,几万行的输出看得头晕眼花。这时候就需要更好的工具来分析。
使用ctbots.com的可视化工具高效分析
直接看strace的原始输出真的很痛苦。我开发了 ctbots.com的strace在线分析工具,希望能解决类似的麻烦问题
工具地址:https://ctbots.com/zh/linux/performance/strace.html
数据收集
首先,我们需要收集strace数据。工具页面会给你生成标准的命令,我们按下不表,按照指引生成指令即可。
在线分析的优势
把strace日志上传到ctbots工具后,你能 检索strace日志了, 不用一点点搜索日志了。
问题排查的常见可疑点
自我总结,这几个地方最容易出问题:
文件系统相关
# 经常看到的问题模式
openat(AT_FDCWD, "/nonexistent/path/config.conf", O_RDONLY) = -1 ENOENT
# 程序在找不存在的配置文件
stat("/usr/share/locale/zh_CN/LC_MESSAGES/app.mo", {st_mode=S_IFREG|0644, st_size=45678, ...}) = 0
# 程序在反复读取语言文件,可能有缓存问题
网络连接问题
connect(3, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED
# 数据库连接被拒绝
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("8.8.8.8")}, 16) = -1 ETIMEDOUT
# 网络超时
内存分配异常
mmap(NULL, 1073741824, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM
# 程序想要分配1GB内存但失败了
进程创建问题
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1234567890) = -1 EAGAIN
# 系统无法创建新进程,可能进程数量达到限制
记住,strace是个强大的工具,但也要合理使用。在生产环境使用时要小心,因为它会影响程序性能。配合ctbots.com的在线分析工具,你就能事半功倍地解决各种奇怪问题了!