侧边栏壁纸
  • 累计撰写 19 篇文章
  • 累计创建 4 个标签
  • 累计收到 5 条评论

目 录CONTENT

文章目录

CPU-占用100排查指南-001

Linux 服务器 CPU 占用 100% 排查指南

版本: 1.0
更新时间: 2025-06-06
适用对象: 运维工程师、系统管理员、开发人员


前言

CPU 占用 100% 是什么?

想象一下:一个厨师(CPU)同时要做 4 道菜(任务),但突然来了 100 份订单,他忙得团团转,其他顾客(服务请求)都只能排队等着。这就是 CPU 满载的状态。

当 CPU 被某个进程完全占满时,系统响应会变慢,服务可能超时甚至崩溃。

本文档会告诉你:

  • 如何快速定位罪魁祸首进程
  • 如何分析进程为什么占用高 CPU
  • 如何安全地解决问题
  • 如何预防未来再次发生

目录

  1. 快速诊断
  2. 现状确认
  3. 分层排查
  4. 常见原因分析
  5. 解决方案
  6. 验证修复
  7. 预防措施
  8. 总结

一、快速诊断

最常见原因:某个进程失控(死循环、计算密集型任务、挖矿木马)

快速验证:执行 topP(按 CPU 排序)查看最耗 CPU 的进程

一键定位命令

# 👀 查看占用 CPU 最高的前 10 个进程
ps aux --sort=-%cpu | head -11

# 参数解释:
# aux:显示所有进程的详细信息
# --sort=-%cpu:按 CPU 使用率降序排序(- 表示降序)
# head -11:显示前 11 行(1 行表头 + 10 个进程)

# 输出示例:
# USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
# app       1234 99.8  2.5 500000 80000 ?        Rl   10:00  15:30 python3 /var/www/myapp/scripts/data_process.py
# nginx     5678  1.2  0.6 100000 20000 ?        S    09:00   0:05 nginx: worker process
# root      9012  0.5  0.1  50000  8000 ?        Ss   08:00   0:02 /usr/lib/systemd/systemd

# 解读:
# - USER:运行进程的用户(app 用户运行的脚本)
# - PID:进程 ID(1234,后续操作要用到)
# - %CPU:CPU 使用率(99.8%,几乎占满)
# - %MEM:内存使用率(2.5%,内存正常)
# - STAT:进程状态(R=运行中,l=多线程,s=会话领导)
# - TIME:累计使用 CPU 的时间(15:30,已经跑了 15 分 30 秒)
# - COMMAND:完整命令行(明确看到是哪个脚本)

二、现状确认

2.1 确认操作系统环境

# 查看系统版本
cat /etc/os-release

# 输出示例:
# NAME="Ubuntu"
# VERSION="20.04.6 LTS (Focal Fossa)"
# ID=ubuntu
# PRETTY_NAME="Ubuntu 20.04.6 LTS"

# 解读:
# NAME:操作系统名称(Ubuntu)
# VERSION:具体版本(20.04.6 长期支持版)
# 不同系统的命令可能略有差异(如 systemctl vs service)
# 👀 查看 CPU 核心数
nproc

# 输出:4
# 解读:
# 4 核 CPU 意味着:
# - 单核 100% = 总体 25%
# - 4 核都 100% = 真满载(top 会显示 400%)
# - Load Average > 4 表示 CPU 超负荷

2.2 确认系统负载

# 查看系统负载
uptime

# 输出:
# 10:30:00 up 5 days, 2:15, 1 user, load average: 4.20, 3.80, 2.90

# 解读:
# - 10:30:00:当前时间
# - up 5 days, 2:15:系统运行了 5 天 2 小时 15 分钟
# - load average:负载平均值(像超市排队人数)
#   - 4.20:最近 1 分钟平均排队任务数
#   - 3.80:最近 5 分钟平均
#   - 2.90:最近 15 分钟平均
#   - 趋势分析:2.90 → 3.80 → 4.20,问题在恶化!
#   - 如果数字 > CPU 核心数(4),说明 CPU 已经忙不过来了

三、分层排查

3.1 应用层排查(最常用)

# 👀 实时查看进程动态(推荐交互式)
top

# 进入 top 后按:
# P:按 CPU 使用率排序(默认)
# M:按内存使用率排序
# 1:展开每个 CPU 核心的使用情况
# q:退出

# 输出示例:
# top - 10:30:00 up 5 days,  2:15,  1 user,  load average: 4.20, 3.80, 2.90
# Tasks: 120 total,   3 running, 117 sleeping,   0 stopped,   0 zombie
# %Cpu(s): 98.5 us,  1.2 sy,  0.0 ni,  0.2 id,  0.0 wa,  0.0 hi,  0.1 si,  0.0 st
#
#   PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
#  1234 app       20   0  500000  80000  10000 R  99.8   2.5  15:30.50 python3
#  5678 root      20   0  100000  20000   8000 S   1.2   0.6   0:05.20 nginx

