
凌晨两点收到告警登录上去第一反应往往是top一把梭看到 %Cpu 飙红就准备重启。先别急。服务器CPU 到底是被谁吃满了、是真算力不够还是被 IO 拖累这两件事的处理方式完全不同分不清就重启大概率半小时后又告警。这篇文章把CPU 打满这件事拆成四步先定性再定位进程再钻到进程内部最后才是止血还是扩容。每一步都给可照做的命令也标出几个容易误判的坑。一、先定性你看到的CPU 高到底是哪一种top第一行那行%Cpu(s)是整台机器最该先看懂的地方它把时间切成了八块us用户态时间应用代码在跑大部分 CPU 消耗落在这里sy系统态时间内核在干活系统调用、中断、调度ni被降过优先级的进程占的时间id完全空闲waiowaitCPU 其实闲着在等磁盘或网络 IO 完成hi/si硬件 / 软件中断ststeal time只出现在虚拟机里是宿主机把本该给你的 CPU 周期给了别的租户关键判断就三条us高、id低 → 应用真的在吃算力往下走定位进程那条线。wa高、us低 → 不是 CPU 的锅是存储或网络 IO 瓶颈top里%wa冒红就别去加 CPU先查磁盘和慢查询。st高 → 你是虚拟机且宿主机超卖了本地再怎么调优也绕不开这层限制只能找厂商换规格或换宿主机。还有一个常被误读的指标load average平均负载。它显示的三个数1 分钟 / 5 分钟 / 15 分钟统计的是可运行态R 不可中断睡眠态D的进程数D 状态基本就是卡在 IO 上的进程。所以一台机器 load 飙到 20、但%Cpu的id还有 70%很可能只是磁盘慢CPU 自己闲着。判断 CPU 是否真饱和别只看 load要看vmstat 1的输出vmstat1# procs ---- r b ---- cpu --- us sy id wa st# r b swpd free buff cache si so bi bo in cs us sy id wa st# 8 2 0 120000 0 800000 0 0 40 120 300 900 85 5 2 5 3r是运行队列长度b是卡在 D 状态的进程数us/sy/id/wa/st对应上面那八块。对照nproc出来的核数——r长期大于核数才是真的排队等 CPUb长期很大则是 IO 在堵。一个真实的误判案例某次告警 load 冲到 15新人直接申请扩容结果top里%id还有 60%、%wa到了 35%——根因是一块云盘 IO 被打满MySQL 在等磁盘CPU 根本没饱和。机器加上去IO 还是瓶颈问题照旧。这就是为什么要先看完那八个数再决定动作。还有一层容易坑人的是容器。在 Docker / K8s 容器里直接跑top或nproc经常看到的是宿主机的核数而不是这个容器被分配到的限额。要看容器真正能用多少 CPU得读 cgroup 的配额文件/sys/fs/cgroup/cpu/cpu.cfs_quota_us和cpu.cfs_period_us两者相除才是该容器允许使用的核数。监控指标也要以容器内采集的为准否则你会以为 CPU 很闲其实早被隔壁容器挤占了。顺带提一句服务器cpu温度如果机房空调出问题或风扇故障CPU 会因为过热降频thermal throttle表现出来就是没干重活却变慢这种用sensors或带外管理的温度接口能看到属于另一种独立的排查线别和算力瓶颈混为一谈。二、定位进程top、htop 与 pidstat定性完了确认是us真高下一步把谁在吃揪出来。top默认就按%CPU从高到低排进去后按P可以再强制按 CPU 排一次确认htop更直观按F6选CPU%排序还能看到每个核的占用条。找到可疑 PID 后光看%CPU不够还要看它是单线程打满一个核总利用率不高但那个核 100%还是多线程铺满所有核。要看每核明细用mpstat -P ALL 1来自 sysstat 包单核 100%、其他核闲着说明程序没做好并行加核没用得改代码或加进程数。想要更干净的进程级采样用pidstatpidstat-u1# 每 1 秒刷新各进程 CPU 占用pidstat-u-p12341# 只盯某个 PIDpidstat的好处是能跨采样窗口稳定输出方便你贴进值班记录。顺带提一句linux服务器查看cpu使用率和 linux服务器cpu使用率查看命令网上搜出来大多是top/htop/mpstat这三板斧记住它们各管一层就够了。想知道整机规模如何查看服务器的内存和cpu参数可以从nproc和lscpu入手前者看在线逻辑核数后者看架构、型号和缓存。三、钻进进程内部不同语言各有各的刀锁定到 PID 只是半路真正要知道它在算什么得再往里钻否则你只知道MySQL 很忙不知道它在跑哪条烂 SQL。Java 服务最省事的是 async-profiler挂上就能采 CPU 火焰图./profiler.sh startpid# 跑个几十秒./profiler.sh stop-fflamegraph.svgpid打开 svg横着最宽的那一层函数就是吃 CPU 的大头照着去优化那一段比盲猜强十倍。C / C / 系统层perf top直接看实时热点函数要留档就用perf record -F 99 -p pid -g -- sleep 30再perf report不需要改代码、不需要重启。MySQLSHOW PROCESSLIST;看Time、State、Info三列Time 很大且 State 卡在Sending data或Locked的基本就是慢查询或锁等待再去翻慢查询日志slow log拿完整 SQL。PHP-FPM开slowlog超时的请求会把调用栈写进去常见于某段同步远程调用或正则回溯爆炸。Java 退出也有讲究顺带说一句止血。对 JVM 这类进程优先发kill -15而不是-9——-15会触发 shutdown hook让连接池、线程池有序关闭、把内存里的数据刷盘-9是直接剥夺进程没机会做清理重启后可能要更长的时间做恢复或校验。通用兜底strace -p pid -c统计这个进程在调哪些系统调用如果满屏是futex多半是锁竞争满屏是read/write多半是 IO。这一层的意义在于服务器cpu使用率过高怎么解决答案从来不在重启或加机器而在到底是哪一行代码 / 哪一条 SQL。定位不到这一层扩容只是把问题变得更贵。四、止血与根治kill -9 不是万能药临时要保住线上有几招比直接杀进程温和renice 10 -p pid把问题进程优先级调低让它少抢 CPU给核心业务让路。用 systemd 的CPUQuota或 cgroup 给这个服务设 CPU 上限防止它把整台机器拖死# /etc/systemd/system/xxx.service.d/limit.conf [Service] CPUQuota50%业务侧限流、降级非核心功能把峰值削平。至于kill -9有两个坑必须知道一是D 状态不可中断睡眠的进程kill -9也杀不掉因为它在等硬件事件比如一块卡死的 nfs 挂载得先解决底层 IO二是数据库、消息队列这类有状态的进程强杀主进程可能导致数据不一致或恢复缓慢能kill -15SIGTERM让它自己收尾就别用-9。根治的方向就三类算法或 SQL 优化、加缓存减少重复计算、把同步改成异步或分片。止血能救今晚根治才不用来回加班。五、该扩容时怎么选 vCPU云服务器的 4 核是真 4 核吗前面都是够不够用、哪里不够如果确认就是长期算力不足要加机器这里有个选型章节值得单独说。很多人纠结云服务器4核cpu是真4核还是假4核——准确说云服务器的 vCPU 一般是物理 CPU 的超线程切出来的逻辑核且同一颗物理核由多个租户共享这点从上面top里的%ststeal time就能感觉到邻居一忙你的st就涨。所以它不是你独占的物理核但对绝大多数业务来说按 vCPU 数规划和按物理核规划在容量上是对等的重点看的是vCPU 数量与基准性能 / 突发性能是否匹配你的常驻负载突发型实例的CPU 积分机制闲时攒、忙时花持续高负载会掉速是否需要独享型 / 裸金属来规避超卖带来的st抖动。各家实例规格的命名和 vCPU 映射都写在官方文档里选型前建议直接翻三家对照而不是只看某一家的宣传阿里云 ECS 实例规格族说明阿里云 ECS 实例规格腾讯云 CVM 实例规格腾讯云 CVM 实例类型华为云 ECS 实例规格华为云 ECS 实例规格三家虽然命名不同阿里云叫实例规格族、腾讯云叫实例类型、华为云也叫实例规格但底层都是把物理 CPU 通过虚拟化切分成 vCPU 提供给租户。选购时真正要对比的是这台实例能给到多少稳定算力和对应的计费模型而不是名字好不好听。突发型适合平时闲、偶尔冲一波的业务独享型 / 裸金属适合对st抖动零容忍的稳态负载。如果业务是短时、波峰波谷明显弹性伸缩比租一台固定的 cpu服务器 更划算如果是稳态高负载且对st敏感独享型或裸金属更稳。另外别把 gpu服务器与cpu服务器的区别 搞混普通 Web、数据库靠的是 CPU 通用算力只有 AI 推理、训练、图像渲染这类并行计算才需要 GPU两者选型维度不同别一上来就堆 GPU。六、收个尾CPU 打满这件事链路其实很清晰先定性us / wa / st 分清再定位进程top / pidstat / mpstat再钻进程内部火焰图 / 慢查询 / slowlog最后才是止血或扩容。把这套走完你解决的就不只是这次为什么慢而是真的知道瓶颈长什么样。文中涉及的各家实例规格、vCPU 映射、计费与配额政策以厂商当期官方公示为准扩容前请到对应控制台核实当期配置与价格再决定是弹性扩容还是换独享规格。