服务器越跑越慢但 CPU 不高:从 CPU 降频、温度到 steal time 的硬件层性能诊断实战

服务器为什么"越跑越慢",而 CPU 占用看着却不高

很多站长都遇到过一个诡异现象:服务器刚上线时一切正常,跑了一段时间后,某些操作开始变慢——数据库查询偶尔卡顿、编译或备份时间变长、SSH 敲命令有明显的停顿感。登上去一看,top 里 CPU 占用不高,内存也还有余量,磁盘 df 更是离写满还远。于是无从下手。

这种情况里,有一个非常常见却被忽视的原因:CPU 因为过热而降低了运行频率。当散热跟不上、机箱风道被堵、或者机房温度偏高时,CPU 会自动降频来保护自己。降频是保护机制,不是故障,但它会让整机性能"无声地打折"——CPU 占用率看起来一样,实际每秒干的活却少了一截。本文讲的就是如何用 Linux 自带的工具,把这类"看不见的硬件层性能损失"查出来。

第一层:看 CPU 当前实际跑在什么频率

先别急着装任何工具。/proc/cpuinfo 里就有当前频率:

grep -m1 "model name" /proc/cpuinfo
grep "cpu MHz" /proc/cpuinfo

每条 cpu MHz 对应一个逻辑核心的当前频率。如果你看到所有核心都稳定在标称频率的一半甚至更低,而且此时系统并不空闲,那就值得警惕。但这个数字是瞬时值,会跳动,最好多看几次、或者在压测时看。

更规范的做法是用 cpupower(来自 linux-cpupower 包):

apt install -y linux-cpupower
cpupower frequency-info

输出里的关键几行是:driver(驱动,比如 intel_pstate 或 acpi-cpufreq)、current policy(当前的 governor、频率上下限)、current CPU frequency。你要特别关注"频率上界"这一项——如果它被设成了远低于 CPU 标称最大频率的值,那性能就被硬性限制住了。常见于云服务器厂商为了控制功耗而设的 scaling_max_freq,也常见于你自己或某个调优脚本改过之后忘了改回来。

第二层:读懂 governor 决定"什么时候升频"

CPU 频率不是恒定的,它由 governor(调频器) 决定在什么负载下升到多高。几种常见取值:

  • performance:直接锁在最高频。"性能最好、最费电、最容易热"。
  • powersave:尽量待在低频,按需缓慢升频。省电但可能"跟不上"突发负载。
  • ondemand / schedutil:按负载动态调整,是最常见的默认值。
  • conservative:比 ondemand 更保守地升频,升得慢。

查看与切换:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

如果默认是 powersave 或某个偏保守的策略,而你的服务器是"常年有稳定负载"的类型(比如跑着网站、数据库),那么临时切成 performance 往往能明显改善响应速度:

cpupower frequency-set -g performance

但这个改动重启就丢。要持久化,不能只改 /sys(那是内核暴露的运行时接口,写进去只是临时的)。正确做法有两条路:

# 路线一:安装 cpufrequtils 并用其配置文件
apt install -y cpufrequtils
echo 'GOVERNOR="performance"' > /etc/default/cpufrequtils
systemctl restart cpufrequtils
# 路线二:systemd 服务在开机时下发
# 写一个 unit,ExecStart=cpupower frequency-set -g performance

这里要强调一个判断原则:不要无条件把 governor 设成 performance。云服务器上,很多实例的 CPU 是共享的,你锁死最高频并不一定能拿到更多物理 CPU,反而可能因为功耗和散热策略触发更严重的降频。正确做法是先测——在改之前和改之后各跑一次同样的负载,用 cpupower frequency-info 的实时频率 + 实际任务耗时来对比,用数据决定,而不是凭感觉。

第三层:用 lm-sensors 读出温度与风扇

频率问题的根子往往是温度。要读温度,最通用的是 lm-sensors:

apt install -y lm-sensors
sensors-detect    # 一路回车,探测本机的传感器芯片
sensors

sensors-detect 会把探测到的内核模块名写进 /etc/modules-load.d/ 或 /etc/modules,这样重启后还能加载。sensors 的输出会列出若干组温度,常见的有:

  • Package id 0 或 Core X:CPU 各核心温度,最常见的判据。触到接近 high/crit 阈值就说明散热有问题。
  • fan1、fan2:风扇转速(RPM)。如果某路 fan 显示为 0 或 N/A,可能是风扇没转、线没接、或该通道没接传感器——对物理服务器值得排查。
  • in0 等电压:一般不用管,除非你怀疑供电问题。

虚拟机的坑:大多数云 VPS 里 sensors 读不到真实温度,因为虚拟化层不向客户机暴露物理传感器。你会看到 sensors-detect 说没找到任何芯片,或者 sensors 输出为空。这不是工具坏了,是环境限制。云上的"硬件层监控"要靠厂商提供的控制台或 API(有的提供 CPU 积分/超限信息),而不是 lm-sensors。

看内核有没有"主动降频"的痕迹

除了温度,内核还可能因为其他原因限制频率。这些信息都在 dmesg / journald 的内核日志里:

