線上 CPU 飆高最怕兩件事:一是盯著top看了半小時,最后還是不知道是誰打滿了核;二是誤把負(fù)載高當(dāng)成 CPU 高,處理動作做反了,越處理越抖。生產(chǎn)環(huán)境里,CPU 問題通常不是單一指標(biāo)異常,而是一條完整鏈路:業(yè)務(wù)請求放大、線程模型失控、內(nèi)核軟中斷堆積、磁盤或網(wǎng)絡(luò)抖動把 CPU 拖進系統(tǒng)態(tài),最后體現(xiàn)在告警平臺上只剩一行“CPU usage > 90%”。
我自己排這類故障時,不會一上來就改參數(shù),也不會先重啟服務(wù)。第一步永遠是把現(xiàn)場固定住,先判斷是整機 CPU 打滿、單進程熱點、線程級死循環(huán)、內(nèi)核態(tài)消耗,還是虛擬化層 steal time。判斷對了,后面的命令基本就是順著證據(jù)走。
一、概述
1.1 背景介紹
Linux 服務(wù)器 CPU 飆高,常見表現(xiàn)有三類:
監(jiān)控中CPU usage連續(xù) 5 分鐘超過 85%,業(yè)務(wù) RT 明顯抬升
load average飆升,但應(yīng)用日志沒有大量報錯,看起來像“無聲故障”
單臺機器異常,重啟后短時間恢復(fù),過一陣又復(fù)發(fā)
這類問題本質(zhì)上是在回答四個問題:
CPU 時間消耗在用戶態(tài)還是內(nèi)核態(tài)
是哪個進程、哪個線程、哪段調(diào)用棧在吃 CPU
是業(yè)務(wù)代碼導(dǎo)致,還是網(wǎng)絡(luò)、中斷、磁盤、容器配額把 CPU 頂上去
現(xiàn)場止血之后,怎么避免再次發(fā)生
1.2 技術(shù)特點
分層排查:先看整機,再看進程,再看線程,再看調(diào)用棧,避免在錯誤層級浪費時間
證據(jù)驅(qū)動:每一步都保留命令輸出、時間點和 PID,復(fù)盤時能回放故障過程
兼容生產(chǎn)環(huán)境:優(yōu)先使用低侵入命令,只有在證據(jù)不足時才上perf、strace這類更重的工具
1.3 適用場景
電商、支付、營銷活動高峰期間,某臺業(yè)務(wù)機 CPU 持續(xù) 90% 以上
Java、Go、Python 服務(wù) RT 抬升,容器副本正常但單 Pod 熱點明顯
Nginx、網(wǎng)關(guān)、日志采集節(jié)點出現(xiàn)高系統(tǒng)態(tài) CPU,懷疑是軟中斷或連接風(fēng)暴
1.4 環(huán)境要求
| 組件 | 版本要求 | 說明 |
|---|---|---|
| 操作系統(tǒng) | CentOS 7/8、Rocky Linux 8/9、Ubuntu 20.04+ | 文中命令以主流生產(chǎn)發(fā)行版為準(zhǔn) |
| 診斷工具 | procps-ng 、sysstat、perf、strace、lsof | sysstat 提供sar/mpstat/pidstat,perf用于熱點采樣 |
| 硬件配置 | 4 vCPU / 8 GB 內(nèi)存起 | 低于該配置時 CPU 抖動更明顯,結(jié)論要結(jié)合負(fù)載模型看 |
| 監(jiān)控體系 | Prometheus + Node Exporter 或等價方案 | 用于回放故障窗口和設(shè)置閾值 |
二、詳細(xì)步驟
2.1 準(zhǔn)備工作
2.1.1 系統(tǒng)檢查
先確認(rèn)這臺機器是不是真的在燒 CPU,而不是負(fù)載高、IO 卡頓或虛擬機被宿主機搶占。第一輪命令我通常固定成下面這一組:
date hostname -f uptime w top -b -n 1 | head -20 mpstat -P ALL 1 3 vmstat 1 5 sar -u 1 5 sar -q 1 5 free -h df -h dmesg -T | tail -50
這組命令重點看下面幾個指標(biāo):
%usr:用戶態(tài) CPU,高了通常先看應(yīng)用進程或線程熱點
%sys:系統(tǒng)態(tài) CPU,高了先看網(wǎng)絡(luò)、磁盤、中斷、內(nèi)核路徑
%iowait:高了不一定是 CPU 問題,很多人會誤判
%steal:云主機上很關(guān)鍵,高了說明宿主機在搶 CPU
run queue:vmstat中的r持續(xù)大于 CPU 核數(shù),說明調(diào)度壓力明顯
load average:只說明等待隊列變長,不等于 CPU 一定打滿
如果現(xiàn)場還沒裝診斷工具,先補齊:
# Debian / Ubuntu sudo apt update sudo apt install -y sysstat linux-tools-common linux-tools-generic strace lsof iotop dstat tcpdump linux-cpupower # RHEL / CentOS / Rocky / AlmaLinux sudo yum install -y sysstat perf strace lsof iotop dstat tcpdump kernel-tools
生產(chǎn)環(huán)境里建議把sysstat常駐打開,不要等出事了才發(fā)現(xiàn)機器上沒有sar歷史數(shù)據(jù)。
2.1.2 固定現(xiàn)場
CPU 問題最容易丟現(xiàn)場,尤其是應(yīng)用被自動拉起、容器自動重建或者值班同學(xué)順手重啟服務(wù)。先把關(guān)鍵現(xiàn)場落盤:
sudo mkdir -p /var/log/cpu-hotspot/$(date +%F_%H%M%S)
SNAPSHOT_DIR=$(ls -dt /var/log/cpu-hotspot/* | head -1)
top -b -n 1 >"${SNAPSHOT_DIR}/top.txt"
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head -50 >"${SNAPSHOT_DIR}/ps_top_cpu.txt"
mpstat -P ALL 1 5 >"${SNAPSHOT_DIR}/mpstat.txt"
pidstat -u -r -d -h 1 5 >"${SNAPSHOT_DIR}/pidstat.txt"
vmstat 1 5 >"${SNAPSHOT_DIR}/vmstat.txt"
sar -u 1 5 >"${SNAPSHOT_DIR}/sar_u.txt"
sar -n DEV 1 5 >"${SNAPSHOT_DIR}/sar_net.txt"
sar -d 1 5 >"${SNAPSHOT_DIR}/sar_disk.txt"
dmesg -T | tail -200 >"${SNAPSHOT_DIR}/dmesg_tail.txt"
如果是容器環(huán)境,再補一組 cgroup 和 kubelet 側(cè)信息:
kubectl top pod -A --containers | sort -k3 -hr | head -20 kubectl describe pod-n crictl stats cat /sys/fs/cgroup/cpu.max 2>/dev/null || cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us cat /sys/fs/cgroup/cpu.stat 2>/dev/null || cat /sys/fs/cgroup/cpu/cpu.stat
這里最容易踩坑的是:容器里看到 CPU 100%,但那是**單核 100%**,不是整機 100%。如果 Pod 只給了500m,應(yīng)用被節(jié)流后一樣會表現(xiàn)成 RT 飆升。
2.2 核心排查步驟
2.2.1 先判斷是整機問題還是單進程問題
先看全局,再看個體:
mpstat -P ALL 1 3 ps -eo pid,user,ni,pri,psr,stat,%cpu,%mem,etime,cmd --sort=-%cpu | head -30 pidstat -u -p ALL 1 5
判斷原則我一般這么定:
所有核心都高,且多個業(yè)務(wù)進程都在跑:優(yōu)先看流量、批處理、宿主機爭搶、全局中斷
只有 1-2 個核心高:大概率是單線程熱點、鎖競爭、自旋或綁核不均
整機 CPU 不高,單進程 CPU 很高:直接進線程級定位
整機%sys高、進程視角又不明顯:轉(zhuǎn)到中斷、網(wǎng)絡(luò)棧、磁盤 IO 路徑
業(yè)務(wù)止血時,不要急著kill -9。先確認(rèn)是不是可以摘流:
# 例如在負(fù)載均衡層先摘掉異常節(jié)點 curl -s http://127.0.0.1:9090/healthz sudo ipvsadm -Ln sudo ss -s
如果節(jié)點還能響應(yīng),優(yōu)先在網(wǎng)關(guān)或注冊中心把實例摘掉,再做深度取證。
2.2.2 區(qū)分用戶態(tài) CPU 和系統(tǒng)態(tài) CPU
這一刀必須切清楚,不然會把應(yīng)用問題排到內(nèi)核層,或者把中斷風(fēng)暴排到業(yè)務(wù)線程。
top -b -n 1 | head -10 mpstat -P ALL 1 5 sar -u ALL 1 5
經(jīng)驗上可以這樣理解:
%usr + %nice高:代碼熱點、死循環(huán)、頻繁 JSON 編解碼、正則、GC、壓縮解壓
%sys高:系統(tǒng)調(diào)用密集、網(wǎng)絡(luò)包處理、軟中斷、磁盤路徑、連接風(fēng)暴
%soft高:網(wǎng)絡(luò)包小包過多、連接突發(fā)、iptables/conntrack 壓力
%irq高:硬件中斷、網(wǎng)卡隊列、某些存儲控制器異常
%steal高:不是你機器的問題,先找云平臺或宿主機資源爭搶
如果%sys明顯高,繼續(xù)執(zhí)行:
cat /proc/softirqs cat /proc/interrupts sar -n DEV,EDEV 1 5 ethtool -S eth0 | egrep'drop|miss|error|timeout'
如果%usr高,直接進入進程和線程熱點定位。
2.2.3 進程級定位:誰在吃 CPU
先把 top 進程抓出來,再看生命周期和啟動參數(shù):
ps -eo pid,ppid,lstart,etime,pcpu,pmem,cmd --sort=-pcpu | head -20 pidstat -u -t -p1 5 cat /proc/ /status cat /proc/ /limits lsof -p | head -50
幾個實戰(zhàn)判斷點:
新拉起的進程 CPU 高:通常和新版本發(fā)布、配置變更、緩存未熱有關(guān)
運行幾天后的進程 CPU 高:更多見于線程泄漏、連接泄漏、任務(wù)堆積、GC 退化
只有某個工作線程高:優(yōu)先抓線程棧,不要先抓完整堆 dump,太重
Java 進程排查可以直接把高 CPU 線程映射到十六進制線程號:
top -H -pprintf'0x%x ' jstack | less
Go 進程建議先看pprof:
curl -s http://127.0.0.1:6060/debug/pprof/profile?seconds=30 -o cpu.pprof go tool pprof -top cpu.pprof
Python 進程如果 CPU 很高,先看是不是純 Python 死循環(huán)、JSON 序列化過重,或者多進程 worker 數(shù)配大了:
top -H -pstrace -p -tt -T -f -o /tmp/python.strace -c
2.2.4 線程級定位:哪個線程、哪段棧在熱
線程級定位是 CPU 問題里最有價值的一步,很多線上問題在這里就能定性。
top -H -pps -Lp -o pid,tid,psr,pcpu,stat,comm --sort=-pcpu | head -20 pidstat -t -p 1 5
常見現(xiàn)象和結(jié)論:
某個線程固定占滿 100% 單核:典型死循環(huán)、自旋鎖、空輪詢
多個線程同時高:并發(fā)打滿、線程池放大、熱點 key 或批任務(wù)沖擊
線程 CPU 高且上下文切換也高:可能是鎖競爭、頻繁喚醒、線程數(shù)過多
繼續(xù)往下抓熱點時,優(yōu)先用perf,比strace更適合 CPU 分析:
sudo perf top -p-g sudo perf record -F 99 -p -g -- sleep 30 sudo perf report --stdio | head -80
perf的使用原則:
采樣 15-30 秒通常夠了,時間太長會把短期熱點沖淡
線上優(yōu)先-F 99或-F 49,不要把采樣頻率拉太高
perf top適合現(xiàn)場判斷,perf record/report適合留證據(jù)
如果內(nèi)核限制了perf_event_paranoid,臨時調(diào)整前先評估權(quán)限:
sysctl kernel.perf_event_paranoid sudo sysctl -w kernel.perf_event_paranoid=1
改完記得回收,別把調(diào)試口子常駐留在生產(chǎn)機上。
2.2.5 系統(tǒng)態(tài) CPU 高:重點盯中斷、網(wǎng)絡(luò)和磁盤
系統(tǒng)態(tài)高最容易出現(xiàn)“應(yīng)用沒問題,但機器已經(jīng)快扛不住”的情況。排查順序建議固定:
看網(wǎng)卡收發(fā)和丟包
看軟中斷分布
看連接狀態(tài)和 backlog
看磁盤隊列和 IO 等待
看內(nèi)核日志有沒有網(wǎng)卡、驅(qū)動、文件系統(tǒng)異常
sar -n DEV,EDEV,TCP,ETCP 1 5 ss -s ss -ant state syn-recv netstat -s | egrep -i'listen|overflow|drop|retrans' cat /proc/softirqs cat /proc/net/softnet_stat iostat -xz 1 5 pidstat -d 1 5
幾種典型模式:
NET_RX飆高:小包洪峰、負(fù)載均衡不均、網(wǎng)卡隊列/中斷綁核不合理
ksoftirqd高:軟中斷堆積,用戶態(tài)進程看起來并不高,但 CPU 已經(jīng)被內(nèi)核吃掉
wa高、avgqu-sz高:不是 CPU 問題本身,根因在 IO
SYN-RECV很多:上游連接風(fēng)暴、半連接隊列不足、攻擊流量或健康檢查異常
2.2.6 云主機、虛擬化和容器環(huán)境的特殊檢查
很多“CPU 高”其實是資源被限制或者宿主機搶占。
mpstat -P ALL 1 5 sar -u ALL 1 5 grep . /sys/fs/cgroup/cpu.max 2>/dev/null grep . /sys/fs/cgroup/cpu.stat 2>/dev/null cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us 2>/dev/null cat /sys/fs/cgroup/cpu/cpu.cfs_period_us 2>/dev/null
重點關(guān)注:
%steal持續(xù)超過 5%:宿主機資源爭搶,業(yè)務(wù)再怎么調(diào)也只是緩解
nr_throttled持續(xù)增長:容器被 CPU quota 節(jié)流
usage_usec增長平緩但 RT 很高:可能是線程拿不到調(diào)度片
Kubernetes 場景里,再補兩步:
kubectl top node kubectl top pod -A --containers | head -30 kubectl describe node| egrep -A3'Allocated resources|Non-terminated Pods'
如果節(jié)點超賣嚴(yán)重,優(yōu)先做資源回收、親和性重排、Pod 驅(qū)逐,而不是只盯某個業(yè)務(wù)進程。
2.3 驗證排查結(jié)論
2.3.1 先驗證臨時止血動作是否生效
常見止血動作有三種:摘流、限流、降并發(fā)。動作做完后至少看 10 分鐘,不要看 30 秒就下結(jié)論。
watch -n 2"uptime; echo '---'; mpstat -P ALL 1 1; echo '---'; ss -s"
止血動作有效時,通常會看到:
熱點核心利用率下降到 60%-75%
業(yè)務(wù) RT 在 3-5 分鐘內(nèi)回落
連接重傳率和超時率同步下降
2.3.2 再驗證根因是否閉環(huán)
根因驗證至少要滿足三件事:
# 1. 熱點線程已消失或熱點函數(shù)占比明顯下降 sudo perf report --stdio | head -40 # 2. 關(guān)鍵業(yè)務(wù)接口恢復(fù) curl -s -o /dev/null -w"%{http_code} %{time_total} "http://127.0.0.1:8080/health # 3. 監(jiān)控指標(biāo)回歸 sar -u 1 3
閉環(huán)標(biāo)準(zhǔn)建議寫得硬一點:
CPU 峰值恢復(fù)到過去 7 天同時間窗 P95 附近
錯誤率回到告警閾值以下
相同流量下未再次出現(xiàn)同類熱點線程
三、示例代碼和配置
3.1 完整配置示例
3.1.1 主配置文件
下面這份配置用于開啟sysstat長期采樣,保證故障發(fā)生后能回看 CPU、IO、網(wǎng)絡(luò)的歷史走勢。線上機器不留歷史指標(biāo),很多 CPU 故障最后只能靠猜。
# 文件路徑:/etc/sysconfig/sysstat HISTORY=28 COMPRESSAFTER=7 SADC_OPTIONS="-S DISK -S XDISK -S INT -S IPV6" SA_DIR=/var/log/sa YESTERDAY=no
CentOS 7/8 系列還要確認(rèn)定時任務(wù)開啟:
# 文件路徑:/usr/lib/systemd/system/sysstat-collect.timer [Unit] Description=Run system activity accounting tool every 10 minutes [Timer] OnCalendar=*:00/10 AccuracySec=1min Persistent=true [Install] WantedBy=timers.target
啟用方式:
sudo systemctl daemon-reload sudo systemctlenable--now sysstat sudo systemctlenable--now sysstat-collect.timer sudo systemctlenable--now sysstat-summary.timer
3.1.2 輔助腳本
這份腳本用來在 CPU 異常時自動抓取快照,適合掛在定時任務(wù)、Prometheus Alertmanager webhook 或值班手冊里。腳本目標(biāo)不是“自動修復(fù)”,而是把最容易丟的現(xiàn)場第一時間保存下來。
#!/usr/bin/env bash
# 文件名:/usr/local/bin/cpu_hotspot_snapshot.sh
# 功能:采集 CPU 異?,F(xiàn)場,保留進程、線程、網(wǎng)絡(luò)、磁盤和內(nèi)核證據(jù)
set-euo pipefail
BASE_DIR="/var/log/cpu-hotspot"
TS="$(date +%F_%H%M%S)"
OUT_DIR="${BASE_DIR}/${TS}"
mkdir -p"${OUT_DIR}"
echo"[INFO] snapshot dir:${OUT_DIR}"
{
echo"===== basic ====="
date
hostname -f
uptime
uname -a
echo
echo"===== top ====="
top -b -n 1 | head -40
echo
echo"===== mpstat ====="
mpstat -P ALL 1 3
echo
echo"===== vmstat ====="
vmstat 1 5
echo
echo"===== sar cpu ====="
sar -u ALL 1 3
echo
echo"===== sar net ====="
sar -n DEV,EDEV,TCP,ETCP 1 3
echo
echo"===== iostat ====="
iostat -xz 1 3
} >"${OUT_DIR}/system.txt"2>&1
ps -eo pid,ppid,user,psr,stat,%cpu,%mem,lstart,cmd --sort=-%cpu | head -50
>"${OUT_DIR}/top_processes.txt"
pidstat -u -r -d -t -h 1 5 >"${OUT_DIR}/pidstat.txt"2>&1 ||true
ss -s >"${OUT_DIR}/ss_summary.txt"2>&1 ||true
cat /proc/softirqs >"${OUT_DIR}/softirqs.txt"2>&1 ||true
cat /proc/interrupts >"${OUT_DIR}/interrupts.txt"2>&1 ||true
dmesg -T | tail -200 >"${OUT_DIR}/dmesg_tail.txt"2>&1 ||true
TOP_PID="$(ps -eo pid,%cpu --sort=-%cpu | awk 'NR==2 {print $1}')"
if[[ -n"${TOP_PID}"&&"${TOP_PID}"=~ ^[0-9]+$ ]];then
ps -Lp"${TOP_PID}"-o pid,tid,psr,pcpu,stat,comm --sort=-pcpu
>"${OUT_DIR}/pid_${TOP_PID}_threads.txt"2>&1 ||true
timeout 20 perf record -F 49 -p"${TOP_PID}"-g -- sleep 15
>"${OUT_DIR}/perf_record.log"2>&1 ||true
perf report --stdio >"${OUT_DIR}/perf_report.txt"2>&1 ||true
fi
find"${BASE_DIR}"-maxdepth 1 -typed -mtime +7 -execrm -rf {} ; ||true
echo"[INFO] snapshot completed"
部署建議:
sudo install -o root -g root -m 0750 cpu_hotspot_snapshot.sh /usr/local/bin/cpu_hotspot_snapshot.sh echo'*/5 * * * * root /usr/local/bin/cpu_hotspot_snapshot.sh >/dev/null 2>&1'| sudo tee /etc/cron.d/cpu-hotspot
如果機器數(shù)量多,別每 5 分鐘全量抓。正確做法是只在告警觸發(fā)時抓,或者給腳本加條件判斷,例如最近 1 分鐘 CPU 大于 85% 才采樣。
3.2 實際應(yīng)用案例
案例一:Java 線程死循環(huán)把單核打滿
場景描述:某訂單服務(wù)發(fā)布后 RT 從 30 ms 拉高到 800 ms,監(jiān)控上整機 CPU 只有 45%,但 1 個核心長期 100%,業(yè)務(wù)側(cè)以為是數(shù)據(jù)庫慢,實際上根因在應(yīng)用線程。
排查過程:
top -H -p 28461 ps -Lp 28461 -o pid,tid,pcpu,comm --sort=-pcpu | head printf'0x%x '28513 jstack 28461 | grep -A 20 6f61 sudo perf top -p 28461 -g
關(guān)鍵現(xiàn)象:
線程28513持續(xù)占用 99% 單核
jstack顯示線程卡在業(yè)務(wù)規(guī)則引擎的循環(huán)判斷里
perf熱點集中在字符串拆分和正則匹配
實現(xiàn)代碼:
publicvoidcalculateDiscount(Listrules){ while(true) { for(String rule : rules) { if(rule.matches(".*VIP.*")) { doSomething(rule.split(":")[1]); } } } }
這段代碼在測試環(huán)境不容易暴露問題,因為規(guī)則量小、線程少。線上規(guī)則列表擴到 3 萬條之后,死循環(huán)加正則匹配直接把單核打穿。
修復(fù)動作:
先在注冊中心把異常實例摘流
回滾到上一版本,確認(rèn) CPU 回落
用緩存和預(yù)編譯規(guī)則替換循環(huán)內(nèi)的matches
給線程執(zhí)行邏輯加退出條件和超時保護
運行結(jié)果:
修復(fù)前:單核 99%,實例 P99 RT 1.2s,訂單超時率 8.7% 修復(fù)后:熱點線程消失,整機 CPU 下降到 31%,P99 RT 恢復(fù)到 85ms
案例二:軟中斷堆積導(dǎo)致網(wǎng)關(guān)節(jié)點系統(tǒng)態(tài) CPU 飆升
場景描述:某 API 網(wǎng)關(guān)節(jié)點在晚高峰出現(xiàn)%sys70% 以上,Nginx Worker 進程 CPU 并不高,但機器整體不可用,請求連接超時明顯增多。
排查過程:
top -b -n 1 | head -10 cat /proc/softirqs | column -t | egrep'NET_RX|NET_TX' sar -n DEV,EDEV,TCP,ETCP 1 5 ss -s ethtool -S eth0 | egrep'drop|miss|queue'
關(guān)鍵現(xiàn)象:
NET_RX軟中斷在 CPU0、CPU1 上遠高于其他核心
ksoftirqd/0、ksoftirqd/1持續(xù)占用 CPU
網(wǎng)卡多隊列開了,但中斷綁核不均,流量基本都壓在前兩個核心
處理腳本:
#!/usr/bin/env bash
# 文件名:rebalance_irq.sh
set-euo pipefail
SERVICE="irqbalance"
NIC="eth0"
sudo systemctlenable--now"${SERVICE}"
sudo ethtool -L"${NIC}"combined 8
forirqin$(grep"${NIC}"/proc/interrupts | awk -F:'{print $1}');do
echo0f | sudo tee"/proc/irq/${irq}/smp_affinity">/dev/null
done
運行結(jié)果:
調(diào)整前:sys 72%,NET_RX 在 CPU0/1 明顯傾斜,請求超時率 5.4% 調(diào)整后:sys 下降到 28%,各核心軟中斷分布趨于均衡,請求超時率降到 0.3%
這個案例里,如果只盯業(yè)務(wù)進程,基本看不出問題。CPU 真正被打滿的是內(nèi)核網(wǎng)絡(luò)收包路徑。
四、最佳實踐和注意事項
4.1 最佳實踐
4.1.1 性能優(yōu)化
優(yōu)化點一:常駐歷史采樣,別等出事再裝工具
sar歷史數(shù)據(jù)對 CPU 問題非常關(guān)鍵,尤其是那些“現(xiàn)在已經(jīng)恢復(fù),但昨晚 21:10 出過抖動”的故障。生產(chǎn)環(huán)境建議至少保留 28 天數(shù)據(jù)。
sudo sed -i's/^HISTORY=.*/HISTORY=28/'/etc/sysconfig/sysstat sudo systemctlenable--now sysstat sudo systemctl restart sysstat
優(yōu)化點二:給熱點業(yè)務(wù)做合理的線程上限
線程數(shù)不是越大越好。CPU 密集型業(yè)務(wù)線程池開太大,只會把上下文切換和鎖競爭一起抬高。我們團隊的經(jīng)驗值是:CPU 密集型服務(wù)先按CPU 核數(shù) * 1~2起步,再壓測修正。
nproc pidstat -w -p1 5
如果cswch/s和nvcswch/s持續(xù)很高,同時 CPU 利用率卻上不去,線程數(shù)大概率已經(jīng)過量。
優(yōu)化點三:網(wǎng)絡(luò)型節(jié)點優(yōu)先處理軟中斷綁核
網(wǎng)關(guān)、L4/L7 代理、日志采集節(jié)點,CPU 打滿很多時候不是應(yīng)用邏輯,而是收包路徑失衡。實測下來,雙 10G 網(wǎng)卡機器如果中斷集中在 1-2 個核上,業(yè)務(wù)峰值流量一來就會明顯抖。
irqbalance --debug 2>/dev/null | head cat /proc/interrupts sudo systemctlenable--now irqbalance
4.1.2 安全加固
安全措施一:限制調(diào)試工具使用權(quán)限
perf、strace、gdb都是排障利器,但也能帶來信息泄露風(fēng)險。生產(chǎn)環(huán)境建議只給運維值班組和 SRE 小范圍授權(quán)。
getfacl /usr/bin/perf sudo chmod 750 /usr/bin/perf
安全措施二:對 CPU 調(diào)優(yōu)動作做審計
改sysctl、改 IRQ 綁核、改容器 quota 都要進變更記錄。沒有審計的“臨時優(yōu)化”,一個月后基本沒人記得動過什么。
sudo auditctl -w /etc/sysctl.conf -p wa -k sysctl_change sudo auditctl -w /etc/security/limits.conf -p wa -k limits_change
安全措施三:對采樣腳本做最小權(quán)限執(zhí)行
快照腳本盡量只讀,不要順手把“自動 kill 高 CPU 進程”塞進去。自動止血可以做,但必須經(jīng)過白名單和二次確認(rèn),否則誤傷概率很高。
4.1.3 高可用配置
HA 方案一:業(yè)務(wù)實例接入負(fù)載均衡健康檢查,出現(xiàn) CPU 熱點時支持秒級摘流
HA 方案二:關(guān)鍵服務(wù)采用多可用區(qū)部署,避免單臺熱點機器拖垮整個業(yè)務(wù)面
備份策略:所有 CPU 調(diào)優(yōu)相關(guān)配置在修改前先做版本化備份,尤其是sysctl、網(wǎng)卡參數(shù)、服務(wù)線程配置
建議把下面這些動作標(biāo)準(zhǔn)化:
sudo cp -a /etc/sysctl.conf /etc/sysctl.conf.$(date +%F_%H%M%S).bak sudo sysctl -a > /var/backups/sysctl-all.$(date +%F_%H%M%S).txt tar czf /var/backups/service-config-$(date +%F_%H%M%S).tar.gz /etc/systemd/system /etc/nginx /etc/myapp 2>/dev/null
4.2 注意事項
4.2.1 配置注意事項
警告:CPU 問題沒有確認(rèn)根因前,不要直接重啟、擴容或改線程池。動作雖然能短時壓住癥狀,但會把現(xiàn)場打散,后面再復(fù)盤就只能靠猜。
注意事項一:load average高不等于 CPU 高。很多人看到負(fù)載 30 就判定 CPU 打滿,最后發(fā)現(xiàn)是磁盤卡住
注意事項二:容器 CPU 100% 先換算成限額視角再判斷,500m配額下 100% 和整機 100% 不是一個量級
注意事項三:strace -f -p對高并發(fā)服務(wù)有侵入,優(yōu)先用perf、pidstat、線程棧做輕量定位
4.2.2 常見錯誤
| 錯誤現(xiàn)象 | 原因分析 | 解決方案 |
|---|---|---|
| 看到top某進程 200% 就以為異常 | 多核環(huán)境下進程可以合法使用多個核 | 結(jié)合核數(shù)和線程數(shù)判斷,查看線程級 CPU 分布 |
| 只看當(dāng)前時刻,沒有歷史趨勢 | 瞬時 CPU 回落后,現(xiàn)場已經(jīng)丟失 | 常駐sysstat、保留 Prometheus 歷史數(shù)據(jù)、告警觸發(fā)自動快照 |
| 只抓進程 CPU,不看%sys/%soft/%steal | 根因可能在內(nèi)核、中斷或虛擬化層 | 先分層判斷,再做針對性定位 |
4.2.3 兼容性問題
版本兼容:perf最好和當(dāng)前運行內(nèi)核版本匹配,不匹配時符號解析會不準(zhǔn)
平臺兼容:在云廠商共享宿主機上,%steal的參考價值高于物理機
組件依賴:容器環(huán)境下查看 cgroup 指標(biāo)時,需要區(qū)分 cgroup v1 和 cgroup v2 的文件路徑
五、故障排查和監(jiān)控
5.1 故障排查
5.1.1 日志查看
CPU 飆高雖然是資源問題,但日志仍然能給出觸發(fā)時間點、請求類型和錯誤放大路徑。日志至少看三類:系統(tǒng)日志、應(yīng)用日志、內(nèi)核日志。
# 查看系統(tǒng)日志 sudo journalctl -S -30min # 查看應(yīng)用日志 tail -f /var/log/myapp/app.log # 查看錯誤日志 grep -E"ERROR|Timeout|RejectedExecution|GC overhead"/var/log/myapp/app.log | tail -50
如果是 Java 服務(wù),再補 GC 日志:
grep -E"Pause Young|Pause Full|Full GC"/var/log/myapp/gc.log | tail -50
5.1.2 常見問題排查
問題一:CPU 100%,但top看不到明顯高進程
top -b -n 1 | head -10 mpstat -P ALL 1 5 cat /proc/softirqs cat /proc/interrupts
癥狀:整機 CPU 高,單個業(yè)務(wù)進程都不突出,%sys/%soft偏高
診斷:多半是軟中斷、網(wǎng)卡隊列、驅(qū)動或內(nèi)核收包路徑問題
解決:
檢查NET_RX分布是否傾斜
檢查irqbalance是否正常工作
檢查是否存在小包洪峰、連接風(fēng)暴或異常抓包任務(wù)
問題二:應(yīng)用進程 CPU 高,但業(yè)務(wù)量并不大
ps -eo pid,pcpu,pmem,cmd --sort=-pcpu | head top -H -psudo perf record -F 99 -p -g -- sleep 20 sudo perf report --stdio | head -60
癥狀:請求量一般,實例仍持續(xù)吃滿單核或多核
診斷:常見于代碼死循環(huán)、熱點 key、異常重試、自旋鎖、正則或 JSON 開銷過大
解決:
先摘流,保證實例不繼續(xù)放大影響
抓熱點線程和調(diào)用棧
回滾版本或關(guān)閉問題開關(guān)
補壓測用例,避免同類邏輯再次進生產(chǎn)
問題三:CPU 高伴隨 RT 高,%steal明顯抬升
癥狀:業(yè)務(wù) RT 波動明顯,整機 CPU 看起來不算離譜,但%steal持續(xù)超過 5%
排查:mpstat -P ALL 1 5、云平臺宿主機事件、節(jié)點資源爭搶記錄
解決:遷移實例、切換獨享型規(guī)格、和云平臺確認(rèn)宿主機抖動
5.1.3 調(diào)試模式
線上調(diào)試優(yōu)先輕量模式,不要一上來抓全量 heap dump 或gcore。
# 實時查看熱點函數(shù) sudo perf top -p-g # 20 秒采樣 sudo perf record -F 49 -p -g -- sleep 20 # 查看調(diào)試信息 sudo perf report --stdio | head -80
如果是 Java 服務(wù),補一個只讀線程棧:
jstack -l> /tmp/jstack.$(date +%s).log
5.2 性能監(jiān)控
5.2.1 關(guān)鍵指標(biāo)監(jiān)控
# CPU使用率 mpstat -P ALL 1 3 # 進程維度 CPU pidstat -u -p ALL 1 3 # 網(wǎng)絡(luò)連接 ss -s # 磁盤IO iostat -xz 1 3
建議重點盯這些指標(biāo):
node_cpu_seconds_total按 mode 拆分后的user/system/iowait/steal/softirq
單機 1 分鐘和 5 分鐘load average
進程級 CPU Top N
網(wǎng)絡(luò)重傳、丟包、SYN backlog overflow
容器throttled_periods_total
5.2.2 監(jiān)控指標(biāo)說明
| 指標(biāo)名稱 | 正常范圍 | 告警閾值 | 說明 |
|---|---|---|---|
| 整機 CPU 使用率 | 日常峰值低于 70% | 連續(xù) 5 分鐘高于 85% | 先看用戶態(tài)還是系統(tǒng)態(tài) |
| 單核心 CPU 使用率 | 波峰可到 80% | 連續(xù) 3 分鐘高于 95% | 單線程熱點更依賴這個指標(biāo) |
| steal 比例 | 低于 1% | 連續(xù) 3 分鐘高于 5% | 云主機資源爭搶的典型信號 |
| softirq 比例 | 低于 10% | 連續(xù) 3 分鐘高于 25% | 網(wǎng)卡中斷、連接洪峰常見 |
| 進程 CPU Top1 | 隨業(yè)務(wù)波動 | 單進程長期高于 200% | 多核進程需結(jié)合線程視角判斷 |
| 容器節(jié)流次數(shù) | 接近 0 | 5 分鐘內(nèi)持續(xù)增長 | 說明 CPU quota 不夠 |
5.2.3 監(jiān)控告警配置
# 文件路徑:prometheus/rules/cpu_hotspot.yml
groups:
-name:cpu-hotspot
rules:
-alert:HostCpuHigh
expr:100-(avgby(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m]))*100)>85
for:5m
labels:
severity:critical
annotations:
summary:"主機 CPU 持續(xù)過高"
description:"{{ $labels.instance }}CPU 連續(xù) 5 分鐘高于 85%"
-alert:HostSoftIrqHigh
expr:avgby(instance)(rate(node_cpu_seconds_total{mode="softirq"}[5m]))*100>25
for:3m
labels:
severity:warning
annotations:
summary:"主機軟中斷占比過高"
description:"{{ $labels.instance }}軟中斷 CPU 持續(xù)高于 25%"
-alert:ContainerCpuThrottlingHigh
expr:sumby(pod,namespace)(rate(container_cpu_cfs_throttled_periods_total[5m]))>20
for:5m
labels:
severity:warning
annotations:
summary:"容器 CPU 節(jié)流明顯"
description:"{{ $labels.namespace }}/{{ $labels.pod }}近 5 分鐘 CPU throttling 持續(xù)升高"
5.3 備份與恢復(fù)
5.3.1 備份策略
任何 CPU 調(diào)優(yōu)動作之前,先備份配置。尤其是sysctl、IRQ 綁核、服務(wù)線程池、JVM 參數(shù),改錯了很容易引發(fā)更大的抖動。
#!/usr/bin/env bash
# 文件名:/usr/local/bin/backup_cpu_related_configs.sh
set-euo pipefail
BACKUP_DIR="/var/backups/cpu-tuning/$(date +%F_%H%M%S)"
mkdir -p"${BACKUP_DIR}"
cp -a /etc/sysctl.conf"${BACKUP_DIR}/"
cp -a /etc/sysctl.d"${BACKUP_DIR}/"2>/dev/null ||true
cp -a /etc/security/limits.conf"${BACKUP_DIR}/"2>/dev/null ||true
cp -a /etc/systemd/system"${BACKUP_DIR}/systemd"2>/dev/null ||true
sysctl -a >"${BACKUP_DIR}/sysctl-all.txt"
cat /proc/interrupts >"${BACKUP_DIR}/interrupts.txt"
cat /proc/softirqs >"${BACKUP_DIR}/softirqs.txt"
tar czf"${BACKUP_DIR}.tar.gz"-C"$(dirname "${BACKUP_DIR}")""$(basename "${BACKUP_DIR}")"
echo"backup saved to${BACKUP_DIR}.tar.gz"
5.3.2 恢復(fù)流程
停止臨時調(diào)優(yōu)動作:回滾腳本、關(guān)閉異常定時任務(wù)、撤銷臨時限流或綁核
恢復(fù)配置文件:從最近一次備份還原sysctl、服務(wù)配置、線程池參數(shù)
驗證完整性:執(zhí)行sysctl --system,檢查服務(wù)配置語法和啟動狀態(tài)
重啟或熱加載服務(wù):在低峰期執(zhí)行,并用監(jiān)控觀察至少 10 分鐘
六、總結(jié)
6.1 技術(shù)要點回顧
先分層,再深入:整機、進程、線程、調(diào)用棧四層順著走,判斷不會跑偏
先分態(tài),再取證:先區(qū)分%usr/%sys/%soft/%steal,再決定抓進程還是抓內(nèi)核路徑
先?,F(xiàn)場,再做動作:快照比重啟更重要,沒有現(xiàn)場很難閉環(huán)
線程級定位價值最高:很多 CPU 問題真正的根因都藏在熱點線程和調(diào)用棧里
系統(tǒng)態(tài) CPU 不能只盯應(yīng)用:軟中斷、網(wǎng)卡隊列、連接風(fēng)暴經(jīng)常才是真正的根因
容器環(huán)境要看節(jié)流和 steal:CPU 不夠用不一定是程序?qū)懖睿部赡苁桥漕~和宿主機資源爭搶
6.2 進階學(xué)習(xí)方向
深入 Linux 調(diào)度器和 CFS 配額機制
學(xué)習(xí)資源:Linux kernel documentation、sched相關(guān)內(nèi)核文檔
實踐建議:在測試環(huán)境復(fù)現(xiàn) CPU quota 節(jié)流、綁核和調(diào)度延遲問題
掌握perf、eBPF、bcc工具鏈
學(xué)習(xí)資源:Brendan Gregg 的性能分析資料、bcc-tools
實踐建議:先從perf top、perf record、runqlat、profile這類輕量工具入手
建立故障自動取證體系
學(xué)習(xí)資源:Prometheus Alertmanager webhook、企業(yè)內(nèi)巡檢平臺
實踐建議:把 CPU、高負(fù)載、連接風(fēng)暴的快照采集做成統(tǒng)一腳本和 SOP
6.3 參考資料
Linux kernel CPU documentation- Linux 內(nèi)核 CPU、調(diào)度與性能分析文檔
sysstat official site-sar、mpstat、pidstat工具說明
perf wiki-perf使用方法和常見問題
Brendan Gregg Blog- Linux 性能分析實戰(zhàn)材料
附錄
A. 命令速查表
top -H -p# 查看進程內(nèi)線程 CPU pidstat -u -t -p 1 5 # 觀察線程級 CPU 趨勢 mpstat -P ALL 1 3 # 查看每個核心使用率 sar -u ALL 1 5 # 查看 CPU 各 mode 分布 sar -n DEV,EDEV,TCP,ETCP 1 5 # 查看網(wǎng)絡(luò)與 TCP 指標(biāo) iostat -xz 1 5 # 查看磁盤隊列與 IO 延遲 cat /proc/softirqs # 查看軟中斷分布 cat /proc/interrupts # 查看硬中斷分布 perf top -p -g # 實時看熱點函數(shù) perf record -F 99 -p -g -- sleep 20 # 采樣留證據(jù)
B. 配置參數(shù)詳解
kernel.perf_event_paranoid
作用:控制普通用戶使用perf的權(quán)限
建議:生產(chǎn)環(huán)境默認(rèn)保持嚴(yán)格,排障時臨時下調(diào),結(jié)束后恢復(fù)
HISTORY
作用:控制sysstat歷史數(shù)據(jù)保留天數(shù)
建議:不少于 28 天,雙十一、618 這類業(yè)務(wù)建議保留 60 天
cpu.max/cpu.cfs_quota_us
作用:容器 CPU 配額限制
建議:對低延遲業(yè)務(wù)慎用過小配額,避免頻繁 throttling
smp_affinity
作用:控制中斷可在哪些 CPU 上處理
建議:高流量網(wǎng)關(guān)節(jié)點關(guān)注這個參數(shù),避免中斷只壓在少數(shù)核心
C. 術(shù)語表
| 術(shù)語 | 英文 | 解釋 |
|---|---|---|
| 用戶態(tài) | user mode | CPU 在應(yīng)用代碼上消耗的時間 |
| 系統(tǒng)態(tài) | system mode | CPU 在內(nèi)核代碼、系統(tǒng)調(diào)用、中斷處理上消耗的時間 |
| 軟中斷 | softirq | Linux 內(nèi)核為網(wǎng)絡(luò)、塊設(shè)備等延后處理設(shè)計的輕量機制 |
| 節(jié)流 | throttling | 容器因 CPU quota 不足被強制限制執(zhí)行 |
| 竊取時間 | steal time | 虛擬機本該獲得 CPU,但被宿主機拿去服務(wù)其他虛機的時間 |
-
cpu
+關(guān)注
關(guān)注
68文章
11285瀏覽量
225122 -
Linux
+關(guān)注
關(guān)注
88文章
11767瀏覽量
219100 -
服務(wù)器
+關(guān)注
關(guān)注
14文章
10264瀏覽量
91528
原文標(biāo)題:Linux 服務(wù)器 CPU 飆高怎么排查?一套實戰(zhàn)定位思路講清楚
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
Linux系統(tǒng)CPU占用率100%的排查思路
linux服務(wù)器和windows服務(wù)器
教你linux搭建web服務(wù)器
排查Linux服務(wù)器性能問題工具
JVM CPU使用率飆高問題的排查分析過程
如何使用Checkmk監(jiān)控Linux服務(wù)器?
Linux服務(wù)器常見的網(wǎng)絡(luò)故障排查方法
linux查看服務(wù)器配置
服務(wù)器cpu和普通電腦cpu的區(qū)別
Linux服務(wù)器CPU飆升的原因
Linux服務(wù)器CPU飆高怎么排查
評論