Linux進(jìn)程排查實(shí)戰(zhàn)之strace和lsof命令使用指南
服務(wù)起不來(lái),日志沒(méi)報(bào)錯(cuò)。進(jìn)程在跑,但就是不干活。
這種問(wèn)題最惡心,看日志看不出問(wèn)題,看監(jiān)控也沒(méi)異常。
這時(shí)候就需要strace和lsof這兩個(gè)神器了。
strace:跟蹤系統(tǒng)調(diào)用
strace能看到進(jìn)程在做什么系統(tǒng)調(diào)用,相當(dāng)于給進(jìn)程裝了個(gè)監(jiān)控?cái)z像頭。
基本用法
# 跟蹤一個(gè)命令 strace ls # 跟蹤正在運(yùn)行的進(jìn)程 strace -p <pid> # 跟蹤子進(jìn)程 strace -f -p <pid>
案例一:服務(wù)啟動(dòng)卡住
現(xiàn)象:Java服務(wù)啟動(dòng)后卡住,不打印任何日志。
# 找到進(jìn)程號(hào) ps aux | grep java # 假設(shè)是12345 # strace跟蹤 strace -p 12345
輸出:
futex(0x7f8a8c000000, FUTEX_WAIT_PRIVATE, 0, NULL
卡在futex,說(shuō)明在等鎖。
進(jìn)一步看是什么鎖:
strace -p 12345 -e trace=futex -T
結(jié)合jstack看線程棧:
jstack 12345 > thread.dump grep -A 20 "BLOCKED" thread.dump
發(fā)現(xiàn)是啟動(dòng)時(shí)連接數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)連不上,超時(shí)時(shí)間設(shè)太長(zhǎng)了。
案例二:文件讀寫(xiě)問(wèn)題
現(xiàn)象:服務(wù)很慢,但CPU和內(nèi)存都不高。
# 只看文件相關(guān)的調(diào)用 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
...
每次寫(xiě)日志都o(jì)pen-write-close,頻繁的文件操作導(dǎo)致性能差。
改成保持文件句柄打開(kāi),或者用異步日志。
案例三:網(wǎng)絡(luò)問(wèn)題
現(xiàn)象:服務(wù)偶爾超時(shí)。
# 只看網(wǎng)絡(luò)相關(guān) 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>
連接數(shù)據(jù)庫(kù)超時(shí)30秒,問(wèn)題找到了。
常用參數(shù)
# -f:跟蹤子進(jìn)程 strace -f -p 12345 # -T:顯示每個(gè)調(diào)用耗時(shí) strace -T -p 12345 # -t:顯示時(shí)間戳 strace -t -p 12345 # -c:統(tǒng)計(jì)系統(tǒng)調(diào)用次數(shù)和耗時(shí) strace -c -p 12345 # -o:輸出到文件 strace -o trace.log -p 12345 # 組合使用 strace -f -T -t -o trace.log -p 12345
統(tǒng)計(jì)分析
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
一眼就能看出時(shí)間花在哪了。
lsof:列出打開(kāi)的文件
Linux里一切皆文件,lsof能看到進(jìn)程打開(kāi)了什么文件、網(wǎng)絡(luò)連接、設(shè)備等。
基本用法
# 查看進(jìn)程打開(kāi)的所有文件 lsof -p <pid> # 查看某個(gè)文件被誰(shuí)打開(kāi) lsof /var/log/app.log # 查看某個(gè)端口 lsof -i :8080 # 查看某個(gè)用戶的所有打開(kāi)文件 lsof -u root
案例一:端口被占用
# 誰(shuí)占用了8080端口 lsof -i :8080
輸出:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 12345 root 123u IPv6 123456 0t0 TCP *:8080 (LISTEN)
進(jìn)程12345占用了8080端口。
案例二:文件句柄泄漏
現(xiàn)象:服務(wù)運(yùn)行一段時(shí)間后報(bào)"Too many open files"。
# 查看進(jìn)程打開(kāi)的文件數(shù)
lsof -p 12345 | wc -l
# 按文件類型分組統(tǒng)計(jì)
lsof -p 12345 | awk '{print $5}' | sort | uniq -c | sort -rn
輸出:
5000 IPv4
3000 REG
1000 DIR
5000個(gè)網(wǎng)絡(luò)連接?明顯有連接泄漏。
# 看看都連了誰(shuí) 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->10.0.0.2:3306 (ESTABLISHED)
java 12345 root 125u IPv4 123458 0t0 TCP 10.0.0.1:54323->10.0.0.2:3306 (ESTABLISHED)
...
全是連數(shù)據(jù)庫(kù)的,連接池用完沒(méi)歸還。
案例三:刪除的文件還在占用空間
# 查看已刪除但仍被引用的文件 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)
日志文件被刪了,但進(jìn)程還引用著,10G空間釋放不掉。
解決:重啟服務(wù),或者truncate文件:
# 找到文件描述符路徑 ls -l /proc/12345/fd/10 # 清空內(nèi)容但不關(guān)閉句柄 : > /proc/12345/fd/10
案例四:網(wǎng)絡(luò)連接分析
# 查看所有網(wǎng)絡(luò)連接
lsof -i
# 只看TCP
lsof -i tcp
# 只看某個(gè)狀態(tài)
lsof -i | grep ESTABLISHED
# 統(tǒng)計(jì)連接數(shù)
lsof -i | grep ESTABLISHED | wc -l
# 按目標(biāo)地址分組
lsof -i | grep ESTABLISHED | awk '{print $9}' | cut -d'>' -f2 | cut -d':' -f1 | sort | uniq -c | sort -rn
組合使用
排查思路
- 先用top/htop看整體
- 用ps看進(jìn)程狀態(tài)
- 用lsof看打開(kāi)了什么
- 用strace看在做什么
實(shí)戰(zhàn):服務(wù)假死排查
現(xiàn)象:服務(wù)進(jìn)程在,但不響應(yīng)請(qǐng)求。
# 1. 看進(jìn)程狀態(tài)
ps aux | grep java
# 狀態(tài)是Sl,正常
# 2. 看打開(kāi)的文件和連接
lsof -p 12345 | wc -l
# 8000+,有點(diǎn)多
# 3. 看網(wǎng)絡(luò)連接
lsof -p 12345 -i | grep -c ESTABLISHED
# 5000+,太多了
# 4. 看連接狀態(tài)分布
ss -tnp | grep 12345 | awk '{print $4}' | sort | uniq -c
# 大量CLOSE_WAIT
# 5. strace看在做什么
strace -p 12345 -e trace=network
# 卡在accept上,但新連接進(jìn)不來(lái)
根因:連接池滿了,CLOSE_WAIT狀態(tài)的連接沒(méi)有正確關(guān)閉。
實(shí)戰(zhàn):CPU 100%排查
# 1. top找到占用CPU的進(jìn)程 top -c # PID 12345 CPU 99% # 2. 看線程CPU使用 top -H -p 12345 # TID 12346 CPU 99% # 3. 把線程ID轉(zhuǎn)成16進(jìn)制 printf "%x\n" 12346 # 303a # 4. jstack看線程棧(Java) jstack 12345 | grep -A 30 "0x303a" # 5. 或者用strace看系統(tǒng)調(diào)用 strace -p 12346 -c
遠(yuǎn)程排查
有時(shí)候問(wèn)題機(jī)器在遠(yuǎn)程,需要登錄排查。
我們有幾臺(tái)服務(wù)器在不同機(jī)房,之前用跳板機(jī)一層層跳很麻煩。現(xiàn)在用星空組網(wǎng)把所有機(jī)器組到一起,直接SSH過(guò)去就能用strace、lsof排查,效率高多了。
常用命令速查
# strace速查 strace -p <pid> # 跟蹤進(jìn)程 strace -f -p <pid> # 跟蹤包括子進(jìn)程 strace -e trace=network -p <pid> # 只看網(wǎng)絡(luò) strace -e trace=file -p <pid> # 只看文件 strace -c -p <pid> # 統(tǒng)計(jì) strace -T -p <pid> # 顯示耗時(shí) # lsof速查 lsof -p <pid> # 進(jìn)程打開(kāi)的文件 lsof -i :<port> # 誰(shuí)占用端口 lsof -i tcp # 所有TCP連接 lsof +L1 # 已刪除但仍占用的文件 lsof -u <user> # 用戶打開(kāi)的文件
總結(jié)
| 工具 | 用途 | 典型場(chǎng)景 |
|---|---|---|
| strace | 跟蹤系統(tǒng)調(diào)用 | 卡死、慢、報(bào)錯(cuò)看不出原因 |
| lsof | 看打開(kāi)的文件/連接 | 端口占用、文件泄漏、連接泄漏 |
排查原則:
- 從宏觀到微觀
- 從現(xiàn)象到根因
- 不確定就多看幾遍
這兩個(gè)工具用熟了,大部分疑難雜癥都能查出來(lái)。
以上就是Linux進(jìn)程排查實(shí)戰(zhàn)之strace和lsof命令使用指南的詳細(xì)內(nèi)容,更多關(guān)于Linux strace和lsof命令的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
linux服務(wù)器中開(kāi)放端口實(shí)現(xiàn)過(guò)程
本文介紹了如何在Linux上使用firewall命令開(kāi)放端口,包括查看狀態(tài)、開(kāi)啟和關(guān)閉端口、添加和移除IP段規(guī)則、批量添加區(qū)間端口、開(kāi)放系統(tǒng)服務(wù)等操作2025-11-11
虛擬機(jī)安裝Linux rhel7.3操作系統(tǒng)(具體步驟)
這篇文章主要介紹了虛擬機(jī)安裝Linux rhel7.3操作系統(tǒng)(具體步驟),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
CentOS 7 在vmware中的網(wǎng)絡(luò)設(shè)置詳細(xì)介紹
這篇文章主要介紹了CentOS 7 在vmware中的網(wǎng)絡(luò)設(shè)置詳細(xì)介紹的相關(guān)資料,這里對(duì)主要網(wǎng)絡(luò)問(wèn)題進(jìn)行了一一介紹及如何解決,需要的朋友可以參考下2016-11-11
CentOS8.1搭建Gitlab服務(wù)器詳細(xì)教程
這篇文章主要介紹了CentOS8.1搭建Gitlab服務(wù)器詳細(xì)教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Linux系統(tǒng)非正常關(guān)機(jī)導(dǎo)致磁盤異常的問(wèn)題及解決
文章介紹了在VMware ESXi虛擬化環(huán)境中,由于斷電導(dǎo)致的Linux系統(tǒng)非正常關(guān)機(jī)和磁盤異常問(wèn)題及其解決方案,主要問(wèn)題包括文件系統(tǒng)損壞和報(bào)錯(cuò)信息,解決方案涉及檢查和修復(fù)`/etc/fstab`文件中的語(yǔ)法錯(cuò)誤,并使用`dmsetup`命令恢復(fù)設(shè)備映射2025-11-11

