4、操作系统基础调优:内核参数调整、CPU隔离与中断绑定、NUMA亲和性设置

操作系统层面的调优,说白了就是给RoCE通信铺好路。你想想看,网卡再快,如果CPU忙着处理别的事,或者内存访问跨了节点,那延迟照样下不来。我个人习惯,拿到一台新机器,先做三件事:改内核参数、绑中断、调NUMA。这三板斧下去,性能基本能稳住。

核心思路:让RoCE流量走最短路径,CPU只干该干的活,内存就近访问。

4.1 内核参数调整:给网络栈松松绑

Linux内核默认的网络参数,其实是为通用场景设计的。做RoCE调优时,我们需要把一些限制放开。我记得第一次调一个40Gbps的RoCE链路,没改参数前,吞吐死活上不去,后来发现是接收缓冲区太小,丢包严重。

以下是我常用的参数调整清单:

# 调整TCP/UDP缓冲区大小(单位:字节)
net.core.rmem_max = 134217728    # 128MB,接收缓冲区上限
net.core.wmem_max = 134217728    # 128MB,发送缓冲区上限
net.core.rmem_default = 262144   # 256KB,默认接收缓冲区
net.core.wmem_default = 262144   # 256KB,默认发送缓冲区

# 调整TCP读写缓冲区(最小值、默认值、最大值)
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728

# 开启TCP窗口缩放,支持高带宽长距离链路
net.ipv4.tcp_window_scaling = 1

# 调整网卡队列长度,减少丢包
net.core.netdev_max_backlog = 50000

# 调整最大连接数
net.core.somaxconn = 65535

# 关闭TCP时间戳,减少CPU开销(RoCE场景下建议关闭)
net.ipv4.tcp_timestamps = 0

# 开启快速回收TIME_WAIT连接(注意:NAT环境下慎用)
net.ipv4.tcp_tw_reuse = 1

我的经验:这些参数中,rmem_maxwmem_max是最关键的。我曾经遇到一个案例,把rmem_max从默认的212992字节改成128MB后,吞吐直接翻倍。但注意,改太大也可能导致内存占用过高,建议根据实际带宽和延迟计算。

为什么要调这些?说白了,RoCE虽然走的是RDMA协议,但底层还是依赖内核的网络栈来管理连接和资源。缓冲区太小,数据来了没地方放,只能丢包重传,延迟就上去了。

4.2 CPU隔离与中断绑定:让网卡独占一个核

中断处理是RoCE性能的隐形杀手。你想想看,网卡每收到一个包,都会触发一个中断,CPU就得停下手中的活去处理。如果中断在各个核之间乱跳,缓存命中率会大幅下降。

我建议的做法是:

  1. 关闭irqbalance服务——这个服务会自动均衡中断,但在RoCE场景下反而坏事。
  2. 手动绑定中断到指定CPU核——让网卡的中断固定在一个或几个核上。
  3. 隔离CPU核——把处理中断的核从进程调度中隔离出来,避免被其他任务抢占。

具体操作如下:

# 1. 停止并禁用irqbalance
systemctl stop irqbalance
systemctl disable irqbalance

# 2. 查看网卡中断号(以mlx5_0为例)
cat /proc/interrupts | grep mlx5_0

# 3. 绑定中断到CPU 2(假设中断号为 118-125)
echo 2 > /proc/irq/118/smp_affinity
echo 2 > /proc/irq/119/smp_affinity
# ... 依次绑定所有相关中断

# 4. 隔离CPU核(在grub中配置)
# 编辑 /etc/default/grub,添加 isolcpus=2,3
GRUB_CMDLINE_LINUX="... isolcpus=2,3"
# 然后更新grub并重启
grub2-mkconfig -o /boot/grub2/grub.cfg

注意:隔离CPU核后,这些核就不会被普通进程使用了。你需要确保RoCE相关的进程(比如你的应用)通过tasksetnumactl绑定到这些核上。我曾经见过有人隔离了核,但应用没绑上去,结果那些核空转,中断还是跑到了其他核上,性能反而更差。

为什么会这样?因为中断亲和性决定了网卡硬件把中断信号发给哪个CPU。如果中断在多个核之间跳来跳去,每个核的L1/L2缓存都得重新加载数据,延迟自然就高了。固定在一个核上,缓存命中率能到90%以上。

4.3 NUMA亲和性设置:内存就近访问

NUMA架构下,CPU访问本地内存和远端内存的速度差很多。我测过,跨NUMA节点的内存访问延迟,比本地高30%-50%。对于RoCE这种对延迟敏感的场景,这个差距是致命的。

NUMA亲和性设置的核心原则:网卡、CPU、内存要在同一个NUMA节点上

具体做法:

  1. 查看NUMA拓扑——用lscpunumactl --hardware查看。
  2. 确认网卡所在的NUMA节点——用cat /sys/class/infiniband/mlx5_0/device/numa_node查看。
  3. 绑定应用和内存到同一节点——用numactl命令。
# 查看NUMA拓扑
numactl --hardware
# 输出示例:
# available: 2 nodes (0-1)
# node 0 cpus: 0 1 2 3
# node 0 size: 32768 MB
# node 1 cpus: 4 5 6 7
# node 1 size: 32768 MB

# 查看网卡所在NUMA节点
cat /sys/class/infiniband/mlx5_0/device/numa_node
# 输出:0 (表示网卡在NUMA节点0)

# 启动应用时绑定到NUMA节点0
numactl --cpunodebind=0 --membind=0 ./your_roce_app

我的习惯:我会写一个启动脚本,自动检测网卡的NUMA节点,然后绑定应用。这样换机器或换网卡时,不用手动改参数。脚本大概长这样:

#!/bin/bash
NUMA_NODE=$(cat /sys/class/infiniband/mlx5_0/device/numa_node)
numactl --cpunodebind=$NUMA_NODE --membind=$NUMA_NODE ./your_roce_app

嗯,这里要注意一点:如果你的服务器有多个网卡,每个网卡可能在不同NUMA节点上。这时候需要根据实际使用的网卡来绑定。我曾经踩过这个坑,两个网卡分别挂在node0和node1上,我绑错了节点,性能直接腰斩。

4.4 知识体系总览

下面这张图,是我梳理的操作系统调优核心逻辑。你可以看到,三个方向最终都指向同一个目标:减少路径上的瓶颈

操作系统基础调优核心逻辑 内核参数调整 rmem_max / wmem_max CPU隔离与中断绑定 irqbalance / smp_affinity NUMA亲和性设置 cpunodebind / membind 减少路径瓶颈,降低延迟 减少丢包重传 提高缓存命中率 避免跨节点访问 三者缺一不可,建议按顺序执行:内核参数 → CPU隔离 → NUMA绑定

4.5 验证调优效果

调完了,怎么知道有没有用?我一般用这几个方法验证:

  • 检查中断分布cat /proc/interrupts | grep mlx5,看中断是否集中在绑定的核上。
  • 检查NUMA命中率numastat -p your_app_pid,看本地内存访问占比是否接近100%。
  • 跑带宽延迟测试:用ib_write_bwib_write_lat对比调优前后的数据。

避坑指南:我曾经在调完参数后,发现性能反而下降了。排查了半天,原来是irqbalance虽然关了,但系统里还有别的服务在动态调整中断亲和性。所以建议调完后,用chkconfig irqbalance off彻底禁用,并检查/proc/irq/*/smp_affinity是否稳定。

好了,操作系统层面的调优就这些。说白了,就是让硬件资源各司其职,别互相干扰。下一层,我们会深入到网卡和驱动层面,那里还有更多细节等着我们。


专注资料整理