技术博客

Linux 6.12 LTS 企业部署指南:PREEMPT_RT 实时内核与生产调优

Linux 6.12 于 2024 年 11 月发布并成为 LTS 版本,计划支持到 2026 年底。最重要的变化是历经近 20 年开发的 PREEMPT_RT 实时抢占补丁集正式合并主线,Linux 内核第一次原生支持硬实时计算。本文讲解 Linux 6.12 对云原生运维的影响:实时内核的启用与适用场景、容器环境下的内核参数调优(网络/内存/文件系统)、cgroup v2 完整迁移、以及在 Kubernetes 节点上的 6.12 升级实践。

Linux内核PREEMPT_RT实时计算性能调优cgroupKubernetes企业运维

Linux 6.12 是 2024 年底发布的一个重要版本,也是当前使用最广泛的 LTS 内核之一。它的最大亮点——PREEMPT_RT 实时抢占正式合并主线——结束了这个补丁集近 20 年的“只能打外部 Patch”历史。

对大多数云原生运维场景来说,6.12 带来的改进是渐进的而不是革命性的,但有几个方面值得重点关注。


Linux 6.12 关键特性概览

PREEMPT_RT 实时抢占(主线合并)
  历史最久的 Linux Patch,终于进主线
  让 Linux 可以作为硬实时操作系统使用
  支持架构:x86/x86_64、ARM64、RISC-V
  适用场景:工业控制、金融高频交易、边缘 AI 推理延迟敏感场景

GPU 驱动改进
  NVIDIA GSP 固件驱动改进(对 AI/ML 工作负载有收益)
  AMD RDNA4 架构支持(RX 9000 系列显卡)
  Intel 新一代 GPU 支持

网络优化
  IO_uring 网络操作进一步完善(异步 I/O 性能提升)
  网络调度器改进(多队列网卡利用率提升)

文件系统
  bcachefs 文件系统进一步稳定
  Btrfs RAID 性能改进
  XFS 异步 I/O 优化(对数据库类应用有收益)

安全
  Landlock LSM 新增网络控制能力
  BPF token 机制(更细粒度的 BPF 权限控制)

PREEMPT_RT 实时内核

什么是 PREEMPT_RT

普通 Linux 内核:
  内核代码的某些关键路径持有锁,期间不可被抢占
  导致:最坏情况下的调度延迟(Latency)可达几毫秒到几十毫秒
  对大多数应用够用,但对实时系统不可接受

PREEMPT_RT(全抢占):
  几乎所有内核代码都可以被更高优先级任务抢占
  调度延迟大幅降低:通常 < 100 微秒,极端情况 < 1 毫秒
  代价:吞吐量略有下降(约 5-10%)

适用场景:
  ✓ 工业控制系统(伺服电机控制,需要 <1ms 响应)
  ✓ 金融高频交易(微秒级延迟敏感)
  ✓ AI 推理边缘设备(需要确定性响应时间)
  ✓ 音视频处理(防止音频 XRun)
  
不适用场景:
  ✗ 普通 Web 服务器、数据库、K8s 节点(收益不明显,有开销)
  ✗ 追求最大吞吐量的批处理场景

检查和启用 PREEMPT_RT

# 检查当前内核是否支持 RT
uname -r
# 如果显示 xxx-rt-xxx,已经是 RT 内核

# 检查内核编译选项
grep PREEMPT /boot/config-$(uname -r)
# CONFIG_PREEMPT_RT=y 表示全实时
# CONFIG_PREEMPT=y 表示普通抢占(不是实时)

# Ubuntu/Debian 安装实时内核
apt-get install linux-image-realtime
# 或者
apt-get install linux-lowlatency    # 低延迟版本,比全 RT 开销小

# 设置进程实时优先级(需要 CAP_SYS_NICE 或 root)
chrt -f -p 80 <PID>    # 设置 FIFO 调度,优先级 80

# 测量调度延迟(需要安装 rt-tests)
apt-get install rt-tests
cyclictest -l 1000000 -m -Sp80 -i200 -h400 -q
# 关注 Max 延迟(正常 RT 内核应该 < 200us)

Kubernetes 节点内核参数调优

这些参数适用于运行 Kubernetes 工作节点的 Linux 6.12 系统,无论是否使用 RT 内核。

网络参数

# /etc/sysctl.d/99-kubernetes-net.conf

# 连接追踪表(大集群必须扩大,否则 conntrack: table full 报错)
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 300
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30

# 端口范围(避免与 Service NodePort 冲突)
net.ipv4.ip_local_port_range = 32768 60999

# TCP 性能
net.core.somaxconn = 65535                    # listen() 队列大小
net.core.netdev_max_backlog = 5000            # 网卡接收队列
net.ipv4.tcp_max_syn_backlog = 8192           # SYN 半连接队列
net.ipv4.tcp_tw_reuse = 1                     # TIME_WAIT 复用
net.ipv4.tcp_fin_timeout = 30                 # FIN_WAIT2 超时

# 发送/接收缓冲区(高带宽场景)
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728

# 开启 BBR 拥塞控制算法(比 cubic 更适合数据中心网络)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# Kubernetes 需要的内核参数
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

