上一篇 下一篇 分享链接 返回 返回顶部

香港服务器用 CentOS 7 时,我如何用 Tuned Profile 做“自动化性能优化”,把机器按工作负载一键切到合适的状态

发布人:Minchunlin 发布时间:2025-08-26 10:37 阅读量:684


那天夜里 1:20,我在葵涌机房的冷风里被手机报警叫醒:某跨境电商客户做直播秒杀,香港集群前端 p99 延迟从 18ms 飙到了 120ms,MySQL 的行锁堆叠像电梯口的双十一。机房灯光打在机柜门上,能看见自己呼出的白气。我没有先去翻 Nginx、内核、网卡一堆参数,而是直接在跳板机上敲了两行:

sudo tuned-adm profile latency-performance
sudo tuned-adm active

三十秒后,前端延迟掉回 25~30ms,回写队列也缓了下来。这不是魔法,是我早就把“不同工作负载用不同的 Tuned Profile”这套东西打通了,而且把自定义 profile 做成了自动化切换。那晚的后半夜,我把临时切换固化成策略:让机器“自己知道自己是谁”,在“低延迟 Web”、“数据库 IO 密集”、“跨机房吞吐备份”、“虚拟化承载”之间,一键/自动切换到最适合的状态。

下面我把这套做法完整摊开。既写给踩坑的人,也写给想把这活儿做漂亮的人。

1. 现场环境与硬件清单

我们手上的两类香港机型用得最多(真实上架批次之一):

项目 机型 A(前端/数据库) 机型 B(备份/虚拟化)
机箱/主板 Supermicro 1U / X11DPU Dell R740xd
CPU 2 × Intel Xeon Silver 4214 (12C/24T, 2.2GHz) 2 × Intel Xeon Gold 6130 (16C/32T, 2.1GHz)
内存 128GB DDR4-2666(8×16GB) 256GB DDR4-2666(16×16GB)
系统盘 2 × SATA SSD 480GB(RAID1) 2 × SATA SSD 480GB(RAID1)
数据盘 2 × NVMe U.2 3.2TB(RAID1, 数据库/缓存) 10 × SATA HDD 8TB(RAID6, 备份/对象)
网卡 Intel X710 10GbE ×2 Mellanox ConnectX-4 25GbE ×2
OS CentOS 7.9 (3.10 内核,部分升级至 5.4 LTS) CentOS 7.9 (3.10 内核)
关键服务 Nginx/LVS、Percona MySQL 5.7 MinIO/rsync、KVM、Docker

注:CentOS 7 默认 3.10 内核,如需 BBR 或更好的多队列 NVMe/网卡体验,我们会对前端节点打 ELRepo 的 kernel-lt/kernel-ml(比如 5.4/5.10)。统一变更时请评估内核 ABI 兼容。

2. Tuned 是什么?为什么适合“按场景一键优化”

Tuned 是 RHEL/CentOS 系列自带的系统调优守护进程 + 配置集,核心点:

  • 提供一组工作负载导向的预置 profile(Balanced、Throughput、Latency、Network、Virtual-* 等)。
  • 每个 profile 通过插件式段落([cpu] [vm] [sysctl] [disk] ...)把CPU 频率/能耗、内核 sysctl、磁盘调度、THP、IRQ、网卡等调到某种“性格”。
  • 可以叠加和自定义:我们常用 include=某预置,再加上业务化的 sysctl/脚本。
  • 有常用命令:tuned-adm list/recommend/profile/active/profile_info;服务名 tuned。

CentOS 7 常见内置 profile(命名略有差异):

Profile 适用 核心倾向
balanced 通用默认 折中
throughput-performance 批处理/备份/吞吐 提升吞吐,CPU 高性能,readahead 更大
latency-performance 延迟敏感(Web/交易) 追求低延迟,禁 THP,性能 governor
network-latency 网络低延迟 网栈偏低延迟
network-throughput 网络高吞吐(大包/备份) rmem/wmem 更大
virtual-host KVM 宿主机 NUMA/中断/调度倾向虚拟化
virtual-guest 虚机内部 虚机通用调优
powersave 低功耗 省电优先

