CPU 飙到 100% 别急着重启!一文讲透云服务器高负载的排查与根治

做站长这些年,最怕半夜收到监控告警:某台云服务器 CPU 使用率持续 100%,网站打开慢如蜗牛,SSH 连上去都卡半天。很多朋友第一反应是重启,重启确实能续命几分钟,但过不了多久又飙红。治标不治本,今天笔者就把自己踩过的坑和一套完整的排查思路分享出来,从快速定位到彻底解决,手把手带你搞定这个疑难杂症。

先别慌,这几个问题你大概率遇到过

💡 推荐阅读:云服务器选型横评:个人博客与小型团队项目到底需要什么配置?

Q1:CPU 100% 但 top 里看不到高占用进程,怎么回事?

这是最让人抓狂的情况。你用 top 看,每个进程 CPU 都不高,但整体负载就是满的。常见原因有两个:一是 被挖矿木马做了进程隐藏,比如通过 rootkit 篡改 ps/top 的输出;二是 大量短生命周期进程,比如被 CC 攻击时每个请求 fork 一个进程,top 刷新间隔根本抓不到。这时候你需要用 htop 或者直接看 /proc 目录下的进程状态来交叉验证。

Q2:CPU 高但流量不大,是不是云厂商超售了?

有可能,但先别急着甩锅。笔者遇到过不少案例,其实是磁盘 I/O 等待(iowait)被算进了 CPU 负载。用 top%wa 那一列,如果超过 20%,说明瓶颈在磁盘不在 CPU。另外,云服务器如果用的是共享型实例,确实存在资源争抢,但正规厂商的独享型实例基本不会。选服务器时别贪便宜买那种几块钱一个月的超售机器,后面有的是坑。

Q3:重启后正常,过一会又 100%,怎么根治?

这说明有定时任务或守护进程在反复拉起问题程序。挖矿木马通常会写 crontab、systemd service 或者 LD_PRELOAD 劫持。你只 kill 进程没用,必须找到它的持久化入口一并清理。后面我会给出具体的排查命令。

Q4:CPU 100% 会导致数据丢失吗?

会。如果数据库(MySQL/Redis)因为 CPU 抢占导致响应超时,连接池打满,严重时可能触发主从切换或数据写入失败。所以定位要快,但千万不要在没搞清楚状况前直接 kill -9 数据库进程,先做好快照或备份。

根因深度剖析:CPU 100% 的五大元凶

🔥 【限时特惠福利】高性价比独享云服务器限时 1 折起

搭建网站或部署容器推荐选择高稳定性独享云服务器。限时特惠通道开放中,点击即可领取专属满减代金券与特惠折扣:

👉 立刻领取云服务器限时优惠券

💡 延伸阅读:别再花冤枉钱!云服务器2核2G和2核4G真实跑分对比,看完再买不踩坑

根据笔者处理过的几十个案例,CPU 长期满载基本逃不出下面五类原因:

类型 典型特征 排查入口
恶意挖矿 CPU 占满但进程名伪装成 kworker 等 crontab、systemd、/tmp 目录
CC/DDoS 攻击 大量 ESTABLISHED 连接,来源 IP 集中 netstat、nginx 访问日志
代码死循环 单个进程 CPU 持续 90%+ top -Hp、strace
配置不当 PHP-FPM 进程数过多、MySQL 全表扫描 慢查询日志、进程数配置
磁盘 I/O 瓶颈 %wa 高,负载高但 CPU 空闲 iostat、iotop

实操步骤:从定位到清除

💡 深度技术指南:Docker 日志把磁盘吃满了?别慌,手把手教你清理并永久限制大小

第一步:快速锁定高占用进程

登录服务器后,先别急着操作,按顺序执行:

# 查看整体负载和 CPU 分布
top -c

# 按 CPU 排序,找出罪魁祸首
top -b -n 1 | head -20

# 如果怀疑进程隐藏,用 /proc 交叉验证
ls /proc/*/exe -l | grep deleted

如果发现某个进程的 exe 链接指向 (deleted),基本可以确定是恶意程序——正常服务不会把可执行文件删掉还在跑。

第二步:深挖进程背后的东西

假设你锁定了一个可疑 PID,比如 12345:

# 查看该进程打开的文件和网络连接
lsof -p 12345

# 查看进程的启动命令和父进程
cat /proc/12345/cmdline | tr '\0' ' '
ps -ef | grep 12345

# 查看该进程的所有线程 CPU 占用
top -Hp 12345

如果发现它连接了一个陌生的境外 IP,或者打开的是一堆 /tmp/xxx 文件,那不用怀疑,就是挖矿木马。

第三步:清除持久化后门

直接 kill 进程只是第一步,必须清理它的自启动入口:

# 检查所有用户的 crontab
for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l 2>/dev/null; done

# 检查系统级定时任务
cat /etc/crontab
ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/

# 检查 systemd 服务
systemctl list-units --type=service | grep -v systemd

# 检查 LD_PRELOAD 劫持
cat /etc/ld.so.preload

发现可疑条目后,先注释掉或删除,再 kill 进程,最后重启服务器观察。如果条件允许,重装系统是最彻底的方案,但重装前务必确认数据已备份。

第四步:如果是攻击导致的高负载

检查连接数:

# 统计 ESTABLISHED 连接来源 IP
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

如果某个 IP 连接数上百,直接封禁:

iptables -I INPUT -s 恶意IP -j DROP

同时检查 Nginx 访问日志,看看是不是被 CC 攻击了。如果是,建议上 CDN 或者配置 limit_req 限流模块。这里多说一句,选云服务器时尽量选带基础 DDoS 防护的,别等被打穿了才后悔。

第五步:如果是配置问题

PHP 站点重点看 PHP-FPM 的 pm.max_children,设太大容易把 CPU 吃满;MySQL 重点看慢查询:

# 开启慢查询日志
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2

找到慢 SQL 后加索引或优化查询,CPU 负载通常能降一半。

预防建议:别等出事再救火

  • 装个靠谱的监控:云厂商自带的监控够用,但建议再配个 netdataPrometheus,能看历史趋势,方便定位突发峰值。
  • 定期检查 crontab 和 systemd:笔者习惯每周扫一眼,花不了两分钟,能省大麻烦。
  • SSH 别用弱密码:挖矿木马九成是通过暴力破解进来的,密钥登录 + 改端口 + fail2ban 是标配。
  • 选服务器别只看价格:CPU 长期跑满的另一个隐藏原因是实例本身性能太差,共享型实例跑生产环境就是给自己找罪受。预算允许的话,直接上计算型或通用型独享实例,省下的排查时间远比差价值钱。
  • 做好快照和备份:不管是云厂商的快照还是自己 rsync,关键时刻能救命。

CPU 100% 这事,说难也难,说简单也简单。核心就一句话:先定位,再清除,最后堵住入口。最怕的是一上来就重启,把现场破坏了,问题反复出现却找不到根因。希望这篇排查指南能帮你少走弯路,下次再遇到告警,从容打开终端,一步步搞定它。

相关技术专题与延伸阅读

滚动至顶部