服务器性能莫名砍半:CPU 调频 governor 与 scaling_max_freq 排查,cpupower 持久化实战

服务器性能砍半,问题却出在「省电模式」

这是一个极其隐蔽的性能问题:你的服务器配置没变、负载没涨、磁盘和内存都正常,但某个服务就是比预期慢一倍。你查了慢查询、查了网络、查了磁盘 IO,全都正常。最后发现根因是——CPU 一直跑在最低频率上,从未进入过最高性能档。

这个问题的隐蔽性在于:它不会产生任何错误日志。top 显示的 CPU 使用率甚至可能不高(比如 40%),看起来「还有余量」,但单核性能只有标称值的一半。对于 PHP、MySQL、Nginx 这类单线程性能敏感的应用,CPU 频率降低 50% 约等于整机性能腰斩。

本文把 CPU 频率调节(CPU frequency scaling)这件事从原理到排查到调优讲清楚,重点是让你能在自己的服务器上复现判断,而不是照抄一堆参数。

先理解:Linux 为什么要动态调频

现代 x86 CPU 都支持动态频率调节。设计初衷是省电:空闲时降频降压,发热和功耗都降低,对笔记本意味着续航,对数据中心意味着电费和散热成本。

Linux 内核通过 CPUFreq 子系统管理这件事。它由三部分组成:

  • 调频驱动(scaling driver)——和硬件对话,真正去改频率。常见有 intel_pstate(Intel 现代 CPU,内置在 CPU 里的 P-state 控制)、acpi-cpufreq(传统 ACPI 接口)、amd_pstate(AMD 较新平台)。
  • 调频策略(governor)——决定「什么时候升频、什么时候降频」的算法。
  • 频率表(frequency table)——硬件支持的可用频率档位,由 scaling_available_frequencies 暴露。

问题的根源就藏在 governor 的选择上。

五种常见 governor 的性格差异

先看你的系统在用哪个:

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# 或者一次性看所有核心
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

常见的几种及其实战表现:

powersave(省电)

顾名思义,优先低频。在 intel_pstate 驱动下它的行为比较特殊——并不是死锁在最低频,而是会随负载调整,但反应迟钝、上限保守。很多云厂商的默认镜像就是它。

performance(性能)

直接锁在最高非睿频频率,不降频。这是性能敏感场景的首选。代价是功耗和发热上升,对独立服务器意味着风扇更吵、电费略高。

ondemand(按需)

负载上来就升频,空闲就降频。理论很美好,实际问题是升频有延迟:从检测到负载到频率真正拉起来通常要几十毫秒。对于「突发型」负载(比如一个 PHP 请求进来)恰恰最容易吃亏——请求处理完了频率还没升上去。

schedutil(调度器驱动)

较新的 governor,直接利用调度器的负载信号,比 ondemand 反应更快、更准。现代内核(5.x+)推荐它。

conservative(保守)

比 ondemand 更慢,升频是渐进的。基本不要用在服务器上。

结论:对个人站长的服务器,如果 CPU 不是瓶颈且很在意电费,schedutil 是平衡点;如果追求稳定可预期的性能,直接 performance。

动手排查:三分钟定位你的 CPU 有没有被降频

不要猜,用数据说话。按顺序执行下面几步。

第一步:看当前在跑什么频率

# 逐核查看当前频率(单位 kHz 或 MHz,视驱动而定)
grep MHz /proc/cpuinfo

# 更清晰的输出
for f in /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq; do
  echo -n "$(echo $f | grep -o 'cpu[0-9]*'): "
  awk '{printf "%.2f GHz\n", $1/1000000}' "$f"
done

把输出和你 CPU 的标称频率对比。如果你的 CPU 标称 3.2GHz,而 8 个核心全在 1.2GHz,那问题基本就定位了。

第二步:看可用的频率档和上限

# 硬件支持的所有档位
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies

# 当前允许的上限(可能被手动限制过!)
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq

这里有个大坑:scaling_max_freq 可能小于 cpuinfo_max_freq。前者是「当前允许的上限」,后者是「硬件硬上限」。如果 scaling_max_freq 被人为限制过(比如之前为了降温手动设过、或者云厂商的节能策略),那么即使你切到 performance governor,也不会跑到最高频。

遇到这种情况用 cpupower frequency-set 解开:

cpupower frequency-set -u 3.20GHz   # 把上限设回硬件最高
cpupower frequency-set -g performance  # 切换 governor

第三步:确认散热和功耗墙没有把频率拉下来

有时候 governor 已经是 performance、上限也是最高,但频率还是上不去——这是热限制(thermal throttling)或者功耗墙(RAPL / power limit)在起作用。

# 查看各核心温度
sensors            # 需要 apt install lm-sensors && sensors-detect

# 查看是否有节流事件计数
grep . /sys/devices/system/cpu/cpu0/thermal_throttle/*

# 查看当前的功耗限制(Intel,需要 root)
cat /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw

如果 core_throttle_count 或 package_throttle_count 持续增长,说明 CPU 正在因为过热而被强制降频。这种情况下调 governor 没用,要解决的是物理散热:机箱风道、灰尘、硅脂老化,或者 VPS 上就是邻居在抢(超售)。

在 Proxmox / KVM 环境下的额外一层

如果你的服务器上跑的是 Proxmox 或 KVM 虚拟机,主机的调频策略会直接影响虚拟机的性能,但虚拟机内部看不到真实的频率信息(虚拟机的 /proc/cpuinfo 频率是伪造的或固定值)。

这时候必须在宿主机上检查:

# 在宿主机(不是虚拟机)执行
cpupower frequency-info
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

另外虚拟机的 CPU 类型(CPU type)选择也很关键:

  • 用 host 类型可以把宿主机 CPU 的所有指令集特性透传给虚拟机,性能最好。
  • 默认的 kvm64 类型屏蔽了很多现代指令集(如 AVX2),会让某些计算密集型应用慢很多。
  • 检查命令:qm config <VMID> | grep cpu,或重启前先用 virsh dumpxml 看 <cpu mode='...'/>。

注意给虚拟机切 host 类型有两个前提:不能做实时迁移(live migration),且如果宿主机 CPU 型号不一致,虚拟机迁移会失败。单机场景可以放心用。

让配置永久生效,而不是重启就丢

直接写 /sys/devices/... 是临时的,重启就没了。三种持久化方式,按可靠性排列。

方式一:cpupower 服务(推荐)

# Debian/Ubuntu
apt install -y linux-cpupower
# 写入永久配置
sed -i 's/^GOVERNOR=.*/GOVERNOR="performance"/' /etc/default/cpupower
systemctl enable --now cpupower.service
systemctl status cpupower.service

如果 /etc/default/cpupower 里还有 MAX_FREQ、MIN_FREQ 两个变量,注意别填错——留空表示不限制,填了就会一直生效。

方式二:systemd service 自己写

有些精简镜像没有 linux-cpupower 包,或者 /etc/default/cpupower 格式不对。这时候自己写一个最小的 oneshot 服务最省事:

# /etc/systemd/system/cpu-performance.service
[Unit]
Description=Set CPU governor to performance
After=multi-user.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c 'for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do echo performance > $g; done'

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now cpu-performance.service
# 验证
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

方式三:内核启动参数

在 GRUB 里加 intel_pstate=disable(强制用 acpi-cpufreq)或者 processor.max_cstate 相关参数,效果最彻底但影响面大,改错了可能开不了机。除非上面两种方式都无效,否则不建议动。

调完之后,用数据确认真的变快了

不要凭感觉。改之前和改之后各跑一次基准测试,用数字对比。

# 单核性能(最能体现频率差异)
sysbench cpu --cpu-max-prime=20000 --threads=1 run

# 多核
sysbench cpu --cpu-max-prime=20000 --threads=$(nproc) run

# 顺便看下实时频率变化
watch -n1 'grep MHz /proc/cpuinfo | head -4'