3. 基础安装与“手工救火”到“制度化”的最短路径

3.1 安装与启用

# 安装
sudo yum install -y tuned tuned-utils tuned-profiles-compat

# 开机自启动并马上启动
sudo systemctl enable --now tuned

# 看看系统推荐(会基于硬件/虚拟化特征给建议)
sudo tuned-adm recommend

# 列出所有可用 profile
sudo tuned-adm list

# 激活一个
sudo tuned-adm profile latency-performance

# 查看当前生效
sudo tuned-adm active
sudo tuned-adm profile_info

排错入口:/var/log/tuned/tuned.log,任何没生效的选项、冲突、脚本报错,这里都有记录。

3.2 两个“立竿见影”的开关(CentOS 7)

CPU governor:切到 performance,延迟场景肉眼可见地稳定。

THP(Transparent Huge Pages):数据库延迟敏感时常常关掉(never 或 madvise),减少抖动。

4. 我们的“场景画像”与自定义 Profile

策略:先 include 官方 profile,再用小刀精准加料。这样“稳又快”,也方便回滚。

4.1 场景 A:低延迟 Web(Nginx/LVS)

目录:/etc/tuned/custom-nginx/tuned.conf

[main]
include=latency-performance
summary=Low-latency web front profile (CentOS 7, HK POP)

[cpu]
governor=performance
energy_perf_bias=performance
force_latency=1

[vm]
transparent_hugepages=never
swapiness=10

# 主要是网络栈,保持低延迟倾向
[sysctl]
net.core.somaxconn=4096
net.core.netdev_max_backlog=65536
net.ipv4.tcp_fin_timeout=15
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_mtu_probing=1
net.ipv4.tcp_timestamps=1
net.ipv4.tcp_sack=1
net.ipv4.tcp_low_latency=1
# 适度放大缓冲但保持低延迟优先
net.core.rmem_max=33554432
net.core.wmem_max=33554432
net.ipv4.tcp_rmem=4096 87380 33554432
net.ipv4.tcp_wmem=4096 65536 33554432
# BBR 仅当内核>=4.9且模块存在,否则保持 cubic
net.ipv4.tcp_congestion_control=cubic

[disk]
# NVMe 通常是 'none',SATA SSD/HDD 用 deadline
elevator=deadline
readahead=256

说明:这里不盲目开超大缓冲,因为直播/抢购这种流量突增时,过大的队列反而会让尾延迟拉长。

4.2 场景 B:数据库(Percona MySQL 5.7)

/etc/tuned/custom-mysql/tuned.conf

[main]
include=latency-performance
summary=MySQL OLTP profile (HK POP, NVMe RAID1)

[cpu]
governor=performance
energy_perf_bias=performance

[vm]
transparent_hugepages=never
swappiness=1
dirty_background_ratio=5
dirty_ratio=15
overcommit_memory=1

[sysctl]
vm.max_map_count=262144
fs.aio-max-nr=1048576

# InnoDB + 连接池延迟敏感
net.core.somaxconn=8192
net.ipv4.ip_local_port_range=10240 65535
net.core.rmem_max=67108864
net.core.wmem_max=67108864
net.ipv4.tcp_rmem=4096 87380 67108864
net.ipv4.tcp_wmem=4096 65536 67108864
net.ipv4.tcp_congestion_control=cubic

[disk]
# SATA SSD: deadline;NVMe: 维持 none/none 等价
elevator=deadline
readahead=128

补充:MySQL 本身要配合 innodb_flush_method=O_DIRECT、innodb_flush_neighbors=0,NVMe 更明显。

4.3 场景 C:跨机房大吞吐备份(rsync/MinIO)

/etc/tuned/custom-throughput/tuned.conf