dmesg | grep -i -E "thermal|throttl|temperature|microcode"
journalctl -k --since "1 hour ago" | grep -i -E "thermal|throttl"

几个关键词的含义要分清:

  • CPU0: Core temperature above threshold, cpu clock throttled:字面意思是"温度超阈值,CPU 时钟被节流"——这是最直接的过热降频证据。
  • thermal 相关的其他提示:说明触发了温度管理策略。
  • mce(Machine Check Exception)或 microcode 更新日志:硬件层的纠错事件,如果频发要留意 CPU 或内存是否真的有硬件问题。

如果你看到 clock throttled 这类日志,基本可以确定性能损失来自硬件层。接下来的动作是:检查机箱/机房散热、清灰、确认风扇正常、必要时申请换机房或加散热。这类问题的根治在物理层面,软件再怎么调都只是缓解。

区分"降频"和"被限制":两件不同的事

排查时一定要把两个概念分开,否则会走错方向:

  1. 降频(throttling):CPU 本来能跑高频,但因为过热/功耗被动态压下来。特征是频率忽高忽低、伴随温度日志。解决方向:散热、环境温度。
  2. 频率限制(capping):scaling_max_freq 被设成了一个较低的固定值,CPU"永远到不了高频"。特征是频率稳定地卡在一个上限、也没有过热日志。解决方向:改回或调整 scaling_max_freq、检查是谁设的。

判断方法:如果 cpupower frequency-info 里 hardware limits 显示的最大频率远高于 current policy 的 max,那就是被软件限住了(属于第二种);如果两个上限一致、但当前频率经常掉下来且伴随高温,那就是降频(第一种)。把这一条搞清楚,能替你省下大量瞎调参数的时间。

虚拟化环境下的额外变量

在 KVM/云主机里,还有几个特有的坑:

  • CPU 型号被伪装:宿主机可能把 model name 伪造成一个通用型号("Intel Xeon"之类的泛化名),/proc/cpuinfo 看到的频率也不一定真实。别把这里的数字当成物理真相。
  • CPU steal time:这是虚拟化最该看的指标,表示"你的 vCPU 想跑但被宿主机调度走了"的时间占比。用 top 看 %st,或者 mpstat -P ALL 1 看 %steal。steal 持续偏高(比如 >5%)说明你的机器在同宿主机上被邻居抢了资源,这比降频更能解释"CPU 不高但就是慢"。这时候唯一有效的动作是联系厂商换机器/升配,调 governor 没用。
  • CPU 积分/突发(burstable 实例):一些便宜的 VPS 采用"积分制"——平时攒积分,需要时消耗积分来突发。积分用完就被压回基线性能。这种"忽快忽慢"也常被误当成降频。看厂商控制台的积分面板,或 cpupower frequency-info 之外的厂商 API 才能确认。

把监控做成常态,而不是出事了才查

上面讲的都是"事后排查"。真正省心的做法,是把关键指标做成定期采集、留下历史、能看趋势,而不是等性能出问题才临时登机器看一眼。对个人站长来说,不需要上 Prometheus 那一套重家伙,用最容易落地的办法就够了:

  1. 定时采样温度与频率:一条 cron,每小时把 sensors 和 cpupower frequency-info 的关键行追加到一个日志文件,配上日期。跑一周后你就有了一条温度曲线,能看出"是不是下午机房升温就掉频"这种规律。
  2. 记录 steal time 趋势:把 mpstat -P ALL 1 1 的 %steal 列也采下来。如果它随时间缓慢上升,说明宿主机在变拥挤,是换机器或升配的明确信号。
  3. 给阈值配告警:温度超过某个值、频率持续低于某个值、steal 超过 5%,都值得触发一次通知(邮件、TG bot 都行)。告警的意义是让你在问题还小的时候就介入。

这套东西不复杂,但它把"靠感觉"变成了"看数据"。运维里最贵的成本从来不是工具,而是"我不知道机器正在变坏"这种信息盲区。哪怕只是三个每小时的采样点,坚持积累就足以让判断有据可依。

一份可直接照做的排查清单

  1. grep "cpu MHz" /proc/cpuinfo 看当前频率,空闲时是否异常偏低。
  2. cpupower frequency-info 对比 hardware limits 与 current policy 的 max,判断是"降频"还是"被限频"。
  3. cat scaling_governor 看调频策略,决定是否切换(先测后改)。
  4. sensors 看温度与风扇(物理机);云机跳过此项。
  5. dmesg | grep -i "throttl\|thermal" 找过热降频的直接证据。
  6. top 里的 %st 或 mpstat 的 %steal,排查虚拟化资源被抢。
  7. 改完 governor/max_freq 后一定要持久化(cpufrequtils 配置或 systemd unit),并重跑一次负载对比数据。

最后提醒一句:硬件层性能问题,软件只能"诊断"和"缓解",不能"治愈"。如果确认是散热或宿主机争抢导致的,该做的是换环境——把时间花在真正能解决的层面,比在 /sys 里反复折腾参数划算得多。

Last modification:October 7th, 2026 at 08:24 pm

Leave a Comment