- 僵尸進程 / 孤兒進程:是什么、為什么會出現、如何定位與清理
- 進程優先級:nice/priority、CFS 與實時調度、I/O 優先級、cgroup 限流
/proc
文件系統:最常用路徑與診斷手法- CRC 校驗:在存儲/網絡里的作用與局限、抓包“校驗錯誤”的常見誤解
- “網絡溢出”問題:從網卡環形緩沖到 socket 緩沖的全鏈路掉包/擁塞定位與調優
僵尸進程、孤兒進程、進程優先級、/proc 文件系統、CRC 與網絡溢出問題處理(實戰 + 原理)
一、僵尸進程(Zombie)與孤兒進程(Orphan)
1. 僵尸進程是什么?
- 子進程已經退出,但父進程還沒調用
wait()/waitpid()
回收退出狀態 ? 子進程殘留一條進程表項(Z
狀態)。 - 占用極少內核資源,但PID 槽位被占著;大量僵尸會耗盡 PID 導致新進程創建失敗。
如何發現
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/ {print}'
top # STAT 列出現 Z
如何處理
- 優先修父進程:讓它正確調用
wait()
(或設置SIGCHLD
、SA_NOCLDWAIT
)。 - 若父進程異常:重啟父進程或把僵尸“托孤”給
systemd
/init
(殺父進程,PID 1 會回收它的子進程)。
# 找僵尸的父進程
ps -o ppid= -p <ZOMBIE_PID>
# 溫和重啟父進程或 kill -TERM 父進程
注意:不能直接 kill 僵尸,它已經“死了”;要么讓父進程回收,要么讓 PID 1 接管回收。
2. 孤兒進程是什么?
- 父進程先退出,子進程仍在運行。
- 子進程會被
systemd
/init
收養,不等于有問題。 - 僅當孤兒進程無人管理、占資源或失控時需要處理。
排查要點
# 看某進程的父進程是否為 1(systemd)
ps -o ppid= -p <PID>
# 如果該孤兒進程異常占用資源,按常規排障或干預
二、進程優先級:CPU/I/O 調度的“方向盤”
1. CPU 調度基礎
- CFS(Completely Fair Scheduler):Linux 默認調度器,面向一般任務,盡量“公平”分配 CPU 時間。
- 實時調度:
SCHED_FIFO
/SCHED_RR
,優先級高于 CFS,用于低延遲關鍵任務(謹慎使用)。
2. nice 與 priority
- nice 值:-20(最高優先)… 19(最低)。影響 CFS 分配權重。
- 修改方式
nice -n -5 myjob # 以更高優先級啟動
renice -n 10 -p <PID> # 運行中調整
3. 實時優先級(慎用)
chrt -f -p 50 <PID> # FIFO 50
chrt -r -p 20 <PID> # RR 20
風險:錯誤配置可能餓死系統(其它任務拿不到 CPU)。務必設置合理的 CPU 限額或 watchdog。
4. I/O 優先級(磁盤競爭場景)
ionice -c2 -n0 -p <PID> # best-effort 最高
ionice -c3 -p <PID> # idle,只在空閑 I/O 時執行
5. cgroups(建議的企業做法)
- 對服務設置CPU/內存/IO配額與權重,避免互相“打架”:
# systemd 單元示例
# /etc/systemd/system/my.service.d/limits.conf
[Service]
CPUQuota=200% # 最多用兩核
IOSchedulingClass=best-effort
CPUSchedulingPolicy=other
三、/proc
文件系統:內核的“實時體檢報告”
/proc
是內核導出的偽文件系統,映射當前系統與進程的內核狀態。
1. 與進程相關
/proc/<PID>/status # 內存/權限/狀態
/proc/<PID>/stat # 原始統計
/proc/<PID>/cmdline # 啟動參數
/proc/<PID>/fd/ # 打開的文件描述符
/proc/<PID>/stack # 內核棧(需權限)
/proc/<PID>/limits # 資源限制
快速定位 FD 泄漏/熱點文件:
ls -l /proc/<PID>/fd | head
lsof -p <PID> | head
2. 系統級常用
/proc/cpuinfo # CPU 信息
/proc/meminfo # 內存
/proc/uptime # 運行時長
/proc/loadavg # 負載
/proc/interrupts # 硬中斷分布(NUMA/隊列調優參考)
/proc/softirqs # 軟中斷(網絡/塊設備熱點)
/proc/slabinfo # 內核對象分配情況
/proc/net/snmp # TCP/UDP 統計(包錯/丟棄)
/proc/net/netstat # ListenOverflows/ListenDrops 等關鍵指標
/proc/sys/net/* # sysctl 網絡內核參數(讀寫)
示例:觀測 TCP 監聽溢出
grep -wE 'ListenOverflows|ListenDrops' /proc/net/netstat
四、CRC 校驗:能“發現問題”,不能“證明安全”
1. CRC 是什么?
- 循環冗余校驗:根據數據多項式計算一個固定長度校驗值(如 CRC32),用于錯誤檢測(傳輸/存儲)。
- 網絡中:以太網幀尾部有 FCS(CRC32);IP/TCP/UDP 也有各自的校驗(非 CRC)。
- 存儲/壓縮工具也常用 CRC(例如 ZIP 內部 CRC32)。
重要:CRC ≠ 加密/簽名
- CRC 只能發現“偶然錯誤”,不能防篡改(對抗性修改很容易撞同 CRC)。
2. 計算/校驗舉例
# 命令行:POSIX cksum(CRC32 變體)
cksum file.bin# Python:zlib CRC32
python - <<'PY'
import zlib, sys
b = open(sys.argv[1],'rb').read()
print(hex(zlib.crc32(b) & 0xffffffff))
PY file.bin
3. 抓包里“校驗錯誤”的常見誤解
- 用
tcpdump/wireshark
在發送端看到 “bad checksum” 多半是網卡硬件下 offload(TSO/GSO/CSO)導致:
數據在內核里尚未填好校驗,交給網卡再補,抓包截的是未修正的中間態。 - 驗證方法:在接收端抓包,或臨時關閉 offload 對比(僅測試用):
sudo ethtool -K eth0 tx off rx off gso off gro off tso off
測完記得恢復;關閉 offload 會影響性能。
五、“網絡溢出”問題:全鏈路掉包/擁塞定位與調優
“溢出”常見于隊列/緩沖寫滿:網卡環形緩沖、內核隊列、協議棧 backlog、socket 緩沖、應用處理能力不足。下面按層排查。
1) 物理/網卡層
現象:dropped
/missed
增長,rx_no_buffer
,環形緩沖溢出。
怎么查
ip -s link show dev eth0 # RX/TX 丟包/錯誤
ethtool -S eth0 | egrep 'rx_|tx_|drop|miss|err' | sed 's/^/ /'
dmesg | egrep -i 'NETDEV WATCHDOG|link is down|reset'
怎么調
- 增大網卡環形緩沖(視驅動支持):
sudo ethtool -G eth0 rx 4096 tx 4096
- 開啟/微調 RSS(多隊列收包)、IRQ 親和性(按 CPU 核分配中斷):
# irqbalance 開啟;或手動寫 /proc/irq/*/smp_affinity
- 調整網卡中斷合并(coalesce),在延遲與吞吐間折中:
ethtool -C eth0 rx-usecs 25 rx-frames 64
2) 協議棧入口隊列
指標:net.core.netdev_max_backlog
、/proc/net/softnet_stat
中的 dropped
。
調優
sysctl -w net.core.netdev_max_backlog=4096
# RPS/RFS:讓軟中斷負載更均勻
echo ffffffff > /sys/class/net/eth0/queues/rx-0/rps_cpus
3) 傳輸層隊列(TCP/UDP)
UDP 溢出:netstat -su
→ packet receive errors
/ RcvbufErrors
TCP 監聽溢出:/proc/net/netstat
→ ListenOverflows/ListenDrops
調優
# socket backlog:應用 listen(backlog) 的上限(全局)
sysctl -w net.core.somaxconn=4096# SYN 隊列
sysctl -w net.ipv4.tcp_max_syn_backlog=4096
sysctl -w net.ipv4.tcp_synack_retries=3# TCP 緩沖自動調諧范圍
sysctl -w net.ipv4.tcp_rmem='4096 87380 67108864'
sysctl -w net.ipv4.tcp_wmem='4096 65536 67108864'# UDP 全局內存池(慎調,觀察內存)
sysctl -w net.ipv4.udp_mem='196608 262144 393216'
4) 進程 socket 緩沖 & 應用層
現象:應用來不及讀/寫,send()
/recv()
阻塞或丟包(UDP)。
定位
ss -s # 匯總
ss -ant state established # 看隊列、擁塞狀態
pidstat -w 1 # 上下文切換,是否線程太多
perf top # CPU 熱點
優化
- 提高單進程 socket 緩沖上限:
sysctl -w net.core.rmem_max=134217728
sysctl -w net.core.wmem_max=134217728
-
應用層:
- 多進程/多實例 + SO_REUSEPORT 分擔單棧瓶頸
- 異步 I/O(epoll/io_uring),減少線程上下文切換
- 限流/背壓:丟棄低價值請求或降級
- 批處理:聚合寫、零拷貝(
sendfile
、splice
)
5) 例:高并發 UDP 采集丟包
-
觀測:
netstat -su
的RcvbufErrors
快速增長 -
解決:
- 提高
rmem_max
/rmem_default
與應用SO_RCVBUF
- 開
RSS
、調netdev_max_backlog
- 多進程 +
SO_REUSEPORT
- 落盤/解碼放到后臺線程,前端線程只負責收包入隊
- 提高
六、排障清單(可直接照著跑)
僵尸/孤兒
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/ {print}' # 找僵尸
ps -o ppid= -p <PID> # 查父進程
優先級/限流
renice -n 10 -p <PID>
ionice -c2 -n0 -p <PID>
chrt -f -p 20 <PID>
/proc 快速定位
cat /proc/loadavg /proc/meminfo | head
grep -wE 'ListenOverflows|ListenDrops' /proc/net/netstat
grep -E 'CPU|NET' /proc/interrupts
CRC/抓包
cksum file.bin
ethtool -K eth0 tx off rx off # 僅測試,抓“真實”校驗
網絡溢出
ip -s link show dev eth0
ethtool -S eth0 | egrep 'drop|err|miss'
cat /proc/net/softnet_stat | awk '{print $2,$3,$4}' | head
netstat -su; netstat -s | grep -i listen
sysctl -a | egrep 'somaxconn|max_syn_backlog|netdev_max_backlog'
七、最佳實踐與避坑
- 優先“修邏輯,再調內核”:先確認應用是否過載/阻塞/鎖爭用。
- 小步快跑:sysctl/ethtool 逐項修改、記錄前后指標;避免“一把梭”。
- cgroups 限流:比單純 renice 更穩;服務化部署綁定 systemd 單元。
- 僵尸成因修在“父進程”:添加
wait()
、信號處理或使用正確的進程管理框架。 - CRC 不是安全手段:完整性校驗用 SHA-256/HMAC,安全性用 TLS/簽名。
- 抓包“壞校驗”先想 offload:對照接收端;不要誤判。
- 記錄基線:平時保留
/proc/net/*
、ethtool -S
、系統負載的健康快照,事發能對比。
結語
這套知識覆蓋了進程生命周期(僵尸/孤兒)、調度與優先級(CPU/I/O/實時與 cgroup)、內核觀測入口(/proc)、以及數據可靠性與網絡韌性(CRC 與溢出治理)的“地基”。
真正的生產環境里,觀察—定位—緩解—根因—固化是閉環:先穩住現場,再補齊架構與自動化,把問題關進歷史。