[main]
include=throughput-performance
summary=WAN backup/object throughput profile

[cpu]
governor=performance

[vm]
transparent_hugepages=madvise
swappiness=10
dirty_background_bytes=67108864
dirty_bytes=536870912

[sysctl]
# 大吞吐,放大缓冲
net.core.netdev_max_backlog=250000
net.core.rmem_max=134217728
net.core.wmem_max=134217728
net.ipv4.tcp_rmem=4096 1048576 134217728
net.ipv4.tcp_wmem=4096 1048576 134217728
net.ipv4.tcp_mtu_probing=1
net.ipv4.tcp_congestion_control=cubic

[disk]
readahead=4096
elevator=deadline

4.4 场景 D:虚拟化宿主机(KVM)

/etc/tuned/custom-virtual-host/tuned.conf

[main]
include=virtual-host
summary=KVM host profile with IRQ/Numa hints

[cpu]
governor=performance
energy_perf_bias=performance

[vm]
transparent_hugepages=madvise
swappiness=5

[sysctl]
kernel.sched_migration_cost_ns=5000000
vm.zone_reclaim_mode=0

KVM 场景里,我们更多把 CPU 绑定、IRQ 亲和、NUMA 拆分交给 Libvirt/调度器,但用 tuned 撑住底层“基调”。

4.5 激活与回滚

sudo tuned-adm profile custom-mysql     # 切到自定义
sudo tuned-adm profile balanced         # 快速回滚到通用

当前生效写在 /etc/tuned/active_profile。我们还做了一个“安全网”脚本,切换前备份关键 sysctl,紧急回滚时直接 restore(见第 6 节)。

5. 自动化:让机器“自己知道选哪个 Profile”

5.1 一段极简的 Bash(无 Ansible 也能跑)

/usr/local/sbin/auto-tuned.sh

#!/usr/bin/env bash
set -euo pipefail

kernel_ver=$(uname -r | cut -d. -f1)
has_mysql=$(pgrep -x mysqld >/dev/null && echo 1 || echo 0)
has_nginx=$(pgrep -x nginx >/dev/null && echo 1 || echo 0)
is_kvm_host=$(lsmod | grep -q kvm_intel && virsh list --all >/dev/null 2>&1 && echo 1 || echo 0)
is_backup=$(systemctl is-active minio >/dev/null 2>&1 || pgrep -x rsync >/dev/null && echo 1 || echo 0)

profile="balanced"

if [[ $is_kvm_host -eq 1 ]]; then
  profile="custom-virtual-host"
elif [[ $has_mysql -eq 1 ]]; then
  profile="custom-mysql"
elif [[ $is_backup -eq 1 ]]; then
  profile="custom-throughput"
elif [[ $has_nginx -eq 1 ]]; then
  profile="custom-nginx"
fi

echo "Selecting tuned profile: $profile"
tuned-adm profile "$profile"
tuned-adm active

开机时调用:

cat >/etc/systemd/system/auto-tuned.service <<'EOF'
[Unit]
Description=Auto select tuned profile by workload
After=network-online.target tuned.service
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/auto-tuned.sh

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable auto-tuned.service

5.2 Ansible 版本(生产常用)

- hosts: hk-pop
  become: yes
  tasks:
    - name: Install tuned
      yum: { name: [tuned, tuned-utils, tuned-profiles-compat], state: present }

    - name: Enable tuned
      systemd: { name: tuned, enabled: yes, state: started }

    - name: Deploy custom profiles
      copy:
        src: "files/tuned/{{ item }}/tuned.conf"
        dest: "/etc/tuned/{{ item }}/tuned.conf"
        mode: "0644"
      with_items:
        - custom-nginx
        - custom-mysql
        - custom-throughput
        - custom-virtual-host

    - name: Install auto selector
      copy:
        src: files/auto-tuned.sh
        dest: /usr/local/sbin/auto-tuned.sh
        mode: "0755"

    - name: Install systemd unit
      copy:
        src: files/auto-tuned.service
        dest: /etc/systemd/system/auto-tuned.service

    - name: Reload systemd and run selector
      systemd: { daemon_reload: yes, name: auto-tuned.service, enabled: yes, state: started }

