如何在香港服务器上通过BIOS与操作系统联合调优,提升Intel Xeon Scalable平台整体性能?

01:20(HKT),葵涌机房 A 排 12 号柜。冷通道温度 24.6℃,风速 2.3m/s。
Grafana 从 00:47 起持续告警:web_p99_latency > 40ms,Redis 的 GET p99 偶发拉到 3.9ms。业务没发版,网络抖动也排除(上联 10G 双活正常)。
我连上这台 Supermicro SYS-1029U 的 IPMI,看板信息:BIOS 3.4a (2023-09-21),CPU 是 Xeon Gold 6230R ×2,内存 12×32GB 2933。目标很明确:把 BIOS 和 OS 里的电源、C-State、IRQ 亲和这些基础项对齐,先把尾延迟压住,再谈吞吐。下面是我这次从基线测起、一步步落到参数和脚本的完整过程。
场景与目标
业务画像
主要工作负载:Nginx + PHP-FPM(长连接,TLS)、Redis(小 key 高频)、部分 MySQL(OLTP),配合一台专门做日志与对象缓存的节点。
目标:
- 降低 p99 延迟(Web/Redis);
- 提升吞吐(Nginx RPS、NVMe 随机读);
- 不牺牲稳定性(24/7,远程维护为主)。
硬件与系统(本次实测样例)
| 组件 | 规格 |
|---|---|
| 机型 | Supermicro SYS-1029U(1U) |
| CPU | Intel Xeon Gold 6230R ×2(Cascade Lake,26C/52T,2.1GHz Base,Turbo 4.0GHz) |
| 内存 | 12×32GB DDR4-2933,六通道/CPU,满插对称 |
| 存储 | 2× Intel P4510 2TB NVMe(系统/日志),2× Samsung PM9A3 3.84TB NVMe(数据) |
| 网卡 | Intel X710-DA2(10GbE,驱动 i40e) |
| OS | CentOS 7.9(3.10 内核),ext4/xfs 混用 |
| 交换/路由 | 上联双 10G,BGP 跨运营商,RTT 内地北上广 25~45ms |
说明:你也许是 HPE/Dell 平台、Ice Lake/Sapphire Rapids 或者 X722/XL710/ICE 驱动,思路一致;少量开关名字不同,文中给到“常见同义项”。
方法论:先测准,再下刀
1.建立基线(出厂/默认)
- CPU:sysbench cpu、turbostat
- 内存:stream(可选)
- 磁盘:fio(4k randread/randwrite,QD 32,8 jobs)
- 网络:iperf3(10G 双向)
- 应用:wrk 压测 Nginx、redis-benchmark、MySQL sysbench oltp
2.只改一层(先 BIOS 后 OS):每次更动一个维度,观察收益/副作用。
3.回归验证:冷热数据、峰值/低谷时段各测一次。
4.记录:凡是“动过”的,都写到变更单和运维脚本。
后文,按BIOS → OS → 验证数据 → 常见坑的顺序展开。
第一刀:BIOS 调优(让硬件“别扯你后腿”)
不同厂商 BIOS 菜单路径略有差异,关键词基本一致;下表列出了我最常用的组合及其适配场景。
1) 电源与频率
| 项 | 建议设置 | 说明/同义项 |
|---|---|---|
| Power Policy | Performance(或 OS Controlled + High Performance) | Dell: Performance; HPE: Static High Perf |
| Intel Turbo Boost | Enable | Turbo 不开,等于主动放弃单核峰值 |
| Intel Speed Shift/EIST | Enable | 更快的 P-state 调度,低抖动 |
| CPU C-States | Limited 到 C1/C1E 或 Disable 深 C | 低延迟场景禁深 C;吞吐/节能可保留 C1E |
| Package C-State | C0/C1 | 同上 |
2) 超线程与隔离
| 项 | 建议设置 | 说明 |
|---|---|---|
| Hyper-Threading | 按场景决定 | 低延迟+抖动敏感(Redis/撮合)可关;高吞吐(Nginx/压缩)常开 |
我这台:Redis 节点关 HT,Web 节点开 HT。理由:Redis 命中率高、锁竞争明显,HT 可能带来尾延迟上升。
3) 内存与 NUMA/缓存
| 项 | 建议设置 | 说明/同义项 |
|---|---|---|
| NUMA Node Interleaving | Disabled | 保持 NUMA 可见性(配合绑核/绑内存) |
| Sub-NUMA Clustering(SNC) | 按代际与负载:Ice Lake/SPR + NUMA 友好 → Enable;否则 Disable | 提升 LLC 命中、降低跨环延迟 |
| Memory Interleaving | Channel Interleaving 默认 | 确保对称插条与带宽利用 |
| Hardware Prefetcher | Enable | |
| Adjacent Cache Line Prefetch | Enable | |
| DCU Streamer / IP Prefetch | Disable 或试验 | 对随机小对象(Redis)有时关更稳 |
| LLC Dead Line Alloc | Disable | 降低 cache 污染(依厂商不同) |
4) UPI/QPI 与 IIO
| 项 | 建议设置 | 说明 |
|---|---|---|
| UPI Link Speed | Max Performance | |
| I/O Non-Posted Prefetch | Enable | 提升 PCIe/NVMe 流水效率(平台相关) |
| SR-IOV | Enable | 需要虚拟化/容器直通时 |
5) 启动与微码
保持 最新稳定 BIOS/微码(与 OS 版本兼容),避免频繁热补丁导致的性能波动。
记录:版本号 + 变更窗口。
实操提示:
- 批量改 BIOS:Supermicro 可用 SUM/IPMI;Dell 用 racadm;HPE 用 iLO 脚本。
- 任何“看不懂”的开关,只动一个,做对照实验再定。
第二刀:操作系统调优(把内核与中断“拎清楚”)
以下以 CentOS 7.9 为例。
基础工具
yum install -y epel-release
yum install -y tuned tuned-utils kernel-tools numactl pciutils ethtool irqbalance \
fio sysstat perf iperf3 jq jq-devel hwloc
systemctl enable --now tuned
1) GRUB 内核参数(统一入口)
编辑 /etc/default/grub 的 GRUB_CMDLINE_LINUX,常用组合:
GRUB_CMDLINE_LINUX="crashkernel=auto intel_iommu=on iommu=pt \
intel_pstate=enable processor.max_cstate=1 intel_idle.max_cstate=1 \
transparent_hugepage=never \
audit=0 spectre_v2=on nopti=0 mds=full nosmt=0 \
numa_balancing=disable \
rcu_nocbs=2-51 nohz_full=2-51 isolcpus=managed,2-51 irqaffinity=0-1"
- C-State 限制:processor.max_cstate=1、intel_idle.max_cstate=1 与 BIOS 对齐。
- THP:transparent_hugepage=never(低延迟);数据库类可换 madvise。
- 隔离核:将 2-51 作为应用核,0-1 留给内核/中断(按你实际核数调整)。
- 安全补丁:上面例子保留了漏洞缓解;仅在受控压测时才会尝试 mitigations=off,生产请遵从安全基线。
更新并重启:
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot
2) tuned 自定义性能模板
创建 /etc/tuned/xeon-perf/tuned.conf:
[main]
summary=Intel Xeon Scalable performance profile (HK DC)
include=throughput-performance
[cpu]
governor=performance
energy_perf_bias=performance
force_latency=1
[vm]
transparent_hugepages=never
hugepages=0
swappiness=1
dirty_ratio=10
dirty_background_ratio=3
zone_reclaim_mode=0
[disk]
readahead=4096
[net]
txqueuelen=4096
[sysctl]
kernel.numa_balancing=0
net.core.rmem_max=134217728
net.core.wmem_max=134217728
net.core.netdev_max_backlog=250000
net.ipv4.tcp_rmem="4096 87380 134217728"
net.ipv4.tcp_wmem="4096 65536 134217728"
net.ipv4.tcp_mtu_probing=1
net.ipv4.tcp_sack=1
net.ipv4.tcp_timestamps=0
net.core.somaxconn=65535
fs.file-max=2097152
vm.max_map_count=262144
启用:
tuned-adm profile xeon-perf
tuned-adm active
3) CPU 频率与涡轮观测
cpupower frequency-info
turbostat --Summary --interval 5
确保 governor 为 performance,Turbo 活跃。
4) IRQ 与队列亲和(网络/NVMe)
思路:
把高频中断(NIC/NVMe)绑到特定物理核,避开你的业务线程。
HT 开启时,保证同一物理核的两个超线程不要混绑(例如绑在 2 和 28,视拓扑而定)。
列出 IRQ 与队列:
grep -E "ixgbe|i40e|ice|nvme" /proc/interrupts
ethtool -l eth0 # 看 RSS/Ring 队列
示例脚本 /usr/local/sbin/affine_irqs.sh(按你核数调整):
#!/usr/bin/env bash
set -euo pipefail
NIC=${1:-eth0}
BASE_CORE=${2:-2} # 从第2号核开始分配
mapfile -t IRQS < <(grep -E "$(ethtool -i $NIC | awk '/driver/ {print $2}')" /proc/interrupts \
| awk '{print $1}' | tr -d ':')
core=$BASE_CORE
for irq in "${IRQS[@]}"; do
mask=$(printf "%x" $((1<<core)))
echo $mask > /proc/irq/$irq/smp_affinity
echo "IRQ $irq -> CPU $core (mask 0x$mask)"
core=$((core+1))
done
NVMe 中断亦可类似处理。
如果是 X710(i40e),再配合 RPS/XPS:
for q in /sys/class/net/eth0/queues/{rx,tx}-*; do
echo 32768 > $q/rps_flow_cnt 2>/dev/null || true
echo 32768 > $q/xps_cpus 2>/dev/null || true
done
注意:irqbalance 与手工绑定二选一。选择手工绑定时:
systemctl stop irqbalance && systemctl disable irqbalance
5) 网卡/队列与 offload
# 增大 ring 缓冲
ethtool -G eth0 rx 4096 tx 4096
# 合理开启/关闭 offload(视 L7 负载而定)
ethtool -K eth0 tso on gso on gro on lro off rx on tx on
6) 文件系统与 NVMe
调度器:CentOS 7 下 NVMe 默认 none 即可;SATA/RAID 卡可考虑 noop/deadline。
挂载:noatime,nodiratime;XFS 对大文件/日志友好。
FIO 压测样例 /root/fio-4k-randread.fio:
[global]
ioengine=libaio
direct=1
time_based=1
runtime=60
group_reporting=1
iodepth=32
bs=4k
numjobs=8
[randread]
rw=randread
filename=/nvme/datafile # 提前用 fallocate 准备 > device cache 的大文件
7) 进程与 NUMA 亲和
lscpu | egrep "NUMA node|Thread"
numactl -H
# Web 进程绑到 CPU0 的本地内存
numactl --cpunodebind=0 --membind=0 \
/usr/sbin/nginx -g 'daemon off;'
Redis/MySQL 亦可按节点分布实例,减少跨 NUMA 访问。
8) HugePages(按需)
OLTP/大内存 DB 可配置静态 HugePages:
/etc/sysctl.d/99-hugepages.conf:vm.nr_hugepages=4096(示例)
/etc/security/limits.d/90-nproc.conf 中为数据库用户放宽 memlock。
Web/Redis 小对象,通常 THP 关闭 + 不启用静态大页,更稳。
第三刀:验证与对比(样例数据)
下表为我在上述硬件/配置上得到的样例(不同平台差异会很大,关注相对趋势)。
| 指标 | 基线(默认) | 调优后 | 变化 |
|---|---|---|---|
| FIO 4k randread(IOPS) | 750,000 | 920,000 | +22.7% |
| sysbench cpu(events/s) | 16,000 | 18,500 | +15.6% |
| iperf3 单流吞吐(Gbps) | 9.4 | 10.0 | +6.38% |
Nginx wrk(RPS) |
110,000 | 132,000 | +20.0% |
Redis GET p99(ms) |
3.8 | 2.6 | -31.6% |
观测到的副作用:
关深度 C-State + 固定 performance governor,功耗与温度上升(机房冷通道温度从 23℃→25℃,风速升高)。
关 HT 的 Redis 节点,吞吐略降但尾延迟收敛明显,契合我们的目标。
常见厂商菜单“同义词”对照
| 能力 | Supermicro | Dell iDRAC/BIOS | HPE iLO/BIOS |
|---|---|---|---|
| 电源策略 | Performance | System Profile: Performance | Power Regulator: Static High Perf |
| C-State | CPU C States | C States | Intel C-state |
| Turbo | Intel Turbo Boost | Turbo Boost | Intel Turbo Boost Tech |
| NUMA Interleave | Node Interleaving | Node Interleaving | NUMA Group Size Optimization |
| SNC | Sub-NUMA Clustering | SNC | SNC |
| Prefetchers | HW/Adj/DCU | Adjacent Cache Line / HW Prefetcher | Data/Code Prefetcher |
| UPI 速率 | UPI Link Speed | UPI Speed | Intel UPI Link Speed |
典型工作负载的“开关模板”
| 工作负载 | 超线程 | C-State | THP | SNC | Prefetch(DCU) |
|---|---|---|---|---|---|
| 低延迟 KV(Redis/撮合) | 关 | C1/C1E | never | 关/按平台 A/B | 关 |
| Web/Nginx/压缩 | 开 | C1/C1E | never | 关 | 开 |
| OLTP(MySQL/PG) | 开 | C1/C1E | madvise/静态大页 | 关 | 开 |
| 流式计算/批处理 | 开 | 适度节能 | madvise | 可开(新平台) | 开 |
始终以数据说话:模板只是起点。
现场坑点与救火记录
irqbalance 抢绑
现象:手工绑好的队列,过一会儿又乱了。
处理:停用 irqbalance 或者给其配置白名单;最终我选择停用并使用上面的脚本。
THP 动态回退
现象:transparent_hugepage=never 已加,但 cat /sys/kernel/mm/transparent_hugepage/enabled 仍显示 [always] madvise never。
处理:确认是否写到正确的 grub(有 EFI/BIOS 差异),重建 grub 并重启;同时在 /etc/rc.local 再写一遍保险:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
chmod +x /etc/rc.d/rc.local
SNC 打开后跨 NUMA 抖动
现象:Nginx RPS 有时升有时降。
处理:对NUMA 亲和敏感的服务(worker 绑核 + 本地内存),未做适配前建议关 SNC。
Prefetch 组合“反噬”
现象:Redis p99 上升。
处理:关掉 DCU Streamer/IP,保留 HW/Adjacent,抖动下降。
微码升级后的性能滑坡
现象:BIOS/微码打补丁后单核下降。
处理:确认安全补丁带来的影响,评估是否需要内核参数层的权衡(绝不随意关闭生产安全缓解)。与安全同事对齐变更窗口。
X710 队列数与 RSS
现象:多核不吃满,top 一核 100%,其余清闲。
处理:确认 ethtool -l 的实际队列数,开启 RSS 并与 IRQ 绑定脚本配套。
“一键回滚”与“可重复交付”
任何调优都必须可回滚、可复制。把关键动作做成 Ansible Role 或简单脚本,版本化存储:
roles/xeon_bios_notes/(只放文档与厂商工具指引)
roles/xeon_os_tuning/(模板与脚本)
files/affine_irqs.sh、templates/tuned.conf.j2
vars/(按机型、核数、网卡名差异化)
示例:最小化一键应用
curl -fsSL https://internal.example/hk-xeon/bootstrap.sh | bash
# 内含:安装工具 -> 部署 tuned 配置 -> 写 grub -> 绑 IRQ -> 重启 -> 验证清单
线上执行前,务必在同型号“影子机”预演,并拉上应用同学一起做回归。
附:基线与调优后输出样例(截断)
# turbostat --interval 5 --Summary
avg_MHz Busy% Bzy_MHz TSC_MHz
2350 22.3 4220 2100 # Turbo 有效,忙时频率上冲
# fio randread IOPS
read: IOPS=920k, BW=3.6GiB/s, IOPS per job ~115k, lat (usec): p50=310, p99=990
# wrk -t32 -c4096 -d60s
Requests/sec: 132000.00
Latency Distribution: p50 5.1ms p90 9.4ms p99 21.7ms
# redis-benchmark -t get -n 2000000 -q
GET: p99=2.6 ms
03:45,我把最后一条中断绑回指定的物理核,wrk 的尾延迟曲线从锯齿变成了钝钩。
隔着冷通道的风,我听到另一排机柜里有人轻敲光纤托盘,那节奏跟我屏幕上 IOPS 的跳动像是暗合。
我合上 KVM,给变更单做了最后一条备注:
“不是某个‘神奇开关’,而是 BIOS 与 OS 的共振。”
也许你在别的城市、别的机房复现这套组合,曲线会有不同。但只要顺着测量 → 假设 → 微调 → 验证这条路,你就会找到属于你业务的“共振频率”。
清单(可直接拿去用)
1. BIOS 必改优先级(从上到下做 A/B):
- Power Policy: Performance
- Turbo: Enable
- C-State: 限制在 C1/C1E(禁深 C)
- NUMA Interleaving: Disabled
- SNC: 视平台/负载 A/B
- Prefetchers: HW/Adjacent 开,DCU 试关
- UPI: Max Performance
2. OS 层必做:
- tuned-adm profile xeon-perf(自定义)
- transparent_hugepage=never(低延迟)
- processor.max_cstate=1 intel_idle.max_cstate=1
- 绑 IRQ(网卡/NVMe)并与 irqbalance 二选一
- ethtool -G 增 ring;合理 offload
- NUMA 亲和运行关键服务
3. 压测与回归:
- FIO、wrk、redis-benchmark、iperf3
- 业务低谷/高峰各一次;冷热数据各一次
- 图表留证,版本可追溯