問(wèn)題背景
服務(wù)器突然變慢、SSH 登錄卡頓、業(yè)務(wù)接口響應(yīng)時(shí)間上升——這些場(chǎng)景幾乎每個(gè)運(yùn)維工程師都遇到過(guò)。很多人的第一反應(yīng)是"負(fù)載太高了",然后跑去查 CPU、查進(jìn)程。但其實(shí)大多數(shù)人對(duì) Linux Load Average 的理解是模糊的——3 個(gè)數(shù)字到底什么意思?數(shù)值到多少算高?和 CPU 使用率是什么關(guān)系?為什么top顯示 CPU 使用率不高,但 Load Average 卻很高?
這些問(wèn)題的答案直接影響故障判斷的方向。如果把 Load Average 和 CPU 使用率混為一談,很可能會(huì)在排查時(shí)走錯(cuò)方向——明明是 IO 瓶頸,你卻盯著 CPU 不放。
這篇文章面向初中級(jí) Linux 運(yùn)維工程師,系統(tǒng)講解 Load Average 的計(jì)算機(jī)制、三個(gè)數(shù)字的真正含義、和 CPU/IO 的關(guān)系、以及在故障排查中的實(shí)際用法。文章內(nèi)容基于 Linux 4.x 及以上內(nèi)核,所有結(jié)論都可以通過(guò) Linux 自帶命令驗(yàn)證,不需要特殊工具。
核心概念:什么是 Load Average
1.1 教科書(shū)式的定義
Linux 的 Load Average 是在過(guò)去 1 分鐘、5 分鐘、15 分鐘內(nèi),系統(tǒng)中處于可運(yùn)行狀態(tài)(Running)和不可中斷等待狀態(tài)(Uninterruptible Sleep)的平均進(jìn)程數(shù)量。
這個(gè)定義里有幾個(gè)關(guān)鍵點(diǎn):
一、"可運(yùn)行狀態(tài)"(Running): 在 Linux 中,進(jìn)程狀態(tài)分為幾種。Running 狀態(tài)意味著進(jìn)程正在 CPU 上運(yùn)行,或者已經(jīng)準(zhǔn)備好等待 CPU 分配。這部分進(jìn)程會(huì)參與 Load Average 計(jì)算。
二、"不可中斷等待狀態(tài)"(Uninterruptible Sleep)": 這個(gè)狀態(tài)也叫 D 狀態(tài)(ps或top顯示為D),指進(jìn)程正在等待 IO 操作完成(磁盤(pán)、網(wǎng)絡(luò)等),而且這個(gè)等待是不可中斷的——信號(hào)無(wú)法打斷。比如進(jìn)程在等待磁盤(pán) IO 返回時(shí),會(huì)進(jìn)入 Uninterruptible Sleep。
這就是 Load Average 和 CPU 使用率最大的區(qū)別:CPU 使用率只統(tǒng)計(jì)正在使用 CPU 的進(jìn)程,而 Load Average 還包括那些在等待 IO 的進(jìn)程。這就是為什么有時(shí)候你看到 CPU 使用率只有 30%,但 Load Average 卻很高——大量進(jìn)程在等待磁盤(pán) IO。
**三、"平均"**: Load Average 不是瞬時(shí)值,而是過(guò)去一段時(shí)間的平均值。它用指數(shù)加權(quán)移動(dòng)平均算法計(jì)算,越近的數(shù)據(jù)權(quán)重越大,但歷史數(shù)據(jù)也有影響。這也是為什么它有 1 分鐘、5 分鐘、15 分鐘三個(gè)數(shù)字。
1.2 Load Average 的三個(gè)數(shù)字到底什么意思
執(zhí)行uptime或top,會(huì)看到類似這樣的輸出:
$ uptime 1032 up 45 days, 3:22, 2 users, load average: 3.52, 2.85, 2.60
三個(gè)數(shù)字的含義:
load average: 3.52, 2.85, 2.60
───── ───── ─────
1分鐘 5分鐘 15分鐘
3.52(1 分鐘):過(guò)去 1 分鐘系統(tǒng)的平均負(fù)載
2.85(5 分鐘):過(guò)去 5 分鐘系統(tǒng)的平均負(fù)載
2.60(15 分鐘):過(guò)去 15 分鐘系統(tǒng)的平均負(fù)載
數(shù)值本身的單位是"進(jìn)程數(shù)",不是百分比。3.52 意味著在過(guò)去 1 分鐘內(nèi),平均有 3.52 個(gè)進(jìn)程在 CPU 上運(yùn)行或等待 IO。
1.3 怎么判斷 Load Average 是否過(guò)高
網(wǎng)上流傳一個(gè)"經(jīng)驗(yàn)公式":Load Average 不應(yīng)該超過(guò) CPU 核心數(shù)。這個(gè)說(shuō)法只對(duì)了一半。
如果是純 CPU 密集型負(fù)載:Load Average 接近 CPU 核心數(shù)是正常的(比如 8 核 CPU,Load Average 在 8 左右)。
如果是 IO 密集型負(fù)載:Load Average 遠(yuǎn)高于 CPU 核心數(shù)是正常的(比如 8 核 CPU,Load Average 可能達(dá)到 50,但 CPU 使用率可能只有 20%)。
正確的判斷方式:
# 查看 CPU 核心數(shù) nproc # 或 grep"processor"/proc/cpuinfo | wc -l # 結(jié)合 Load Average 和 CPU 使用率一起看 uptime # 如果 Load Average > CPU 核心數(shù),且 top 顯示 CPU 使用率不高,說(shuō)明是 IO 瓶頸 # 如果 Load Average > CPU 核心數(shù),且 top 顯示 CPU 使用率也很高,說(shuō)明是 CPU 瓶頸 # 如果 Load Average < CPU 核心數(shù),且 CPU 使用率不高,說(shuō)明系統(tǒng)資源充裕
實(shí)際場(chǎng)景舉例:
場(chǎng)景一:8 核 CPU,Load Average = 2.5,CPU 使用率 = 20% 判斷:系統(tǒng)很輕松,幾乎沒(méi)有負(fù)載 場(chǎng)景二:8 核 CPU,Load Average = 12.0,CPU 使用率 = 15% 判斷:IO 瓶頸,大量進(jìn)程在等待磁盤(pán)或網(wǎng)絡(luò) IO 場(chǎng)景三:8 核 CPU,Load Average = 8.5,CPU 使用率 = 95% 判斷:CPU 瓶頸,進(jìn)程在排隊(duì)等 CPU 場(chǎng)景四:8 核 CPU,Load Average = 60.0,CPU 使用率 = 95% 判斷:同時(shí)有 CPU 和 IO 問(wèn)題,大量進(jìn)程在排隊(duì)
第二步:深入理解 Load Average 的計(jì)算機(jī)制
2.1 內(nèi)核如何計(jì)算 Load Average
Load Average 的計(jì)算邏輯在 Linux 內(nèi)核的kernel/sched/loadavg.c中,使用的是指數(shù)加權(quán)移動(dòng)平均(EWMA)算法:
load(t) = a * load(t-1) + (1-a) * n
其中:
load(t)是當(dāng)前時(shí)刻的 Load Average
load(t-1)是上一個(gè)計(jì)算周期的 Load Average
n是當(dāng)前活躍進(jìn)程數(shù)(Running + Uninterruptible Sleep)
a是衰減系數(shù),設(shè)置為exp(-5/60s)= 0.998
計(jì)算每 5 秒執(zhí)行一次,但報(bào)告給用戶空間是每 1 秒更新一次。
三個(gè)時(shí)間窗口的衰減系數(shù):
1 分鐘:a = exp(-5/60) = 0.9982 5 分鐘:a = exp(-5/300) = 0.9835 15 分鐘:a = exp(-5/900) = 0.9559
這就是為什么 1 分鐘的 Load Average 變化最快,15 分鐘的曲線最平滑。
2.2 /proc/loadavg 文件詳解
Load Average 的數(shù)據(jù)來(lái)源是/proc/loadavg文件:
cat /proc/loadavg # 輸出格式: # 3.52 2.85 2.60 4/1234 56789 # ───── ───── ───── ─────── ────── # 1分鐘 5分鐘 15分鐘 運(yùn)行/總進(jìn)程數(shù) 最后一個(gè)創(chuàng)建的進(jìn)程ID
/proc/loadavg的第四個(gè)字段4/1234:
斜杠前的數(shù)字(4)表示當(dāng)前 Running 狀態(tài)的進(jìn)程數(shù)
斜杠后的數(shù)字(1234)表示系統(tǒng)總進(jìn)程數(shù)(包括所有狀態(tài)的進(jìn)程)
第五個(gè)字段(56789)是 Linux 2.6 以后引入的,代表系統(tǒng)創(chuàng)建的最后一個(gè)進(jìn)程的 PID。這個(gè)數(shù)字持續(xù)增長(zhǎng)說(shuō)明系統(tǒng)在持續(xù)創(chuàng)建進(jìn)程(可能是短生命周期進(jìn)程)。
# 監(jiān)控這個(gè)數(shù)字的變化 watch -n 1'cat /proc/loadavg' # 如果 PID 數(shù)字增長(zhǎng)很快,說(shuō)明有進(jìn)程在不斷創(chuàng)建/銷毀(比如 PHP-FPM 頻繁重啟、某些定時(shí)任務(wù)有問(wèn)題)
2.3 Uninterruptible Sleep 到底是什么
Uninterruptible Sleep(D 狀態(tài)進(jìn)程)是理解 Load Average 的關(guān)鍵。它和普通 Sleep(狀態(tài) S)的區(qū)別:
S 狀態(tài)(Sleep):進(jìn)程在等待某個(gè)事件,比如 sleep(2)、等待鎖、等待 IO 完成。可以被信號(hào)中斷,收到信號(hào)后會(huì)立即喚醒。
D 狀態(tài)(Uninterruptible Sleep):進(jìn)程在等待硬件 IO 完成,不可被信號(hào)中斷。進(jìn)程會(huì)一直等待,直到 IO 操作返回。即使 kill -9 也無(wú)法殺死 D 狀態(tài)的進(jìn)程(只能等 IO 操作完成或超時(shí))。
D 狀態(tài)進(jìn)程的典型場(chǎng)景:
1. NFS 掛載后網(wǎng)絡(luò)斷開(kāi),進(jìn)程在等待 NFS IO 返回 2. 磁盤(pán) IO 非常嚴(yán)重,進(jìn)程在等待磁盤(pán)讀寫(xiě)完成 3. 僵尸進(jìn)程在等待子進(jìn)程退出(極少)
2.4 怎么查看 D 狀態(tài)進(jìn)程
# 方法一:top 命令
top
# 按 Shift + > 或 < 切換排序字段,找到 S 列(進(jìn)程狀態(tài))
# D 狀態(tài)的進(jìn)程會(huì)在 S 列顯示為 D
# 方法二:ps 命令
ps aux | awk?'$8 ~ /D/ {print}'
# 方法三:查找處于 D 狀態(tài)的進(jìn)程(- STAT 列包含 D)
ps aux | grep -E?'D|STAT'
# 方法四:直接查看 /proc//stat 中的進(jìn)程狀態(tài)碼
# 狀態(tài)碼在第 3 個(gè)字段(從 1 開(kāi)始計(jì)數(shù)),D=IO等待,R=運(yùn)行,S=睡眠
如果發(fā)現(xiàn)大量 D 狀態(tài)進(jìn)程,說(shuō)明系統(tǒng) IO 瓶頸嚴(yán)重。這個(gè)時(shí)候 Load Average 很高但 CPU 不高,排查方向應(yīng)該是磁盤(pán)和網(wǎng)絡(luò) IO,而不是 CPU。
第三步:Load Average 和 CPU 使用率的關(guān)系
3.1 top 命令中的 Load Average 和 CPU 信息
top -bn1 | head -5 # 輸出: # top - 1032 up 45 days, 3:22, 2 users, load average: 3.52, 2.85, 2.60 # Tasks: 1234 total, 4 running, 1230 sleeping, 0 stopped, 0 zombie # %Cpu(s): 15.2 us, 3.1 sy, 0.0 ni, 81.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
top 輸出的 CPU 各字段含義:
us: user space - 用戶空間進(jìn)程(應(yīng)用程序)使用的 CPU 時(shí)間 sy: system - 內(nèi)核空間使用的 CPU 時(shí)間 ni: nice - nice 值被調(diào)整過(guò)的用戶進(jìn)程使用的 CPU 時(shí)間 id: idle - CPU 空閑時(shí)間(最關(guān)鍵的指標(biāo)) wa: iowait - CPU 等待 IO 完成的時(shí)間(這是關(guān)鍵?。?hi: hardware interrupts - 硬件中斷 si: soft interrupts - 軟件中斷(網(wǎng)絡(luò)、調(diào)度等) st: stolen - 被虛擬化hypervisor偷走的時(shí)間(虛擬機(jī)場(chǎng)景)
81.7 id 和 Load Average 3.52 的關(guān)系:
CPU 空閑率 81.7% 意味著只有 18.3% 的 CPU 在工作
Load Average 3.52 意味著平均有 3.52 個(gè)進(jìn)程在等 CPU 或 IO
如果 CPU 核心數(shù)是 8,Load Average 3.52 小于核心數(shù),說(shuō)明 CPU 資源本身很充裕
但 Load Average 不為 0,說(shuō)明有進(jìn)程在等東西——如果是 IO 等的,CPU 使用率就不會(huì)高
3.2 %Cpu(s): wa (iowait) 才是關(guān)鍵
iowait(wa)是 Load Average 和 CPU 使用率分道揚(yáng)鑣的核心指標(biāo)。
iowait 表示 CPU 在等待 IO 操作完成的時(shí)間比例。如果 iowait 很高(超過(guò) 20%),說(shuō)明 CPU 大量的時(shí)間在等 IO,而不是在計(jì)算。
# 查看 iowait top -bn1 | grep -E'^%Cpu|^Cpu' # 或用 vmstat(更直觀) vmstat 1 5 # 輸出: # r b swpd free buff cache si so bi bo in cs us sy id wa st # 4 2 0 8000000 500000 10000000 0 0 0 0 100 200 10 5 80 5 0 # r: 運(yùn)行中的進(jìn)程數(shù)(相當(dāng)于 Load Average 1分鐘) # b: 不可中斷睡眠的進(jìn)程數(shù)(就是 Load Average 中計(jì)入的 D 狀態(tài)進(jìn)程) # wa: iowait
3.3 實(shí)戰(zhàn):分析一個(gè)高 Load Average 場(chǎng)景
假設(shè)uptime輸出如下:
load average: 12.5, 10.2, 8.0
同時(shí)top顯示:
%Cpu(s): 10.5 us, 2.1 sy, 0.0 ni, 45.0 id, 42.4 wa
CPU 核心數(shù):nproc = 8
分析:
Load Average 12.5 > CPU 核心數(shù) 8,說(shuō)明系統(tǒng)負(fù)載偏高
CPU 使用率 10.5% + 2.1% = 12.6%,iowait 42.4%,idle 45%
CPU 并不是瓶頸(只有 12.6% 在工作,45% 在 idle)
問(wèn)題在于 IO:iowait 42.4% 說(shuō)明大量進(jìn)程在等待 IO
Load Average 高的原因是大量進(jìn)程處于 D 狀態(tài)(Uninterruptible Sleep)
下一步排查:到底是哪種 IO 在拖慢系統(tǒng)
# 查看磁盤(pán) IO 統(tǒng)計(jì) iostat -x 1 5 # 重點(diǎn)關(guān)注: # %util: 磁盤(pán)IO使用率,如果 > 80% 說(shuō)明磁盤(pán)是瓶頸 # avgrq-sz: 平均請(qǐng)求大?。ㄉ葏^(qū)數(shù)) # avgqu-sz: 平均IO隊(duì)列長(zhǎng)度,如果 > 1 說(shuō)明IO隊(duì)列等待嚴(yán)重 # await: 平均等待時(shí)間(毫秒),如果 > 20ms 說(shuō)明IO很慢 # 查看哪個(gè)進(jìn)程在大量使用 IO iotop -oa # 或 pidstat -d 1 5 # 如果沒(méi)有 iotop,用 ps 輔助判斷 ps aux | awk'$8 ~ /D/ {print $0}'
第四步:高 Load Average 的完整排查流程
4.1 第一步:確認(rèn) Load Average 是否真的過(guò)高
# 查看 CPU 核心數(shù)和當(dāng)前 Load Average nproc uptime # 如果 Load Average < CPU 核心數(shù) * 0.7,問(wèn)題可能不嚴(yán)重 # 如果 Load Average > CPU 核心數(shù) * 2,繼續(xù)排查
4.2 第二步:確認(rèn)是 CPU 瓶頸還是 IO 瓶頸
# 查看 CPU 各指標(biāo) vmstat 1 5 # 判斷標(biāo)準(zhǔn): # - iowait (wa) > 20% 且 idle (id) > 40%:IO 瓶頸 # - iowait 低且 idle 低,us (user) 高:CPU 瓶頸 # - iowait 高且 idle 也低:CPU 和 IO 都有問(wèn)題
4.3 第三步:如果是 CPU 瓶頸,查找消耗 CPU 的進(jìn)程
# 查看 CPU 使用率最高的進(jìn)程(按 CPU 排序) ps aux --sort=-%cpu | head -20 # 或用 top(按 CPU 排序) top -bn1 -o %CPU | head -20 # 查看具體是哪些進(jìn)程的 CPU 使用率高 # 如果是某個(gè)業(yè)務(wù)進(jìn)程 CPU 使用率持續(xù) 100%,需要: # 1. 查看該進(jìn)程的線程數(shù) ps -eLf | grep| wc -l # 2. 查看該進(jìn)程的子進(jìn)程 pstree -p # 3. 分析是單線程慢還是多線程都在忙 # 4. 如果是 Java 進(jìn)程,看 GC 是否頻繁 # 5. 如果是 Python/Golang,看是否有死循環(huán)或計(jì)算密集任務(wù)
4.4 第四步:如果是 IO 瓶頸,查找消耗 IO 的進(jìn)程
# 用 iotop 查看 IO 占用最高的進(jìn)程 sudo iotop -oa # 如果沒(méi)有 iotop,用 pidstat sudo pidstat -d 1 5 # 查看具體是哪個(gè)磁盤(pán)在忙 iostat -x 1 3 # 查看進(jìn)程的 IO 統(tǒng)計(jì) cat /proc//io # rchar: 讀的總字節(jié)數(shù) # wchar: 寫(xiě)的總字節(jié)數(shù) # syscr: 讀系統(tǒng)調(diào)用次數(shù) # syscw: 寫(xiě)系統(tǒng)調(diào)用次數(shù) # read_bytes: 實(shí)際從磁盤(pán)讀的字節(jié)數(shù) # write_bytes: 實(shí)際寫(xiě)到磁盤(pán)的字節(jié)數(shù)
常見(jiàn) IO 瓶頸場(chǎng)景:
場(chǎng)景一:大量日志寫(xiě)入
# 查看誰(shuí)在寫(xiě)磁盤(pán) sudo iotop -oa | head -50 # 發(fā)現(xiàn)某個(gè) Python 進(jìn)程在持續(xù)寫(xiě)日志,寫(xiě)入速度 50MB/s # 查看該進(jìn)程的打開(kāi)文件 ls -la /proc//fd | grep -v socket | grep -v pipe # 發(fā)現(xiàn)寫(xiě)入了大量臨時(shí)文件 # 解決方案: # 1. 日志輪轉(zhuǎn)(logrotate) # 2. 異步寫(xiě)日志 # 3. 將日志寫(xiě)入 tmpfs(內(nèi)存文件系統(tǒng))再定期刷盤(pán)
場(chǎng)景二:Swap 使用導(dǎo)致 IO
# 查看 swap 使用 free -m swapon -s # 如果 Swap 已用 > 0,說(shuō)明物理內(nèi)存不足,系統(tǒng)在用磁盤(pán)做swap # 解決方案: # 1. 查看哪些進(jìn)程占用內(nèi)存最多 ps aux --sort=-%mem | head -10 # 2. 調(diào)整 OOM Killer 策略 # 3. 增加物理內(nèi)存 # 4. 限制進(jìn)程內(nèi)存使用(cgroup)
場(chǎng)景三:MySQL 大量磁盤(pán)順序?qū)?/p>
# 查看 MySQL 的 IO 模式 iostat -x 1 5 # 通常 MySQL 的 IO 是隨機(jī)讀寫(xiě)(InnoDB 臟頁(yè)刷新)和順序?qū)懀╞inlog) # 如果 MySQL IO 很高,考慮: # 1. 調(diào)整 innodb_flush_log_at_trx_commit(權(quán)衡安全性和性能) # 2. 使用電池供電的 RAID 卡(BBU)來(lái)緩存寫(xiě)操作 # 3. 將 binlog 和數(shù)據(jù)文件放在不同物理磁盤(pán) # 4. 調(diào)整 innodb_io_capacity 參數(shù)
4.5 第五步:排查 D 狀態(tài)進(jìn)程
# 查找所有 D 狀態(tài)的進(jìn)程
ps aux | awk'$8 ~ /D/ {print "PID:"$2" USER:"$1" CMD:"$11}'
# 查看某個(gè) D 狀態(tài)進(jìn)程的詳細(xì)信息
cat /proc//stack
# 這個(gè)文件顯示進(jìn)程當(dāng)前的內(nèi)核堆棧,可以知道進(jìn)程在等什么
# 查看 D 狀態(tài)進(jìn)程等待的 IO 設(shè)備
cat /proc//fd/* 2>/dev/null | head -20
# 或者查看進(jìn)程打開(kāi)的文件描述符
ls -la /proc//fd
# 如果某個(gè)文件描述符指向 /dev/sda1,說(shuō)明在等磁盤(pán) IO
第五步:不同場(chǎng)景的 Load Average 分析
5.1 場(chǎng)景一:Load Average 瞬間飆升
# 問(wèn)題:早上 10:00 突然告警 Load Average 從 2 飆升到 20,5 分鐘后恢復(fù) # 1. 查看具體是哪個(gè)時(shí)間點(diǎn) uptime # 10 Load Average 20.5, 12.3, 6.0 # 10 Load Average 8.2, 10.5, 6.5 # 2. 查看 1005 期間運(yùn)行了什么進(jìn)程 sudo ps -eo pid,lstart,cmd | grep"lstart"| awk'$2 " " $3 " " $4 >= "10:00" && $2 " " $3 " " $4 <= "10:05"' # 這個(gè)命令比較復(fù)雜,也可以用 sar 或 auditd # 3. 用 sar 查看 CPU 和 IO 歷史 sar -q 1 60 > /tmp/load.log # %usr: 用戶 CPU # %system: 系統(tǒng) CPU # %iowait: IO 等待 # 4. 常見(jiàn)原因: # - 定時(shí)任務(wù)(cron)同時(shí)啟動(dòng)了大量進(jìn)程 # - 備份腳本在執(zhí)行 # - 日志輪轉(zhuǎn)(logrotate)觸發(fā) # - 某個(gè)批處理任務(wù)啟動(dòng)
預(yù)防措施:錯(cuò)峰定時(shí)任務(wù),不要讓大量定時(shí)任務(wù)在同一分鐘啟動(dòng)。
5.2 場(chǎng)景二:Load Average 持續(xù)很高但 CPU 使用率不高
# 問(wèn)題:Load Average 持續(xù)在 30 左右,但 CPU 使用率只有 15%
# 診斷:
vmstat 1 5
# 查看 iowait 是否很高
# 查看 D 狀態(tài)進(jìn)程數(shù)量
ps aux | awk'$8 ~ /D/ {count++} END {print "D state processes:", count}'
# 如果 D 狀態(tài)進(jìn)程數(shù)量和 Load Average 接近,說(shuō)明 Load Average 主要是 IO 導(dǎo)致的
# 查看磁盤(pán) IO
iostat -x 1 3
常見(jiàn)根因:
NFS/CIFS 掛載后網(wǎng)絡(luò)或服務(wù)器響應(yīng)慢
大量進(jìn)程在等待數(shù)據(jù)庫(kù)磁盤(pán) IO
磁盤(pán)硬件故障或 RAID 卡緩存失效
大量進(jìn)程在等待虛擬化存儲(chǔ)(云服務(wù)器常見(jiàn))
5.3 場(chǎng)景三:Load Average 和 CPU 使用率都很高
# 問(wèn)題:Load Average 持續(xù) 15,CPU 使用率 90% # 診斷: top -bn1 # 確認(rèn)是哪個(gè)進(jìn)程占用了 CPU ps aux --sort=-%cpu | head -10 # 找到 CPU 占用最高的進(jìn)程 # 查看該進(jìn)程的詳細(xì)信息 pstree -p# 查看進(jìn)程樹(shù),看是否有大量子進(jìn)程 # 如果是 java 進(jìn)程 jstack # 查看 Java 進(jìn)程的線程堆棧 # 如果是 nginx/php-fpm ps -eLf | grep | wc -l # 查看 worker 進(jìn)程數(shù)
常見(jiàn)根因:
PHP-FPM 進(jìn)程數(shù)設(shè)置過(guò)多
Java 應(yīng)用出現(xiàn)死循環(huán)或計(jì)算密集任務(wù)
Python 腳本出現(xiàn) GIL 競(jìng)爭(zhēng)
被攻擊(如 CC 攻擊,導(dǎo)致大量請(qǐng)求)
第六步:監(jiān)控和告警配置
6.1 基于 Load Average 配置監(jiān)控告警
#!/bin/bash
# save as: check_load.sh
# 配置 cron: */5 * * * * /usr/local/bin/check_load.sh
THRESHOLD=$(nproc)
LOAD=$(awk'{print $1}'/proc/loadavg)
LOAD_INT=${LOAD%.*}
if["$LOAD_INT"-gt"$THRESHOLD"];then
echo"Alert: Load Average ($LOAD) > CPU cores ($THRESHOLD)"| tee -a /var/log/load_alert.log
# 這里接入告警:釘釘/企業(yè)微信/飛書(shū)/郵件
fi
6.2 用 Prometheus Node Exporter 采集 Load Average
Prometheus 的node_load*指標(biāo)可以采集 Load Average:
# Prometheus 配置中的 node_exporter job -job_name:node static_configs: -targets:['localhost:9100'] relabel_configs: -source_labels:[__address__] target_label:instance
查詢語(yǔ)句:
# 當(dāng)前 Load Average(1分鐘)
node_load1{instance="your-host"}
# 超過(guò) CPU 核心數(shù)的比例
node_load1 / count(node_cpu{instance="your-host"})
# 如果這個(gè)值 > 1,說(shuō)明 CPU 資源不足
告警規(guī)則:
# PrometheusRule
groups:
-name:node-load
rules:
-alert:NodeHighLoad
expr:node_load1/count(node_load1)>0.8
for:5m
labels:
severity:warning
annotations:
summary:"Node{{ $labels.instance }}load is high"
description:"Load Average 1m ={{ $value }}, CPU cores ={{ $labels.cpu }}"
-alert:NodeCriticalLoad
expr:node_load1/count(node_load1)>1.2
for:2m
labels:
severity:critical
第七步:Load Average 優(yōu)化實(shí)戰(zhàn)
7.1 CPU 瓶頸優(yōu)化
如果確認(rèn)是 CPU 瓶頸導(dǎo)致 Load Average 高:
# 1. 找到 CPU 消耗最高的進(jìn)程 ps aux --sort=-%cpu | head -20 # 2. 如果是業(yè)務(wù)進(jìn)程 # - 水平擴(kuò)展:增加進(jìn)程/容器數(shù)量 # - 垂直優(yōu)化:優(yōu)化算法、減少不必要的計(jì)算 # - 熱點(diǎn)代碼優(yōu)化:profiling 后針對(duì)性優(yōu)化 # 3. 如果是系統(tǒng)進(jìn)程 # - 檢查是否有大量中斷(cat /proc/interrupts) # - 檢查是否有大量上下文切換(vmstat 1,看 cs 列) # 上下文切換過(guò)多的排查: pidstat -w 1 5 # 如果某個(gè)進(jìn)程的 cswch/s(上下文切換次數(shù))非常高,說(shuō)明該進(jìn)程在頻繁被調(diào)度
7.2 IO 瓶頸優(yōu)化
如果確認(rèn)是 IO 瓶頸導(dǎo)致 Load Average 高:
# 1. 找到 IO 消耗最高的進(jìn)程 sudo iotop -oa # 2. 如果是大量小文件 IO # - 合并小文件寫(xiě)入 # - 使用 SSD # - 使用內(nèi)存文件系統(tǒng)(tmpfs)做緩沖 # 3. 如果是順序?qū)?IO # - 調(diào)整 IO 調(diào)度算法 cat /sys/block/sda/queue/scheduler # SSD 推薦:none (noop) # HDD 推薦:mq-deadline 或 bfq # 臨時(shí)修改(重啟失效): echonone | sudo tee /sys/block/sda/queue/scheduler # 永久修改:編輯 /etc/default/grub # GRUB_CMDLINE_LINUX="elevator=none" # 4. 如果是 Swap IO free -m # 如果 Swap 使用量持續(xù) > 0,說(shuō)明內(nèi)存不足 # 解決方案:增加內(nèi)存或限制進(jìn)程內(nèi)存
7.3 網(wǎng)絡(luò) IO 瓶頸
# 如果 Load Average 高但磁盤(pán) IO 不高,檢查網(wǎng)絡(luò) IO
sar -n DEV 1 5
# 查看各網(wǎng)卡的網(wǎng)絡(luò)流量
# 查看 TCP 連接數(shù)
netstat -an | awk'/^tcp/ {print $6}'| sort | uniq -c
# 如果有大量 TIME_WAIT 連接
netstat -an | awk'/^tcp/ {print $6}'| grep TIME_WAIT | wc -l
# 解決方案:
# - 開(kāi)啟 tcp_tw_reuse
# - 調(diào)整 tcp_max_tw_buckets
# - 縮短 TIME_WAIT 超時(shí)時(shí)間
總結(jié)
理解 Linux Load Average 的關(guān)鍵是:它不是 CPU 使用率,而是系統(tǒng)中"忙碌"進(jìn)程的數(shù)量。這個(gè)數(shù)量既包括正在使用 CPU 的進(jìn)程,也包括在等待 IO 的進(jìn)程。
Load Average 三個(gè)數(shù)字的含義:
1 分鐘:快速反映當(dāng)前負(fù)載變化
5 分鐘:中期趨勢(shì)
15 分鐘:長(zhǎng)期平穩(wěn)狀態(tài)
判斷高 Load Average 的正確方式:
數(shù)值 < CPU 核心數(shù):通常沒(méi)問(wèn)題
數(shù)值 > CPU 核心數(shù) × 0.7:需要關(guān)注
數(shù)值 > CPU 核心數(shù) × 2:嚴(yán)重問(wèn)題
和 CPU 使用率的關(guān)系:
Load Average 高 + CPU 使用率低 + iowait 高 =IO 瓶頸
Load Average 高 + CPU 使用率高 + iowait 低 =CPU 瓶頸
Load Average 低 + CPU 使用率高 = CPU 可能有尖峰,但系統(tǒng)總體不繁忙
排查口訣:
Load 高,先分清,CPU 瓶頸還是 IO。 top 看 CPU,iostat 看磁盤(pán),vmstat 里找 iowait。 D 狀態(tài)進(jìn)程是關(guān)鍵,內(nèi)核棧里找答案。 文件描述符查 IO,pidstat 找真兇。
記?。篖oad Average 是癥狀,不是原因。優(yōu)化 Load Average 不是目的,找到并解決真正的瓶頸(CPU、IO、網(wǎng)絡(luò)、內(nèi)存)才是目的。
-
負(fù)載
+關(guān)注
關(guān)注
2文章
677瀏覽量
36731 -
cpu
+關(guān)注
關(guān)注
68文章
11343瀏覽量
226045 -
Linux
+關(guān)注
關(guān)注
88文章
11829瀏覽量
219635
原文標(biāo)題:一文搞懂 Linux 系統(tǒng)負(fù)載 Load Average 到底怎么看
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
最慢Linux 計(jì)算機(jī)啟動(dòng)需要4小時(shí)!
Linux CPU負(fù)載率的計(jì)算方式
計(jì)算機(jī)操作系統(tǒng)的運(yùn)行機(jī)制和體系結(jié)構(gòu)
什么是計(jì)算機(jī)系統(tǒng)、計(jì)算機(jī)硬件和計(jì)算機(jī)軟件?
計(jì)算機(jī)及系統(tǒng)組成
什么是計(jì)算機(jī)操作系統(tǒng)?
計(jì)算機(jī)應(yīng)用基礎(chǔ)教案
計(jì)算機(jī)通信原理與系統(tǒng)_部分6
計(jì)算機(jī)通信原理與系統(tǒng)_部分4
計(jì)算機(jī)操作系統(tǒng)原理與設(shè)計(jì)
基于嵌入式Linux網(wǎng)絡(luò)計(jì)算機(jī)的操作系統(tǒng)的實(shí)現(xiàn)方法淺析
Linux系統(tǒng)負(fù)載Load Average的計(jì)算機(jī)制
評(píng)論