6. 变更前备份 & 快速回退

我们在 /usr/local/sbin/sysctl-snapshot.sh 做了一个快照工具:

#!/usr/bin/env bash
set -e
SNAP=/var/backups/sysctl-$(date +%F-%H%M%S).conf
/sbin/sysctl -a 2>/dev/null | sed -n 's/^\([^ ]\+\) = \(.*\)$/\1=\2/p' > "$SNAP"
echo "Saved to $SNAP"

回滚时:

sudo sysctl -p /var/backups/sysctl-<timestamp>.conf
sudo tuned-adm profile balanced

7. 实测数据:切换前后,用数说话

测试方法尽量贴近业务:Web 用 wrk 压测 + tail latency,DB 用 sysbench OLTP,备份用 iperf3 + rsync 大文件。

7.1 前端(Nginx,10GbE,内核 5.4,custom-nginx)

指标 切换前 balanced 切换后 custom-nginx 变化
RPS(wrk, 50 并发) 58,200 64,900 +11.5%
p95 延迟 41.3 ms 28.7 ms -30.5%
p99 延迟 118.9 ms 54.2 ms -54.4%
CPU 频率波动 明显 稳定在高频 稳定

7.2 MySQL(NVMe RAID1,custom-mysql)

指标 balanced custom-mysql 变化
sysbench TPS(oltp_read_write, 64 线程) 3,850 4,410 +14.5%
p95 响应 29.6 ms 22.1 ms -25.3%
InnoDB fsync/s 10.2k 12.1k +18.6%

7.3 跨机房吞吐(25GbE,custom-throughput)

指标 balanced custom-throughput 变化
iperf3 单流 9.8 Gbps 14.7 Gbps +50%
iperf3 4 流 17.2 Gbps 22.9 Gbps +33%
rsync 50GB 大文件 288 MB/s 371 MB/s +28.8%

这些数字不是广告语,是我们在香港 POP 里反复做出来的中位水平;你的结果会受内核版本、线路质量、对端栈、TLS、磁盘等影响。

8. 线上常见坑与我在机房的解决手记

BBR 不是银弹(也不总能开)

CentOS 7 默认 3.10 没 BBR,贸然升级内核要评估驱动、监控 Agent、HBA 兼容。我们做法:前端节点单独灰度到 5.4/5.10,profile 里仍默认 cubic,只在探测到 BBR 可用时脚本再切(sysctl net.ipv4.tcp_available_congestion_control 检测)。

NVMe 调度器

NVMe 通常是 none(等价 noop),你强行写 deadline 也未必能改;所以我在 [disk] 写 elevator=deadline 只是照顾 SATA 盘,同时在巡检脚本里按设备类型判断。查看:cat /sys/block/nvme0n1/queue/scheduler。

THP 生效与否要看内核状态

latency-performance 会关 THP,但线上我一定跑:

cat /sys/kernel/mm/transparent_hugepage/enabled,确认 never 或 madvise 是否真正生效。

之前遇到过容器内和宿主机不一致,最后把调优做在宿主机 profile 上,并在容器入口脚本二次确认。

cpupower/IRQBalance 冲突

部分镜像里装了 cpupower 或我们早期自写的 CPU pinning 服务,会和 tuned 都想改 governor/IRQ,引发拉扯。解决:让tuned 做基线,pinning 用业务化脚本,互相避让。冲突可在 /var/log/tuned/tuned.log 看到。

手动改 /etc/sysctl.conf 被“打回原形”

很多人一边用 tuned,一边到处 echo sysctl。记住:把业务化 sysctl 放在自定义 profile 的 [sysctl] 段,别散落在 sysctl.conf,否则重启/重载后会被 profile 覆盖。

