高频交易对网卡中断亲和性的调优,核心是将网卡各队列的硬件中断固定绑定到专属CPU核心,从源头消除中断漂移带来的延迟抖动,这是纳秒级竞争中不可跳过的一步。
延迟是高频交易的生命线,当行情数据包到达网卡,硬件中断会打断CPU,通知内核处理数据,如果这个中断落在哪个CPU上完全随机,缓存失效、跨核访问、调度延迟就会叠加成微秒级的不稳定波动,对普通业务这不算什么,对高频交易来说,一次抖动就足以让策略错过最佳价格,把中断”钉死”在指定核心上,等于给网络处理修了一条专用车道。
高频交易中网卡中断亲和性怎么调优?先理解中断的脾气
中断亲和性调优的本质,是改写/proc/irq/<中断号>/smp_affinity中的CPU掩码,但你得先弄清网卡和驱动的行为,不然盲改只会更糟。
多队列网卡是前提
现代10G/25G/100G网卡普遍支持RSS(Receive Side Scaling),也就是把收包队列拆成多个,每个队列有独立中断号,如果网卡只有单队列,中断亲和性调优的空间极小,延迟也无法分散,行业内默认先确认网卡是否已开启多队列,用ethtool -l eth0查看当前队列数。
中断号和CPU拓扑的对应关系
每个队列的中断号能在/proc/interrupts里看到,但注意,中断号不是固定的,驱动加载顺序可能导致编号变化,绑定前,一定要核对当前生效的号,CPU拓扑方面,同一物理CPU的超线程兄弟核心共享缓存,绑定中断时应避开超线程搭档,否则两个逻辑核争抢L2缓存,性能反而下降。
高频交易场景的默认策略:关闭irqbalance
多数发行版默认开启irqbalance服务,它会周期性迁移中断以达到负载均衡,这在服务器上很友好,但在高频交易里就是延迟不定性的来源,行业共识认为,跑高频交易策略的机器应当显式关闭该服务,用systemctl stop irqbalance和
systemctl disable irqbalance,然后手动管理每个中断的归属。
网卡中断亲和性设置的详细步骤,照着敲就行
下面是一套经过大量生产环境验证的流程,你的系统是CentOS、Ubuntu还是其他主流发行版,命令基本通用。
第一步:确认网卡队列数量及中断分布
# 查看网卡支持的队列数 ethtool -l eth0 # 查看当前的中断分配与队列对应关系 cat /proc/interrupts | grep eth0
以Intel X710网卡为例,/proc/interrupts中会列出eth0-TxRx-0、eth0-TxRx-1等条目,每条对应一个队列,前面的数字就是中断号。
第二步:写入CPU亲和掩码
CPU掩码是十六进制数,从CPU0开始位对应,要把中断绑定到CPU2,掩码就是0x4;绑定到CPU2和CPU3,掩码是0xC,写入方式:
# 假设中断号是62 echo 4 > /proc/irq/62/smp_affinity
注意,这个写法在部分内核里会提示权限不足,需要先确认/proc/irq/62/smp_affinity_list这个接口,它用十进制列表代替掩码,更直观:
echo 2 > /proc/irq/62/smp_affinity_list
第三步:使用irqbalance的精细化配置
有些场景不希望完全关闭irqbalance,而是让它只管理非关键中断,可以在/etc/irqbalance.conf中设定banirq参数,把特定中断排除在外,但高频交易场景下,我建议连这个都别用,直接关掉,自己写启动脚本。
第四步:将设置固化到系统
重启后上述设置会丢失,推荐写一个systemd服务,在ExecStart中依次绑定所有网卡队列中断,也可以放到/etc/rc.local,但systemd会更优雅,并能设置依赖关系。
[Unit] Description=Pin NIC interrupts to dedicated CPUs After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/pin_irq.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target
pin_irq.sh内部循环,把每个队列中断绑定到预先规划好的核心列表,并顺便把对应的RPS(Receive Packet Steering)关闭,避免内核软件分发干扰硬件绑定。
多队列网卡中断绑定CPU时常见的坑
即使流程写对了,实际运行中还是会有不少陷阱。
超线程兄弟核心不能碰
比如CPU0和CPU1是同一物理核的两线程,把中断分别绑到0和1,表面看分散了,实际上它们共享执行单元和缓存,中断处理要排队,用lscpu -p能看到每个逻辑核的core id,规划绑定表时先画出物理核心分布图。
感知NUMA距离
如果网卡插在NUMA节点0的PCIe槽,却把中断绑到NUMA节点1的CPU上,每次访问网卡寄存器都要跨节点走QPI总线,延迟直接多几百纳秒,用lstopo或cat /sys/bus/pci/devices/<设备地址>/numa_node确认归属,绑定同节点CPU是必须的。
驱动名称不同,设置方法不同
有些驱动,比如Mellanox的mlx5_core,不直接复用/proc/irq,而是提供smp_affinity的sysfs接口或通过ethtool -X配置,走ethtool -X eth0 weight 1 1 1 1可以改变队列权重,但不改变中断归属,务必先读驱动手册,别拿Intel的命令套用到Mellanox上。
高频交易网络延迟优化实践:不只是中断亲和性
中断绑定做好了,数据面延迟可能从几十微秒降到几微秒,但要想进一步压低到微秒以下,还得配合其他手段。
内核协议栈让步:DPDK和AF_XDP
对高频交易,很多团队不会停在内核协议栈,DPDK用户态轮询驱动直接接管网卡,彻底绕开中断,这样一来,中断亲和性调优似乎不重要了?不对,DPDK的PMD线程也需要绑定核,而且旁路内核后,你还要处理内存大页、巨页映射、CPU隔离等问题,如果你仍然使用内核协议栈,中断绑定就是最低成本且最有效的一步。
与CPU调频和隔离联动
设置isolcpus内核启动参数,把用于中断的和用于业务的核心从通用调度器中隔离出来,配合tuned-adm profile latency-performance关闭CPU节能状态,让核心始终工作在最高频率,中断绑定了核心,但核心还去跑其他进程,隔离效果就大打折扣。
实测验证:工具和方法
调优后必须验证。perf的irq事件能统计中断延迟分布,也可以用ping -f测试流量波动,但高频交易更关注实际行情报文的端到端延迟,建议用硬件时间戳的ethtool -T确认网卡支持,再自行编写抓包程序按包序号对比时间存证。
网卡中断亲和性调优的Q&A
网卡中断亲和性设置后立刻生效吗,需要重启吗?
写入/proc/irq/<n>/smp_affinity后立刻生效,无需重启系统,但要注意,驱动在链路重协商、设备复位或挂载额外队列时,可能重新分配中断号,需要重新执行脚本,生产环境应把绑定动作放在网卡就绪后自动触发。
每个队列都绑到同一个CPU行不行?
技术上可以,但完全不推荐,多个队列竞争同一个核心,中断处理串行化,吞吐量大幅下降,正确做法是每个队列独占一个物理核心,如果队列数多于可用核心,优先为处理关键数据流的队列绑定单独核心,其余队列共享。
绑定中断亲和性会降低CPU利用率吗?
不会降低利用率,而是改变中断的分布,由于中断集中在少数核心上,这些核心的软中断和上下文切换开销升高,但业务核心获得了更可预测的执行环境,整体吞吐率可能略降,对高频交易来说,稳定性和低延迟比吞吐率重要得多。
中断亲和性调优不是独立的一步棋,它必须结合网卡队列、CPU拓扑、NUMA节点以及驱动的具体行为来统一规划,对高频交易系统而言,把中断牢牢钉在正确的位置上,是每一微秒都不能妥协的地基。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/630823.html





