属于大家的
VPS知识分享站

云服务器 CPU 100% 排查:7 步定位到慢查询

先说结论:CPU 100% 只是症状,先分清是用户态算得太多、系统态在忙、IO 等待,还是被宿主机偷走了(steal)。再看是哪个进程、哪个线程、哪条 SQL 或哪个外部依赖,最后才决定限流、降级、扩容还是修代码。上来就重启,通常只能好十分钟。

先看四个数,别急着翻日志:

  • us:用户态占用,业务代码、PHP、Java、Python 在算
  • sy:系统态占用,频繁系统调用、网络包、上下文切换
  • wa:IO 等待,磁盘或网络存储慢
  • st:steal,宿主机把 CPU 分给了别人,虚拟机在排队

四个数的组合,基本能判断方向。下面按“定位进程 → 定位线程 → 看业务 → 应急 → 长期优化”讲。

进程树中一个红色高负载进程节点
先找进程,再看线程栈;陌生进程要按入侵排查处理。

第一步:看整体

top
# 看 %Cpu(s) 行的 us/sy/wa/st
uptime
# load average 和 CPU 核数对比
vmstat 1 5
# r 列(运行队列)、wa、st

load average 高于核数不一定有问题,要看 r 队列和 wa。如果 wa 高,CPU 其实在等磁盘;如果 st 高,说明邻居在抢,先找服务商,不是你代码的问题。

第二步:找进程

ps aux --sort=-%cpu | head -20
pidstat -u 1 5
# 看是哪个进程持续吃 CPU

找到进程后,先确认它是不是你认识的:路径、启动参数、启动用户、最近有没有发布。陌生进程、路径在 /tmp 或 /dev/shm、名字伪装成系统进程,要按入侵排查处理。

第三步:看线程和调用栈

top -H -p <pid>
# 找到最热的线程 ID,转成十六进制
printf '%x\n' <tid>

# Java
jstack <pid> > /tmp/threads.txt
# PHP-FPM 看 slow log 和 status
# Node 看 event loop lag 和 CPU profile
# 通用
perf top -p <pid>

Java 线程栈里大量线程卡在同一段代码,通常是死循环、锁竞争或正则回溯;PHP-FPM 看 slow log 里反复出现的脚本;Node 单线程被同步计算阻塞,event loop lag 会飙升。

第四步:区分正常高峰和异常

  • QPS 是否同步上涨:涨了且响应正常,是容量问题;没涨但 CPU 高,是代码或依赖问题
  • 慢查询是否增加:数据库慢会拖高应用 CPU(重试、序列化、日志)
  • 外部 API 是否变慢:超时重试会放大 CPU 和连接数
  • 缓存是否失效:缓存击穿会让请求全部落到数据库和应用
# MySQL
SHOW FULL PROCESSLIST;
SHOW ENGINE INNODB STATUS;
# Redis
SLOWLOG GET 20
一条发光的数据库查询卡在队列中
CPU 高不一定是算得多,也可能是在等慢查询和重试。

第五步:常见原因

  1. 死循环/正则回溯:某个输入触发,CPU 单核跑满
  2. 慢 SQL:没索引、全表扫描、排序临时表
  3. 缓存击穿:热点 key 过期,请求全打到数据库
  4. 外部依赖重试:超时后无限重试,雪崩
  5. 定时任务/备份:压缩、导出、全量同步在高峰期跑
  6. 挖矿/恶意脚本:陌生进程持续吃满,伴随异常外联
  7. 超售/邻居:steal 高,机器本身没问题

第六步:应急处理

  1. 先限流或降级非核心接口,保住核心链路
  2. 重启单个 worker 或 FPM pool,不要直接 reboot
  3. 把定时任务、备份、导出挪到低峰
  4. 扩容或加副本,注意数据库连接数上限
  5. 保留现场:top、线程栈、慢日志、错误日志

顺序是“先止损,再定位”。重启只能争取时间,根因不解决还会复发。

第七步:长期优化

  • 慢查询治理:加索引、拆分大查询、避免 N+1
  • 缓存分层:CDN、页面、对象、数据库
  • 异步化:把导出、图片、AI 调用放队列
  • 限流和熔断:按接口设阈值,外部调用设短超时
  • 容量规划:按峰值 QPS 和单机拐点扩容
  • 监控:CPU、load、wa、st、慢查询、5xx 一起看
负载均衡后面的多个服务器节点,其中一个过热
扩容前先确认瓶颈是单机热点还是整体容量。

还有一种情况:CPU 高但业务看起来正常。先看是不是监控 agent、日志采集、备份压缩、病毒扫描在跑;这些任务通常在凌晨或整点触发,容易和业务高峰重叠。把它们挪到低峰,或者限制 CPU 和 IO 优先级,往往比扩容有效。

另外,CPU 100% 不等于用户体验一定差。如果请求队列没堆积、p95 正常,说明机器在满负荷但还能服务;这时候要做的是加余量,而不是慌着重启。看 r 队列、p95 和错误率,比看单个 CPU 数字可靠。

还有一种常见误判:把“CPU 100%”当成“CPU 不够”。如果单核被打满、其他核空闲,问题在单线程代码或锁,不在核数;这时候加核没用,要做的是把任务拆并行或优化算法。反过来,所有核都满且 QPS 同步上涨,才是真的容量不够。

日志和监控自己也会吃 CPU。访问日志太大、日志采集 agent 频繁刷盘、监控每秒抓一次全量指标,都会在高峰期放大开销。把采样频率和日志级别调低,往往能回收一部分 CPU。

最后提醒一句:排查前先记录时间点和数值,别一边查一边忘,事后复盘没有基线。

常见问题 FAQ

Q1:CPU 100% 一定要重启吗?

不一定。先看是哪个进程、哪个线程。重启只能短暂恢复,死循环和慢 SQL 还会再来。

Q2:load 高但 CPU 不高,是什么原因?

多半是 IO 等待或大量不可中断进程。看 wa、iostat 和磁盘延迟,不要只盯 CPU。

Q3:steal 高怎么办?

说明宿主机资源争抢。先记录时段和数值,找服务商确认;长期跑生产建议换独享或低超售的机型。

Q4:PHP-FPM 占满 CPU 怎么查?

开 slow log 和 status,看哪个脚本慢、哪个接口打满;再结合 Nginx 访问日志定位请求。

Q5:要不要直接升配?

如果是容量问题,升配有效;如果是代码死循环或慢查询,升配只是把问题推迟。先定位再决定。

总结

CPU 100% 的排查顺序是:看 us/sy/wa/st → 找进程 → 看线程栈 → 对照 QPS 和慢查询 → 应急止损 → 长期优化。先分清是算得多、等得久,还是被邻居抢,再决定动哪里。

如果排查下来是机器容量或超售问题,可以按小时开一台萤光云香港 CN2 VPS 做对照测试,确认瓶颈再决定长期配置。

相关推荐

赞(0)
未经允许不得转载:VPS知识分享站 » 云服务器 CPU 100% 排查:7 步定位到慢查询