level2行情包含了逐笔委托、逐笔成交、10档订单簿、盘口队列以及合成订单簿等,每天的数据量达到上百GB,使用TCP接收行情通常会带来较大的延时,为此一般采用UDP组播的方式,但同时也带来了丢包问题,本文介绍Solarflare网卡UDP组播行情丢包的一些优化方案。
一、Solarflare 网卡:金融行情的加速器
Solarflare 网卡之所以成为金融行业的标准,主要得益于其独特的硬件架构和软件生态:
- 超低延迟:通过硬件加速技术,将延迟压缩至亚微秒级。
- OpenOnload 协议栈:这是 Solarflare 的核心武器。它是一个高性能的用户态网络协议栈,通过内核旁路(Kernel Bypass)技术,绕过繁琐的 Linux 内核处理流程,直接在用户空间接收数据,极大降低了 CPU 开销和延迟。
在 UDP 组播行情传输中,Solarflare 不仅能提供极速的接收能力,还能通过硬件层面的过滤和分发,有效应对瞬时流量峰值。
二、 追根溯源:UDP行情丢包常见原因分析
UDP 协议本身是不可靠的,不保证数据包的顺序和到达。在行情传输中,丢包通常由以下原因引起:
- 系统内核瓶颈:标准 Linux 内核协议栈在处理高频小包时,上下文切换和内存拷贝开销巨大,导致缓冲区溢出。
- 缓冲区不足:当行情瞬时爆发(如开盘或重大消息发布)时,若网卡或系统缓冲区设置过小,数据包会因“无处安放”而被丢弃。
- 中断风暴与竞争:大量网络中断请求集中在某个 CPU 核心上,导致该核心处理不过来,而其他核心却在“围观”。
- CPU 调度干扰:操作系统自身的进程调度、节能模式或频率切换(Jitter)会导致处理性能波动。
三、 实战指南:Solarflare 网卡深度优化措施
3.1 Linux系统网络参数优化
主要是缓冲区相关的参数net.ipv4.udp_mem 尽可能设置的大
fs.file-max=10485760net.core.netdev_budget=8192net.core.somaxconn=65535net.ipv4.tcp_max_syn_backlog=16384net.core.netdev_max_backlog=65535net.core.rmem_default=562144000net.core.wmem_default=562144000net.core.rmem_max=1677721600net.core.wmem_max=1677721600net.core.optmem_max=1677721600net.ipv4.tcp_max_tw_buckets=1048576net.ipv4.tcp_fin_timeout=15net.ipv4.udp_mem=268435356 268435356 268435356net.ipv4.udp_rmem_min=268435356net.ipv4.tcp_tw_reuse=1
编辑完成后:sysctl -p生效
3.2 系统级配置
sfcaffinity_config auto
作用: 自动将网卡的硬件接收队列(RSS Channels)均匀地分布到系统的各个 CPU 核心上。 自动关闭系统的 irqbalance 服务(防止内核把中断乱跳)。
这一步至关重要,首先查看网卡支持的最大队列数:
(base) ➜ ethtool -g enp129s0f0 Ring parameters for enp129s0f0:Pre-set maximums:RX: 4096RX Mini: n/aRX Jumbo: n/aTX: 2048TX push buff len: n/aCurrent hardware settings:RX: 4096RX Mini: n/aRX Jumbo: n/aTX: 2048RX Buf Len: n/aCQE Size: n/aTX Push: offRX Push: offTX push buff len: n/aTCP data split: n/a
然后将接收队列调整只最大即可:
ethtool -G enp129s0f0 rx 4096
在 Linux 启动参数中(Grub),通过 isolcpus 将特定的核心从操作系统调度中剔除,专门预留给交易程序和 Solarflare 驱动使用,避免系统上其他程序的竞争: 编辑: /etc/default/grub
在GRUB_CMDLINE_LINUX上面增加一行:
GRUB_CMDLINE_LINUX_DEFAULT="isolcpus=32,33,34,35,36"
最后 update-grub后重启。
3.3 Onload参数配置
这里比较重要的是EF_UDP_RCVBUF缓冲区参数,开盘一瞬间数据包巨大,此值过小极易造成丢包。
#!/bin/bashONLOAD_CORES="41,42,43,44,45,46"APP_CORES="32,33,34,35,36"INTERFACE_NAME="enp129s0f0"export ONLOAD_CPUS=$ONLOAD_CORESexport ONLOAD_AFFINITY=$APP_CORESexport EF_POLL_USEC=-1export EF_SCALABLE_FILTERS="enp129s0f0=transparent_active:passive"export EF_RXQ_SIZE=4096export EF_UDP_RCVBUF=1073741823NUMA_NODE=1nohup numactl --cpunodebind=$NUMA_NODE --membind=$NUMA_NODE onload --profile=latency ./DataServerL2 > ServerL2.log 2>&1 &
如果是多路CPU注意使用numactl绑定。
四、 系统验证
ethtool -S enp129s0f0 | grep 'drop'
查看关键指标:
- port_rx_nodesc_drops:4122902 (关键核心指标)
- 深层解释:网卡硬件收到了组播数据包,但当它想把数据包放入“接收环形缓冲区(RX Ring Buffer)”时,发现缓冲区已经满了,没有可用的描述符(Descriptors)来存放新数据。
- 原因:软件处理速度太慢。你的应用程序(或内核协议栈)从网卡挪走数据的速度,赶不上行情爆发时数据进入网卡的速度。
- 解决方向:增大网卡 rx 环形队列长度(ethtool -G),并使用 OpenOnload 旁路内核。
- port_rx_dp_di_dropped_packets:20630668 (严重警告)
- 含义:数据路径/交付接口丢弃(Data Path / Delivery Interface drops)。
- 深层解释:这是 Solarflare 特有的硬件计数器。它表示数据包在网卡内部的交付路径上被丢弃。通常发生在网卡的内部缓冲区(Internal FIFO/SRAM)也满了,或者由于总线压力(PCIe 拥塞)导致网卡无法及时将数据传送到主内存。
- 原因:系统在高负载下出现了瓶颈。可能由于 CPU 频繁进入省电模式、PCIe 槽位带宽不足、或者是多个网卡接口共享资源导致冲突。
- 严重性:数值高达 2000 万,说明在行情高峰期,网卡已经处于严重的过载状态。
- 含义:因无法分配 skb(内核套接字缓冲区)而导致的丢弃。
- 分析:数值为 0,说明 Linux 内核内存是充足的。丢包不是因为系统没内存了,而是因为硬件队列处理不及时。
- 含义:在使用 XDP(Express Data Path)时被丢弃的包。
- 分析:数值为 0,说明你当前可能没有使用 XDP,或者 XDP 逻辑没有主动丢包。
如果优化后这些指标没有显著增长则说明优化有效。
欢迎关注我的公众号“量化实战”,更多原创技术文章第一时间推送,如有加量化交流群需求,也可在公众号后台留言。