重点关注 events per second 这一项。如果切到 performance 之后这个数字提升了 30% 以上,说明之前的降频确实拖累了性能。

还要做一次真实业务验证:用 ab 或 wrk 压一下你的 Web 服务,看 QPS 和 P99 延迟的变化。基准测试好看但业务没变快,说明瓶颈其实不在 CPU。

在什么情况下不该盲目切 performance

看到这里可能有人想去把所有服务器都改成 performance。先冷静一下,有几种情况要慎重:

  • VPS 且 CPU 严重超售:你切 performance,但物理 CPU 是共享的,效果可能很有限,还可能因为跑满独占时间片引来邻居投诉(或者被云厂商限制)。
  • 散热余量不足的廉价独服:长期满频运行会导致 CPU 温度直奔 90°C+,触发更严重的降频,反而比 powersave 更慢。先测温度再决定。
  • 7×24 低负载的静态站:CPU 大部分时间空闲,performance 只是白白耗电。这种情况 schedutil 才是正解。
  • 笔记本或小主机做服务器:散热和电池都是问题,建议 schedutil 而非 performance。

一个实用的折中:用 schedutil 作为日常,然后针对真正性能敏感的进程做定向优化——比如给 PHP-FPM 主进程用 cgroup 提高 CPU 权重,或者把 CPU 亲和性(CPU affinity)绑定到固定核心,避免频繁迁移带来的缓存失效。

# 把某个进程绑定到 2-3 号核心
taskset -cp 2-3 $(pgrep -f 'php-fpm: master')

# 查看当前进程的亲和性
taskset -cp $(pgrep -f 'php-fpm: master')

常见问题解答

Q:为什么云服务器的 /proc/cpuinfo 频率永远不变?

A:虚拟机的频率信息通常是伪造的固定值,宿主机才是真实的。想大致判断虚拟机被限速的情况,只能用基准测试横向对比,或者看宿主机。很多云厂商还会用 cgroup 的 CPU quota 限速,这在虚拟机内部表现为「CPU 使用率到某个值就上不去了」,和频率无关但现象相似。

Q:切了 performance 之后 top 里的 CPU 百分比反而降低了,是变慢了吗?

A:这是正常现象。频率提高后,处理同样的工作量需要的 CPU 时间变少了,所以使用率百分比会下降。判断性能要看绝对指标(响应时间、QPS),不能看使用率。

Q:cpupower frequency-info 显示驱动是 intel_pstate,但 governor 列表里没有 ondemand,怎么办?

A:intel_pstate 驱动只支持 powersave 和 performance 两个 governor(较新内核还支持 schedutil 的 active 模式)。想用传统的 ondemand 系列需要加内核参数 intel_pstate=disable 切回 acpi-cpufreq,一般没必要。

Q:改完之后网站没变快,还有什么可能?

A:说明瓶颈不在 CPU。按顺序排查:磁盘 IO(iostat -x 1 看 %util 和 await)、内存是否在换页(vmstat 1 看 si/so 是否非零)、数据库慢查询、外部 API 响应时间、CDN 回源延迟。CPU 频率只是众多因素之一,不要因为它是「冷门知识点」就认定它是根因。

小结

CPU 调频是一个典型的「配置正确但状态不对」类问题:所有东西看起来都正常,性能却莫名其妙打折。排查顺序可以固化为:

  • 看当前频率 → 和标称对比
  • 看 scaling_max_freq → 是否被限制
  • 看 governor → 是否是 powersave/conservative
  • 看节流计数和温度 → 是否散热限制
  • 虚拟机场景 → 回到宿主机看,并检查 CPU type
  • 改完用 sysbench 和真实压测验证

整个过程不需要装什么复杂工具,靠 /sys/devices/system/cpu/ 下的文件就能完成全部诊断。把这套流程记下来,下次遇到「配置没变但变慢了」的时候,多一个可以快速排除的维度。

Last modification:September 29th, 2026 at 10:23 pm

Leave a Comment