CPU 占比详细解读

指标 含义 正常值 异常说明
us (user) 用户空间占用 < 70% 应用代码在计算
sy (system) 内核空间占用 < 20% 内核调用过多
ni (nice) 低优先级进程 < 10% 后台任务影响
id (idle) 空闲率 > 20% 越低越忙
wa (wait) IO 等待 < 5% 高说明是磁盘瓶颈
hi/si 硬/软中断 < 5% 高说明网络/中断频繁
st (steal) 被虚拟化偷走 0% 非零说明虚拟机资源被抢占

3.2 进程详情排查

# 👀 查看进程的完整命令行和父进程
ps -p 1234 -o pid,ppid,user,%cpu,%mem,stat,start,time,command

# 参数解释:
# -p 1234:指定进程 ID
# -o:自定义输出字段

# 输出示例:
#   PID  PPID USER     %CPU %MEM STAT  STARTED      TIME COMMAND
#  1234   890 app     99.8  2.5 Rl    2025-06-06  15:30 python3 /var/www/myapp/scripts/data_process.py

# 解读:
# - PPID 890:父进程 ID(谁启动它的)
# - STAT Rl:R=运行中,l=多线程
# - STARTED:启动时间(2025-06-06,今天刚启动的)
# - TIME 15:30:累计占用 CPU 15 分 30 秒
# 👀 查看这个进程打开了哪些文件和连接
lsof -p 1234 | head -30

# 参数解释:
# -p 1234:指定进程 ID
# head -30:只看前 30 行

# 输出示例:
# COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
# python3  1234  app  cwd    DIR    8,1     4096  12345 /var/www/myapp
# python3  1234  app  txt    REG    8,1  1000000  23456 /usr/bin/python3.8
# python3  1234  app    0r   REG    8,1   500000  34567 /var/www/myapp/input.csv
# python3  1234  app    3u  IPv4    0      0t0    56789 TCP *:8080 (LISTEN)

# 解读:
# - cwd:当前工作目录(/var/www/myapp)
# - txt:程序文件(/usr/bin/python3.8)
# - 0r:打开的文件(input.csv 正在被读取)
# - 3u:网络连接(监听 8080 端口)
# - 这些信息能帮你理解这个进程在干什么

3.3 资源检查(USE 方法)

Utilization(利用率)

# 👀 每个 CPU 核心的使用情况
mpstat -P ALL 1 3

# 参数解释:
# -P ALL:显示所有 CPU 核心
# 1 3:每秒采样一次,采样 3 次

# 输出示例:
# 10:30:00  CPU    %usr   %nice    %sys  %iowait    %irq   %soft  %steal  %guest   %idle
# 10:30:01  all   98.50    0.00    1.00     0.00    0.00    0.50    0.00    0.00    0.00
# 10:30:01    0   99.00    0.00    1.00     0.00    0.00    0.00    0.00    0.00    0.00
# 10:30:01    1   98.00    0.00    1.00     0.00    0.00    1.00    0.00    0.00    0.00
# 10:30:01    2   99.00    0.00    0.00     0.00    0.00    1.00    0.00    0.00    0.00
# 10:30:01    3   98.00    0.00    1.00     0.00    0.00    1.00    0.00    0.00    0.00

# 解读:
# - 4 个核心都接近 100% → 真正的满载
# - %usr 很高:用户代码在计算(不是内核问题)
# - %iowait 很低:不是磁盘 IO 问题
# - 如果只有 1 个核心 100%,其他空闲 → 单线程程序

Saturation(饱和度)

# 📊 查看进程调度情况(有多少任务在排队等 CPU)
vmstat 1 5

# 参数解释:
# 1 5:每秒采样一次,采样 5 次

# 输出示例:
# procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
#  r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
#  5  0      0  500000  80000 1000000    0    0    10    20  100  200 98  1  0  0  0
#  4  0      0  499000  80000 1000000    0    0    10    20  100  200 98  1  0  0  0

# 解读关键列:
# - r(running):正在等待 CPU 的进程数
#   - r > CPU核心数 → CPU 饱和了(像超市 4 个收银台,却有 5 个人排队)
#   - 这里 r=5,CPU=4核 → 已经超载
# - b(blocked):等待 IO 的进程数
#   - 如果 b 很高,说明是磁盘问题,不是 CPU 问题
# - us/sy/id/wa:同 top 的 CPU 占比

Errors(错误)