内存参数

# /etc/sysctl.d/99-kubernetes-mem.conf

# 关闭 swap(Kubernetes 要求,或者配置 Swap 感知调度)
vm.swappiness = 0

# 内存过量分配(容器化应用)
vm.overcommit_memory = 1
vm.overcommit_ratio = 50

# 脏页刷新(避免写入突刺导致 I/O 延迟尖峰)
vm.dirty_ratio = 10              # 超过 10% 内存的脏页,开始同步写入
vm.dirty_background_ratio = 5   # 超过 5% 内存的脏页,后台开始写入
vm.dirty_expire_centisecs = 3000 # 脏页 30 秒后必须写入
vm.dirty_writeback_centisecs = 500  # 每 5 秒唤醒一次写回

# 大页内存(AI 训练/高性能数据库场景)
vm.nr_hugepages = 1024           # 预分配 1024 个 2MB 大页(共 2GB)

# NUMA 感知(多 NUMA 节点服务器)
kernel.numa_balancing = 1

文件系统和进程参数

# /etc/sysctl.d/99-kubernetes-fs.conf

# 文件描述符(大量容器时必须提高)
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 8192

# inotify(watch 配额,K8s 组件需要大量 watch)
fs.inotify.max_queued_events = 32768

# 进程/线程数量上限
kernel.pid_max = 4194304
kernel.threads-max = 65536
# 应用参数(在 /etc/security/limits.conf 或 systemd 服务中)
# /etc/security/limits.d/99-kubernetes.conf
* soft nofile 1048576
* hard nofile 1048576
* soft nproc 65536
* hard nproc 65536

一键应用

# 应用所有 sysctl 配置
sysctl --system

# 验证关键参数
sysctl net.netfilter.nf_conntrack_max
sysctl vm.swappiness
sysctl net.ipv4.tcp_congestion_control

# 检查 conntrack 表使用情况
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
# 如果 count/max > 80%,需要扩大 nf_conntrack_max

cgroup v2 完整配置

Linux 6.x 默认已经使用 cgroup v2,但部分场景需要确认配置。

# 确认当前 cgroup 版本
mount | grep cgroup
# cgroup2 on /sys/fs/cgroup 说明是 v2

# 如果是 v1,强制切换到 v2(需要重启)
# 在 /etc/default/grub 中添加
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1"
update-grub && reboot

# 确认 Kubernetes 节点使用 cgroup v2
kubectl get node <node-name> -o jsonpath='{.status.conditions}'
# 查看 MemoryPressure/DiskPressure 等状态

# cgroup v2 的 PSI(Pressure Stall Information)
# 用于感知 CPU/内存/IO 的实际压力
cat /proc/pressure/cpu
# some avg10=0.00 avg60=0.00 avg300=0.00 total=0
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0
# some:部分任务在等待(有压力但不严重)
# full:所有任务都在等待(严重压力)

节点内核升级流程

# 以 Ubuntu 22.04 升级到 6.12 内核为例

# 方法一:Ubuntu HWE(硬件启用内核,稳定性有保证)
apt-get install linux-generic-hwe-22.04

# 方法二:Ubuntu 主线内核 PPA(更新但支持有限)
add-apt-repository ppa:canonical-kernel-team/mainline
apt-get update
apt-get install linux-image-6.12.x-generic

# 升级前的准备(Kubernetes 节点)
# 1. 先驱逐节点上的 Pod
kubectl drain <node-name> \
  --ignore-daemonsets \
  --delete-emptydir-data \
  --timeout=300s

# 2. 标记节点不可调度
kubectl cordon <node-name>

# 3. 在节点上执行内核升级
apt-get upgrade
reboot

# 4. 节点恢复后解除限制
kubectl uncordon <node-name>

# 5. 验证节点状态
kubectl get node <node-name>
kubectl describe node <node-name> | grep "Kernel Version"

性能测试基准

# 网络延迟测试(节点到节点)
iperf3 -s &                    # 在目标节点启动服务端
iperf3 -c <target-ip> -t 30   # 从源节点测试带宽

# 磁盘 I/O 测试
apt-get install fio
fio --name=randwrite \
    --ioengine=libaio \
    --direct=1 \
    --bs=4k \
    --numjobs=4 \
    --size=1G \
    --runtime=60 \
    --group_reporting

# 调度延迟测试(RT 内核)
cyclictest \
  --mlockall \
  --smp \
  --priority=80 \
  --interval=200 \
  --distance=0 \
  --loops=1000000

# CPU 性能
sysbench cpu --threads=$(nproc) run

小结

Linux 6.12 对于大多数运行 Kubernetes 的生产节点来说,是一次平滑的升级——内核参数调优方法没有变化,cgroup v2 在更早的版本就已经默认启用。

PREEMPT_RT 合并主线是历史性的里程碑,但对云原生运维场景的直接收益有限。它真正的价值在于边缘计算、工业 IoT 和金融超低延迟场景——这些场景之前需要打额外的 Patch,现在可以直接使用发行版提供的实时内核包。

升级时最重要的还是按流程操作:先 drain 节点再升级,升级后验证工作负载恢复正常再继续下一个节点。