虚拟机里误用 virtual-host

我见过同事在 KVM 来宾里套了宿主机 profile,时延直接炸。虚机里请用 virtual-guest 或针对业务自定义。

BIOS 电源策略被忘了

机房换主板后 BIOS 复位,CPU 电源策略回到 Balanced,怎么调都不稳。排查 20 分钟后我进 BIOS 改成 Performance,世界瞬间安静。软件调优挡不住硬件被“捆着手脚”。

网卡队列/中断亲和要分工

Tuned 对网卡 ring、coalesce 的能力有限,细粒度优化(ethtool -G/-C、rps_cpus、irqbalance --banirq)我放在脚本插件或 Ansible role 里,而不是硬塞进 tuned。

例子(配合 custom-nginx):

/etc/tuned/custom-nginx/ethtool.sh

#!/usr/bin/env bash
ethtool -G ens3f0 rx 4096 tx 4096 || true
ethtool -C ens3f0 rx-usecs 12 rx-frames 0 || true

tuned.conf 加:

[scripts]
script=/etc/tuned/custom-nginx/ethtool.sh

9. 巡检与验收:别迷信“设了就好”,要看结果

profile 生效检查:

tuned-adm active / tuned-adm profile_info / journalctl -u tuned -n 100

CPU/频率:

cpupower frequency-info(或直接看 /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor)

THP/污页:

cat /sys/kernel/mm/transparent_hugepage/enabled / sysctl vm.dirty_*

磁盘/调度器/预读:

cat /sys/block/sdX/queue/scheduler / blockdev --getra /dev/sdX

网络栈:

sysctl net.core.rmem_max net.core.wmem_max net.core.netdev_max_backlog

基准:

  • Web:wrk -t8 -c128 -d60s https://...
  • DB:sysbench oltp_read_write --tables=16 --table-size=1e6 ... run
  • 吞吐:iperf3 -P4 -t60 -c <peer>

把这些写成 Runbook,每次变更都留“前后对比截图/数据”,久而久之你会有自己的“香港 POP 体感库”。

10. FAQ(我常被问到的)

Q:Tuned 会覆盖我的 Docker 容器内核参数吗?

A:tuned 改的是宿主机;容器网络命名空间里的 sysctl 不会被自动覆盖,需要在容器编排层面设置(例如 docker run --sysctl 或 k8s Pod securityContext)。

Q:能否一台机既跑低延迟 Web 又跑吞吐备份?

A:能,但 profile 只能选一个。我的做法是按主业务选 profile,把次业务的关键参数通过脚本/服务粒度调,避免“拉扯”。

Q:切 profile 会不会瞬时抖动?

A:个别参数重载会有轻微抖动(比如 THP 切换),所以在窗口期做;而 somaxconn、readahead 等通常无感。

11. 收尾:从“半夜救火”到“机器自己会选路”

回想那晚,切到 latency-performance 的那个瞬间,我盯着面板上 p99 的曲线像电梯一样下行——那是我在机房里最爱看的“风景线”。如今,新的香港节点上架,我几乎不需要再守在屏幕前:Nginx 在,选 custom-nginx;MySQL 起,切 custom-mysql;周末做跨机房备份,自动把 profile 换到 custom-throughput。

我仍然会去机柜前听一听风扇的声音、摸一摸网线卡扣是不是松了——**优化不是一堆参数的堆砌,而是让机器“像人一样”知道在什么场景该做什么事。**Tuned 不是终点,但它是把“性能优化”制度化的那把扳手。

如果你也在香港机房里和我经历着同样的夜晚,拿走这套脚本和 profile 吧。先从一台灰度,跑一轮巡检,再让它自动地、可回滚地、可度量地跑起来。等你有了自己的曲线和数字,你就会明白:那并不是一次幸运的按键,而是一套可复制的工程方法。

目录结构
全文