# ⚠️ 检查内核错误(硬件/CPU 异常)
dmesg | tail -50

# 输出示例(如果有问题):
# [12345.678] CPU0: Core temperature above threshold, cpu clock throttled
# [12345.679] CPU1: Core temperature above threshold, cpu clock throttled

# 解读:
# - 如果出现这些错误 → CPU 过热,需要检查散热
# - 如果没有 → 排除硬件问题

四、常见原因分析

根据前面的排查,判断具体原因:

现象 可能原因 解决方案 紧急程度
某个 python/java 进程 99% CPU 代码死循环或计算密集型任务 检查代码逻辑或限制资源 🔴 高
kworker 进程占用高 内核任务(中断处理、IO 等待) 检查 dmesg 和驱动 🟡 中
kswapd 占用高 内存不足触发交换 检查内存,增加 swap 🟡 中
陌生进程名 + 高 CPU 可能是挖矿木马 立即隔离,检查入侵痕迹 🔴 高
systemd-journald 占用高 日志写入过多 清理日志,检查应用 🟡 中
所有核心都 100% + 负载高 真的业务压力大 考虑扩容或限流 🟠 中高

五、解决方案

⚠️ 生产环境高风险操作,请谨慎执行!
在杀死进程前,建议先保存相关日志和状态信息。

操作前:保存现场证据

# 📋 保存当前状态(用于后续分析)
mkdir -p /tmp/cpu_high_reports

ps aux --sort=-%cpu > /tmp/cpu_high_reports/snapshot_$(date +%Y%m%d_%H%M%S).txt

top -bn1 > /tmp/cpu_high_reports/top_snapshot_$(date +%Y%m%d_%H%M%S).txt

# 参数解释:
# mkdir -p:创建目录(幂等,不存在才创建)
# --sort=-%cpu:按 CPU 使用率降序排序
# $(date +%Y%m%d_%H%M%S):当前时间戳,如 20250606_103000
# >:重定向输出到文件

# 验证:
ls -la /tmp/cpu_high_reports/

方案一:优雅停止进程(推荐)

就像正常关机一样,让进程有机会保存数据、关闭连接。

# ⏹️ 发送 SIGTERM 信号(让进程有机会清理后退出)
kill 1234

# 参数解释:
# 1234:进程 PID
# kill 默认发送 SIGTERM(信号 15),进程可以捕获并优雅退出
# 就像告诉进程:"请你自己关机"

# 等待 10 秒后检查
sleep 10
ps -p 1234

# 如果输出为空 → 进程已正常退出 ✅
# 如果进程还在 → 说明进程卡死了,需要方案二

方案二:强制杀死进程(谨慎使用)

⚠️ 危险操作:强制杀进程可能导致数据丢失或文件损坏。
就像直接拔电源,进程没有任何机会保存数据。

# ⏹️ 发送 SIGKILL 信号(强制杀死,进程无法捕获)
kill -9 1234

# 参数解释:
# -9:SIGKILL 信号,内核直接杀死进程
# 进程无法捕获这个信号,无法做任何清理工作

# 确认进程已消失
ps -p 1234
# 应该输出空

方案三:限制进程 CPU(适合正常业务)

如果这个进程是正常业务,但不能让它占满 CPU:

# 方法 1:使用 cpulimit 限制
cpulimit -p 1234 -l 50 &

# 参数解释:
# -p 1234:指定进程
# -l 50:限制最多使用 50% CPU
# &:后台运行

# 如果没安装 cpulimit:
# Ubuntu/Debian
sudo apt install cpulimit
# CentOS/RHEL
sudo yum install cpulimit
# 方法 2:使用 systemd 临时限制(推荐,更专业)
systemctl set-property system.slice CPUQuota=50%

# 参数解释:
# set-property:临时修改属性
# system.slice:系统服务组
# CPUQuota=50%:限制 CPU 配额为 50%

# 恢复:
systemctl set-property system.slice CPUQuota=
# 空值表示恢复默认

方案四:排查代码问题(治本)

如果进程是你自己的应用:

# 查看进程在调用什么函数(需要安装 python3 的 py-spy)
pip3 install py-spy

# 查看进程的调用栈
py-spy top -p 1234

# 参数解释:
# top:实时查看调用栈
# -p 1234:指定进程
# 这会显示进程当前在执行哪行代码

# 输出示例:
# Total Samples: 10000
# GIL: 100.00%, Active: 100.00%
#
#  %Own   %Total  OwnTime  TotalTime  Function (filename:line)
# 98.00%  98.00%   10.0s     10.0s    process_data (data_process.py:45)
#  2.00%   2.00%    0.2s      0.2s    <module> (data_process.py:10)

