Intel ADQ技术:为100G网卡打造专属队列,突破高吞吐低延迟瓶颈

发布时间:2026/10/19 9:32:46
Intel ADQ技术:为100G网卡打造专属队列,突破高吞吐低延迟瓶颈 做网络性能优化的人多半都遇到过这个魔幻场景网卡标称100Giperf3单流也能跑到七八十G可一旦换成真实业务流量吞吐直接腰斩延迟毛刺还一抖一抖的。我们在某数据密集型业务上就踩过这个坑当时怀疑过应用程序、怀疑过内核协议栈折腾了一圈最后把目光落到了网卡本身的队列机制上才算是找到症结。这次要聊的 Intel 应用程序队列ADQ技术就是冲着高吞吐下保住低延迟这个难题来的它尤其适合在100G以太网卡上处理延迟敏感、流量又大的业务场景。先说这篇文章适合谁。如果你手里正好有支持 ADQ 的100G网卡比如 E810 系列正在被高 CPU 占用、尾延迟飙升、多队列负载不均这些问题困扰或者你在做网关、缓存、存储类中间件对单连接性能和延迟可预测性有硬指标那这篇值得看完。我会把 ADQ 的底层逻辑、配置流程、实测收益边界和踩坑经验一次性讲清楚省得你再去翻一堆英文文档。1. 100G网卡跑不出理想性能瓶颈根本不在带宽很多人的第一反应是100G网卡嘛带宽够了就行。但实际一压测就露馅。问题从来不在链路速率而在数据从网卡到应用进程这条路径上的每一个环节。1.1 中断驱动模型的代价吞吐越大CPU越忙传统网卡收包靠中断数据包到了网卡触发中断CPU 停下手头的活儿去处理包。低速网络下这个模型没什么问题但到了100G这个量级每秒可能有上百万个小包。每个包一次中断CPU 大部分时间都在响应中断和切换上下文真正留给应用计算的指令周期所剩无几。我们在压测时就注意过收包进程所在的核softirq占比能到 60% 以上吞吐却卡在 30G 出头明显是 CPU 成了瓶颈。后来上了多队列和 RSSReceive Side Scaling把不同流散列到不同 CPU 核确实能缓解一部分压力但这只是把问题分摊并没有消除中断和上下文切换的开销。流量一旦集中到某几个大流散列不均匀那几个核照样被打满其他核空转。1.2 多队列的均衡不等于可预测RSS 的散列结果是基于数据包五元组算出来的它保证的是统计意义上的均衡而不是某个应用能拿到的确定性资源。同一个应用的多条连接可能被分散到不同的队列进而落到不同的 CPU 核上每个核还要跟其他应用的流量抢资源。结果就是应用感知的延迟和吞吐处在一种随缘状态这次压测结果和上次不一样低峰期和高峰期完全两个样。对缓存、搜索、金融交易这类业务来说这种不确定性是最要命的。你宁可平均延迟稍高一点也不能接受 p99 延迟突然飙到几十倍。1.3 延迟毛刺的真正来源锁、缓存失效和上下文切换我们最初把毛刺归咎于网络抖动后来用perf和bpf抓了下内核栈发现真相很朴素多个线程同时收包必然要碰共享的 socket 锁和协议栈的全局资源一旦涉及跨核访问CPU 缓存全部失效数据得从内存重新拉再加上中断线程和应用线程之间反复调度这三个因素叠加延迟毛刺就这么出来了。所以想解决 100G 网卡场景下的性能问题思路不能停留在把带宽跑满而是要回答另一个问题怎么让一个应用在固定的一组 CPU 上用固定的一组队列以最小开销把包收走。ADQ 解决的就是这件事。2. ADQ 的四个关键设计让应用拥有一条专属车道ADQ 全称 Application Device Queues直译就是应用程序设备队列。它的核心思想不复杂与其让大家挤公共通道不如给关键应用单独修一条车道。但落到实现上有几个设计细节非常关键理解透了才能用好。2.1 应用专属队列把队列从共享资源变成独占资源普通网卡的队列属于网卡所有应用共享。ADQ 的做法是把一部分队列单独划分出来专门服务于某个应用或者某类 socket。拿生活里的例子类比普通队列是高架桥什么车都能上高峰期混在一起谁都走不快ADQ 相当于给特定车辆开了条专用隧道隧道里的车流量是可控的拥堵自然可控。实际操作中这意味着你可以为核心业务分配 4 个、8 个甚至更多队列这些队列不会再被其他应用的数据包干扰。用ethtool能看到网卡队列数量但真正把队列划给应用还需要配合流量定向规则把属于该应用的连接精确导入专属队列。值得强调的是ADQ 不是简单的优先级调度。优先级只是让高优先级包排在前面但包仍然经过同一套处理路径中断、锁、调度开销一点没少。ADQ 是从资源隔离层面解决问题效果完全不同。2.2 忙轮询Busy Polling用 CPU 换延迟ADQ 另一个关键机制是忙轮询。传统收包路径里应用阻塞等待包到了中断唤醒它ADQ 则允许应用所在的 CPU 核持续轮询队列数据一到立刻取走省掉了中断唤醒、线程调度、上下文切换这一整套开销。代价也很直观轮询期间 CPU 核是满负荷转的。所以 ADQ 的实践套路里一定要给应用分配专属 CPU 核并且保证这些核不跑其他任务。我们在压测里看过数据打开忙轮询后包处理延迟的抖动区间从原来的几十微秒缩小到几微秒代价是那两个核的usr占比接近 100%。说白了用一部分 CPU 算力换确定性的低延迟在高价值业务上是划算买卖。2.3 CPU 与内存亲和性把数据放在手边ADQ 配套的还有亲和性控制。网卡队列有它自己的中断 CPU应用线程也应该绑定到同一个 NUMA 节点上的 CPU 核内存分配也要在本地节点。否则数据包从网卡 DMA 到内存应用再去跨 NUMA 读取远端内存访问的延迟能比本地高出 30% 到 50%前面的优化全部白做。这一点我们在部署时差点漏掉。一开始只绑了网卡中断没绑应用线程结果压测数据忽高忽低后来用numactl把应用绑到和网卡同一个 NUMA 节点数据才稳定下来。后面实操部分我会给出具体的绑定命令。2.4 ADQ 与 RSS、Flow Director 的关系不是替代是叠加很多人会问RSS 不也是多队列吗Flow Director 也能做流量定向ADQ 和它们到底什么关系简单说RSS 负责把不同流散列到不同队列它解决的是多核分摊Flow Director 负责把特定流精确送到某个队列它解决的是定向ADQ 则在定向的基础上进一步把这个队列从协议栈路径、锁竞争和中断机制里拎出来配以忙轮询让应用直接面对一个低开销的数据通道。换句话说ADQ 站在 RSS 和 Flow Director 的肩膀上把它们的弱项补掉了。实际配置 ADQ 时底层往往仍然要用 Flow Director 的 ntuple 规则来做流分类。3. 实操在 100G 网卡上把 ADQ 完整跑起来这部分我按自己的实际部署顺序写尽量还原每一步包括那些容易忽略的检查点。硬件方面以 E810 系列 100G 网卡为例驱动用ice系列驱动系统是常见的 x86 服务器配 Linux。3.1 前置条件确认硬件和驱动支持不是所有 100G 网卡都支持 ADQ。Intel 的 E810 系列是明确支持这一特性的但具体到每个功能还要看网卡固件和驱动版本。我的建议是先把驱动升级到官方最新稳定版因为 ADQ 相关代码和参数随驱动迭代变化很快旧版本很可能缺参数或存在 bug。检查固件和驱动版本# 查看网卡固件版本 ethtool -i enp1s0f0 # 查看驱动加载状态 cat /sys/module/ice/version如果输出里的firmware-version和driver版本较老先去官网下载对应的驱动包重新编译安装。这一步别跳过我们最开始用系统自带的驱动版本ethtool高级功能选项都看不到升级完立刻正常。3.2 确认队列能力和中断绑定先用ethtool确认网卡队列数和当前的队列分配# 查看网卡最大队列数和当前生效队列数 ethtool -l enp1s0f0 # 查看收包队列的队列数combined 就是收发共用队列 ethtool -L enp1s0f0 combined 16把 combined 队列设为 16 或 32 是一个常见起点。队列数太少并发流容易挤在一起队列数太多中断和内存开销反而增加。E810 单端口一般支持到 64 甚至更多队列但没必要盲目拉满。我们是按业务并发连接数来定的最终 16 个队列跑得最稳。中断绑定这一步要拿到每个队列对应的中断号# 查看队列和中断号的映射 cat /proc/interrupts | grep enp1s0f0然后手动设置中断亲和性把各队列的中断绑定到不同 CPU 核。这里有个小技巧需要把中断绑定到应用将要运行的那一组 CPU 核上同时尽量保证这些核属于同一个 NUMA 节点。后面绑定应用线程时要和这里保持一致。3.3 配置流定向规则让应用的连接进入专属队列创建专属队列之后还得告诉网卡哪些包进这些队列。这一步依赖网卡的流量定向能力在驱动里通常体现为 ntuple 规则。确认一下功能开启# 打开 ntuple 流定向功能 ethtool -K enp1s0f0 ntuple on这条规则可以精确匹配协议、源地址、目的地址、端口等五元组。例如把目的端口 8080 的 TCP 流量送到队列 8ethtool -N enp1s0f0 flow-type tcp4 dst-port 8080 queue 8不过ADQ 的完整配置通常不是这么几条命令就能搞定的。在我的实践中更推荐写一个配置脚本把常用端口、应用 IP 都列进去规则批量下发。一旦规则冲突用ethtool -n enp1s0f0查看现有规则清单排查起来会方便很多。3.4 绑定应用线程和内存节点这是最容易被忽略的一步。如果应用线程跑在跟网卡中断不同的 NUMA 节点上数据跨节点搬运的开销足以抵消 ADQ 带来的收益。在启动应用时用numactl同时绑定 CPU 和内存节点。例如网卡在 node0那应用也绑到 node0numactl --cpunodebind0 --membind0 ./your_app如果应用是多线程的还可以结合taskset把不同线程绑到 node0 下的不同核上taskset -c 0-7 ./your_app注意核的编号要先查清楚lscpu或numactl --hardware能看到节点和核的对应关系。3.5 调优协议栈参数降低中断与调度开销驱动层面打开忙轮询后系统层面的几个参数也值得同步调。以下是我在用 E810 时比较关注的一组# 调低软中断合并阈值让包更早进入处理流程 sysctl -w net.core.busy_read50 sysctl -w net.core.busy_poll50 # 关闭本机接收校验和卸载中的一些不必要的分担避免增加额外路径 # 具体项目请结合驱动文档调整注意busy_read和busy_poll的单位是微秒设得太小没效果设得太大 CPU 空转严重。我们试过 20、50、100 三档最终 50 是收益和 CPU 开销的平衡点。4. 实测数据与收益边界哪些业务该用 ADQ配置完成后如何判断有没有效果我的建议是别只盯吞吐率要看延迟分布和 CPU 开销的联合变化。4.1 延迟指标的改善p99 和 p99.9 明显收敛我们用一个模拟网关程序做过对比测试同样在 100G 网卡上跑 10 万并发连接业务包含大量小包转发对比开 ADQ 前后的延迟分布。指标未开 ADQ开启 ADQ平均延迟68 微秒22 微秒p99 延迟310 微秒41 微秒p99.9 延迟1.8 毫秒73 微秒收包 CPU软中断占用63%18%从这张表能看到ADQ 对平均延迟的改善是 3 倍左右但 p99.9 的改善接近 25 倍。这正好对上了它的机制去掉中断、锁和上下文切换之后大部分毛刺被削平了。对于看重尾延迟的业务这个收益是决定性的。4.2 吞吐和多流混部场景吞吐方面单流大包传输其实提升不明显因为大包路径本身开销占比小。但在多连接、小包混合的转发场景收益就出来了。我们做了另一个测试同时跑 200 个并发连接每个连接发 256 字节的小包开启 ADQ 后总吞吐从 42G 提升到 61G接近 50% 的增幅。原因不难解释小包场景下中断次数和协议栈开销占比最大ADQ 恰好把这两部分给省掉了。4.3 收益有限的场景别盲目折腾ADQ 也不是万能药。几种情况我建议别抱太高期望一次只跑一个大流、包尺寸又接近 MTU 的场景性能提升很有限传统多队列加适当调优就够了。应用本身 CPU 不密集、延迟不敏感比如离线批处理、日志传输ADQ 反而白白占用 CPU 核。走sendfile或splice这种内核侧零拷贝路径时ADQ 的部分优势会被抵消因为收包路径和发送路径优化不总是完全对称。在调研时我们还对比过 DPDK。DPDK 走完全用户态轮询驱动性能上限很高但代价是应用要改造成本大、需要独占网卡、和多进程模型配合复杂。ADQ 的优势是仍然走内核协议栈应用代码基本不用改属于性价比极高的兼容型优化。如果你的业务能接受 DPDK 的复杂度它可以做到更强的极致性能但如果想低投入获得确定性延迟ADQ 显然更合适。4.4 与 XDP、io_uring 的取舍我们也测过 XDP。XDP 在网卡驱动层直接处理包性能极其凶猛但问题在于它能做的处理相对有限一旦需要进协议栈、或者做复杂的业务逻辑XDP 就要退回内核路径收益大打折扣。io_uring 则是从异步 IO 角度优化解决的是应用和内核之间的交互效率和 ADQ 并不冲突甚至可以在某些场景叠加使用。简单总结我在选型时的判断逻辑先用 ADQ 把协议栈路径的确定性拉起来再看有没有进一步优化的必要如果还不够再考虑引入 XDP 或 DPDK。这样风险和改造成本都更低。5. 实操中的坑与最终自检清单ADQ 配置踩坑概率不低这里记录几个我们真实遇到过的坑以及我最终沉淀下来的一套自检清单。5.1 坑一队列绑了但应用跑在另一个 NUMA 节点有一次配置完 ADQ压测数据不升反降。我们用perf一看内存访问延迟异常偏高才意识到应用线程被调度到了 node1而网卡和专属队列都在 node0。跨节点访问导致每次收包都要走远端内存延迟多出几十微秒。解决办法就是前面说的numactl --cpunodebind0 --membind0。另外还要确认 BIOS 的超线程设置和isolcpus内核参数确保轮询核上不会跑其他杂活。5.2 坑二中断合并参数和忙轮询打架E810 这类网卡本身有中断合并interrupt coalescing机制默认的合并参数偏向于吞吐场景可能积压大量包才触发一次中断。ADQ 的忙轮询逻辑是靠数据包到达尽快唤醒的如果合并阈值设得很大忙轮询的优势会被延迟暴露。我们当时调了ethtool -C enp1s0f0 rx-usecs 0之类参数把合并延迟压到最低并配合adaptive-rx on参数才看到理想的延迟效果。具体参数名称因驱动版本而异方向就是让包尽快暴露给驱动层。5.3 坑三多队列规则冲突导致流量还是走到默认队列用 ntuple 规则做流定向时如果规则写得不够精确或者云平台开启了一些虚拟化卸载功能流量可能匹配不到专属队列静默走默认队列。排查时用ethtool -S enp1s0f0看各队列的收包计数对比一下专属队列是否真的有包进入。如果专属队列计数为 0说明规则没生效优先检查 ntuple 开关和规则冲突。5.4 最终自检清单我把每次部署后必查的几项整理成清单你可以直接抄走检查项命令期望结果网卡固件和驱动版本ethtool -i enp1s0f0版本较新支持 ADQ队列数量ethtool -l enp1s0f0combined 队列数符合预期ntuple 定向功能ethtool -k enp1s0f0ntuple 为 on队列中断亲和性cat /proc/interrupts各队列中断落在预期核上专属队列实际收包数ethtool -S enp1s0f0专属队列计数持续增长应用线程绑定taskset -p pid线程绑在预期的 NUMA 节点核上延迟指标sockperf或自研压测p99.9 明显收敛且稳定做完这些检查基本可以确定 ADQ 是否真正起作用了。在我自己这几年的经验里ADQ 属于那种配置半小时、收益一整年的类型。它不要求你重写应用不要求你放弃内核协议栈就能把 100G 网卡的高吞吐潜力真正转化为延迟可预测的服务质量。不过它也考验人的细心程度队列分配、中断绑定、NUMA 亲和、流定向规则每一个环节偷懒数据都会诚实地给你脸色看。希望这篇能把你在配置路上可能踩的坑提前填平。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询