# 解读:
# - process_data 函数在第 45 行占用了 98% 的 CPU
# - 打开这个文件检查第 45 行是否有死循环

六、验证修复

6.1 确认 CPU 恢复正常

# ✅ 检查 CPU 使用率
top -bn1 | grep "%Cpu"

# 输出示例(正常):
# %Cpu(s):  5.2 us,  1.0 sy,  0.0 ni, 93.5 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st

# 解读:
# - id (idle) = 93.5% → CPU 93.5% 空闲,恢复正常 ✅
# - us = 5.2% → 只有 5.2% 在跑用户程序,很轻松

6.2 确认负载下降

# ✅ 检查 Load Average
uptime

# 输出示例:
# 10:35:00 up 5 days,  2:20,  1 user,  load average: 0.50, 1.20, 2.00

# 解读:
# - 趋势:2.00 → 1.20 → 0.50 → 正在恢复
# - 0.50 < 4(核心数)→ CPU 不忙了 ✅

6.3 确认问题进程已消失

# ✅ 确认进程已不存在
ps -p 1234

# 输出(空):
# PID TTY          TIME CMD

# 解读:没有输出进程信息 → 已消失 ✅

七、预防措施

7.1 设置 CPU 监控告警

#!/bin/bash
# /usr/local/bin/cpu_monitor.sh
# CPU 使用率超过 90% 持续 3 次采样,记录告警日志

CPU_USAGE=$(top -bn1 | grep "%Cpu" | awk '{print $2}' | cut -d'.' -f1)
THRESHOLD=90
LOG_FILE="/var/log/cpu_alert.log"

mkdir -p "$(dirname "$LOG_FILE")"

if [ "$CPU_USAGE" -gt "$THRESHOLD" ]; then
    echo "⚠️ [$(date)] CPU usage is ${CPU_USAGE}% (threshold: ${THRESHOLD}%)" >> "$LOG_FILE"
    echo "📊 Top 3 CPU consumers:" >> "$LOG_FILE"
    ps aux --sort=-%cpu | head -4 >> "$LOG_FILE"
    echo "---" >> "$LOG_FILE"
    # 可选:发送邮件告警
    # echo "CPU high: ${CPU_USAGE}%" | mail -s "Server Alert" admin@example.com
fi

# 参数解释:
# awk '{print $2}':提取 CPU 使用率的数字部分
# cut -d'.' -f1:去掉小数部分
# $():命令替换,把命令结果赋值给变量
# >>:追加到文件(不覆盖)
# 添加执行权限
chmod +x /usr/local/bin/cpu_monitor.sh

# 设置定时任务(每 5 分钟检查一次)
(crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/cpu_monitor.sh") | crontab -

# 参数解释:
# crontab -l:列出当前定时任务
# 2>/dev/null:忽略错误(首次执行时没有任务)
# echo "*/5...":添加新的定时任务
# crontab -:写入定时任务列表

7.2 设置进程资源限制

# 使用 systemd 服务文件限制资源
# /etc/systemd/system/myapp.service
[Service]
# 限制 CPU 使用率不超过 50%
CPUQuota=50%

# 限制内存使用
MemoryMax=1G

# 限制打开文件数
LimitNOFILE=65536
# 重新加载配置
systemctl daemon-reload
systemctl restart myapp

# 验证限制是否生效
systemctl show myapp -p CPUQuota
# 输出:CPUQuota=50%

八、总结

核心排查步骤

步骤 关键命令 目的
1. 找进程 ps aux --sort=-%cpu | head -11 找到 CPU 最高的进程
2. 看详情 ps -p PID -o command 确认进程在干什么
3. 查资源 top + vmstat + mpstat 确认是 CPU 问题还是 IO 问题
4. 查文件 lsof -p PID 查看打开的文件和连接
5. 先优雅 kill PID 尝试正常退出
6. 后强制 kill -9 PID 卡死时强制杀死
7. 验证 uptime + top 确认 CPU 恢复正常

黄金法则

  1. 先诊断,后行动 - 不要盲目 kill 进程,先搞清楚它是什么
  2. 先优雅,后强制 - 先 kill,无效再 kill -9
  3. 留证据,方便追溯 - 操作前保存状态快照
  4. 治标更要治本 - 找到代码层面的根本原因
  5. 预防胜于治疗 - 设置监控告警和资源限制

速查表

# 一键诊断命令
ps aux --sort=-%cpu | head -11 && uptime && echo "---" && top -bn1 | grep "%Cpu"

# 这行命令会同时显示:
# 1. CPU 占用最高的进程
# 2. 系统负载
# 3. CPU 使用率详情

文档版本:1.0
最后更新:2025-06-06
维护者:guobin

0

评论区