ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Scale-up/Scale-out下网卡与IO Die端点微架构拆解

Scale-up/Scale-out下网卡与IO Die端点微架构拆解 做服务器网络和系统架构这十几年我被人问得最多的一类问题是“交换机都 51.2T 了网卡也 400G 了链路为什么还是跑不满”答案往往不在链路上而在端点。这篇要聊的就是 Scale-up 与 Scale-out 两种扩展方式下网卡本体和 IO Die 这两块微架构的设计逻辑——它们怎么把线速吃下来又怎么在延迟和一致性上把自己逼到墙角。如果你在做服务器选型、存储/计算集群组网、RDMA 调优或者单纯想在 400G/800G 时代不被“标称带宽”忽悠这篇内容基本能覆盖你 80% 的疑问。剩下的 20%是你自己机箱里那几块卡的 BIOS 设置和 NUMA 亲和性——那部分只能动手。1. 先分清 Scale-up 和 Scale-out 分别在向端点要什么1.1 两种扩展方式在网络语义上的差别Scale-up 和 Scale-out 经常被当成“买更大的机器”和“买更多的机器”这种粗线条说法但只要落到微架构层面两者对网卡和 IO Die 的要求几乎是两个方向。Scale-up 关心的是域内语义一个小规模的紧耦合域通常一个机箱、一个刀片、一个超节点die 与 die 之间用私有互连或类 CXL 的链路连起来语义单元是 cache line目标是让人看不出这是一堆芯片。它要的是内存语义 一致性 低延迟能容忍的拥塞很小一旦出现重传或者 cache line 乒乓性能是断崖式下跌。Scale-out 走的完全是另一条路。它的语义单元是消息节点之间通过以太或 RDMA 组网规模从几十到上万节点拓扑是 Clos 或 Dragonfly必须容忍丢包、必须做拥塞控制、必须能优雅降级。它要的是可预测的吞吐 相对宽松的延迟 可观测性。同一块物理网卡在这两个场景下的微架构取舍是相反的Scale-up 想要极少的队列、极低的单跳延迟、尽量少的状态Scale-out 想要极多的队列几千到几万个 flow 要隔离、强大的分流和流控、丰富的计数器以及能承受几十微秒抖动的缓冲。维度Scale-up 域内Scale-out 节点间语义单元cache line / load-store消息 / descriptor典型延迟目标单跳 100~300 ns端到端 3~20 μs一致性要求需要目录协议不需要显式刷写传输载体私有 die 间链路、CXL、NVLink 类以太 / RoCE / IB拥塞代价极高几乎不允许排队可控靠 ECN / DCQCN端点角色片内网络的一个成员一个独立的协议翻译器这张表最值得记住的是最后一行。它解释了为什么“端点才是最难的那一半”——在 Scale-out 里网卡是一个边界设备坏了换一块就行在 Scale-up 里网卡一旦被拉进一致性域它就变成了片上网络的一部分出错是整个域崩。1.2 IO Die 的出场端点从“外挂设备”变成了“片内成员”Chiplet 流行起来之后主流服务器处理器的布局基本都是“若干计算 Die 一个大 IO Die”。这个 IO Die 承担的角色远不止“把线引出来”它内部集成了 PCIe Root Complex、IOMMU/SMMU、内存控制器、die 间一致性引擎有些设计里还带一部分末级缓存切片和内存侧的一致性目录。换句话说网卡插在 PCIe 槽上但它连接的其实是 IO Die而不是“CPU”这个抽象概念。这件事的直接后果是端点的微架构不再只是网卡自己的事。一块 NIC 从网线收到包走 PHY、MAC、包处理、DMA跨 PCIe 进入 IO Die然后 IO Die 要决定这个写请求是命中 LLC、需要 snoop 远端计算 Die还是直接落内存。每一个岔路口都有自己的延迟和带宽上限而 NIC 侧的队列深度、突发特性会直接冲击 IO Die 的内部仲裁。我在实际项目里见过一个很典型的案例两块 400G 卡插在同一条 PCIe Root Complex 下游单卡测试都能跑到线速的 92%双卡同时压测直接掉到 61%原因不是 PCIe 带宽不够而是两块卡的 DMA 突发在同一时间窗口内对 IO Die 的写通道形成了竞争仲裁一抖动NIC 侧描述符环回写就延迟队列一深端到端时延立刻涨上去。1.3 为什么说端点是更难的那一半把带宽做大这件事在 fabric 侧其实是“线性”的lane 不够就加 lane波长不够就加波长交换芯片 radix 不够就堆 chiplet。物理层每往前一代工程难度确实涨但方向和收益都是清楚的。端点难在它是收敛点所有扩张的带宽最终要在几个有限的接口上被吸收——PCIe 通道、内存带宽、cache、DMA 引擎、中断队列、CPU 核。任何一环提前饱和前面的带宽就是画在纸上的。举个具体数字。400GbE 单向需要 50 GB/s 的持续搬运能力400 Gbit/s ÷ 8。PCIe Gen4 x16 的理论单向带宽是 31.5 GB/s直接用一块 Gen4 卡接 400G 端口即使不考虑任何协议开销也已经超了 60%。这就是为什么 400G 网卡几乎清一色要求 Gen5 x16 起步Gen5 x16 单向 63 GB/s看起来有 26% 余量但算上 TLP 头、DLLP 开销、描述符回写和内存读回的正反向流量真实可用余量往往不到 10%。再往上走 800GbE单向 100 GB/sGen5 x16 直接不够要么走 Gen6 x16要么把网卡逻辑塞进 IO Die 里做片内直连——这就回到了标题里那个判断端点侧的物理通道比 fabric 更早撞墙。2. 网卡微架构拆解一个包在端点里经历了什么2.1 内部功能分区的真实划分现代高性能网卡内部大致可以切成五块光/电接口与 SerDes、MAC/PCS 与包解析、包处理器含表项查找与修改、DMA 与主机接口、以及一块用来缓存描述符和包的片上 SRAM。这个划分听起来平淡但每一块的资源配比决定了卡的性格。SerDes 决定端口速率和误码率这块基本是买 IP 的活。MAC/PCS 负责帧同步、CRC 校验、流控通常会把 pause 帧的处理放在最靠前的位置因为流控必须比包处理快。包处理器的核心是表项查找宽度和流水线级数查找表塞得越深支持的规则越复杂但流水线越长、延迟越高。这块是各家差异最大的地方也是“同样是 400G为什么一块卡转发延迟 400 ns、另一块要 900 ns”的主要来源。DMA 和主机接口是最容易被忽略、但实际上最决定成败的一块。它不是一个简单的搬运工它要处理描述符环的预取、doorbell 的合并、写回的顺序、以及跨 PCIe 的事务打包。片上 SRAM 的容量决定了能挂多深的队列、能缓存多少 in-flight 描述符。这块要是小了高并发场景下你会看到队列利用率上不去、CPU 侧空转。2.2 队列与 DMA描述符环、doorbell 与预取策略我一般跟人解释 DMA 时用快递柜的类比描述符环就是那一排柜子每个柜子里写着“货送到哪个地址、多长”doorbell 就是你按的那个取件通知而网卡内部的预取引擎就是提前把几个柜子打开、把标签读进手里避免每送一件货就回去看一次柜子。这套机制里有两个坑几乎所有新手都会踩。第一是描述符环的对齐与大小。队列环如果跨了 cache line 没有对齐每次更新 head/tail 指针都要多一次无效化高包率下这部分开销能吃掉 10% 以上的 CPU。第二是doorbell 频率。每收一个包就敲一次 doorbellPCIe 上会塞满小尺寸写事务效率极低批量敲又会让延迟变高。实践中常见做法是设置一个阈值比如攒够 8 个描述符或者超时 10 μs 就敲一次这个阈值没有通用最优解必须配合你的包长分布实测。具体到参数上我会先看几个东西。ethtool -g看环形缓冲ethtool -l看队列数ethtool -c看中断合并。这三个值构成了一条非常直接的因果链环深决定能扛多少突发队列数决定能分到多少 CPU 核合并参数决定中断频率和延迟的平衡点。很多人调优只改其中一个效果当然不明显。# 先看现状 ethtool -g eth0 # Ring buffer ethtool -l eth0 # Channels / 队列数 ethtool -c eth0 # Coalesce 参数 ethtool -k eth0 # 卸载开关 cat /sys/class/net/eth0/device/numa_node # 这张卡挂在哪个 NUMA 节点2.3 中断与轮询MSI-X、NAPI 与纯轮询的取舍MSI-X 的中断向量数量决定了你能把中断散到多少个核上。一块现代网卡给 64 到 512 个向量都很正常关键不是数量本身而是向量到队列到 CPU 核的映射是不是一对一且绑定在正确的 NUMA 节点上。我见过太多机器是这样的状态网卡在 node 0中断却被 irqbalance 全甩到 node 1跨 die 中断往返一次多出 60 到 100 ns包率一高收包核全在等中断。中断合并的工作模式值得单独说一下。NAPI 的设计是“第一个包来中断之后转为轮询”这个设计的原文表述很朴素但它隐含了一个前提包到达速率足够高轮询一次能拿到多个包。如果你的业务是稀疏流量比如每秒几千个包的 RPC 长连接NAPI 的轮询预算反而会让每个包多花几百纳秒去空转。这时候要么开中断合并让中断更少要么干脆用 busy-poll代价是烧 CPU。纯轮询模式DPDK、部分用户态协议栈把中断完全去掉收包核 100% 时间在转换来的是最稳定的延迟和最高的包率。代价非常直白每个收包核都要独占一个物理核还得考虑 C-state 和频率缩放——我在一台机器上踩过这个坑BIOS 里 C-state 没关收包核频繁进出 C1P99 延迟直接劣化到原来的三倍。这类问题不靠读手册是发现不了的只能靠turbostat加压测对比。2.4 卸载能力的分界哪些该下放哪些必须留软件卸载是把双刃剑。我列一张表按我自己的经验给出适用边界你对着业务形态看就行。卸载能力该下放的场景建议留在软件的场景校验和计算几乎所有场景无TSO / LRO大包为主的批量传输小包、低延迟敏感、需要精确时延分析VLAN / 隧道封装大流量隧道网关需要复杂策略、动态隧道的场景RDMA / RoCE存储、HPC、AI 集合通信有大量小消息且需要灵活分片时慎用TLS / IPsec 卸载固定密钥、长连接的加解密会话切换频繁、密钥轮换密集时间戳PTP金融、测量类业务对时钟精度无所谓的一般业务这张表的核心逻辑是卸载适合“行为模式稳定”的流量不适合“决策频繁变化”的流量。因为卸载逻辑一旦下放到硬件它的表项更新要走控制面路径长、频率低。一个每秒新建几万个连接的网关把隧道封装全下放到硬件表项同步都能把 CPU 吃满。3. IO Die 微架构端点为什么在 Chiplet 时代彻底变了3.1 IO Die 里到底放了什么一颗典型的服务器级 IO Die内部至少包含这几样PCIe Root Complex 及其对应的几个 x16 控制器、IOMMU/SMMU、内存控制器与 PHY、die 间互连的物理层与链路层、一致性目录的一部分、以及作为末级缓存代理的接口。这些单元共享 IO Die 内部的片上网络而这块片上网络的带宽和仲裁策略就是端点性能的天花板。理解这一点的意义在于PCIe 端点的带宽不是“总线带宽”而是“共享片上网络的分配结果”。我今天实测过一个现象在同一台机器上把 GPU、NVMe 和网卡都挂到同一颗 IO Die 下NVMe 做顺序大块写的时候网卡的 P99 收包延迟会涨 40% 左右。不是 PCIe 抢不过是 IO Die 内部的写通道仲裁对突发更敏感而 NVMe 的写突发远比网卡更“贪”。所以选型时我会先看拓扑几颗 IO Die、每颗下面挂什么、die 间链路是几条、对称不对称。这些信息在lspci -tv和lstopohwloc 提供里都能看出来我建议每个人都至少跑一次对自己机器的物理拓扑形成肌肉记忆。lspci -tv # PCIe 树状拓扑看设备挂在哪个 root complex 下 lstopo --of console # 完整的 NUMA / PCI / 缓存拓扑 numactl -H # 节点与距离矩阵3.2 一条包路径的延迟构成把数字摊开看我习惯把端到端延迟拆成五段来看任何一段膨胀都能定位到具体环节。环节典型延迟影响因素SerDes / PHY20~60 ns速率、编码、FEC 开关MAC 包处理30~120 ns流水线级数、表项深度PCIe 控制器与协议层50~120 nsGen 代数、TLP 大小、ASPMIO Die 片内路由30~80 ns跨 die 与否、仲裁竞争内存子系统80~160 nsLLC 命中率、DDR 代际、跨 socket把最理想的情况加起来纯硬件的单向延迟在 250 到 500 ns 之间这是物理下限。再往上叠加软件栈内核网络栈一次收发通常在 3 到 8 μsDPDK 用户态在 600 ns 到 2 μsRDMA 单边操作在 1 到 2 μs。这些数字之间的差距就是“为什么同样的硬件有人能做到 1.5 μs RTT有人只能做到 15 μs”的全部原因。还有一笔账经常被忽略串行化延迟。一个 1500 字节的帧在线速 100GbE 上需要 12000 bit ÷ 100 Gbit/s 120 ns 才能“推”上线换成 64 字节小包只有约 6.7 ns。这意味着小包场景下延迟几乎完全由处理路径决定跟带宽没关系。反过来大包场景里串行化延迟会迅速变成主导项这时候你优化队列、优化中断收效都很有限。3.3 带宽账三个接口之间的“剪刀差”端点侧的带宽必须同时满足三个不等式缺一个都会成为瓶颈。我拿 400GbE 举个完整算例。第一是端口侧400 Gbit/s ÷ 8 50 GB/s 单向双向就是 100 GB/s 的总搬运量。第二是 PCIe 侧Gen5 单 lane 有效速率 32 GT/s × 128/130 31.5 Gbit/s ≈ 3.94 GB/sx16 就是 63 GB/s 单向。看起来够但要注意 PCIe 的读和写共享这一组 lane收包设备写内存和发包设备读内存在双向满载时会互相挤占另外描述符回写、完成报文Completion也占带宽。经验上可用效率打七折实际单向能力约 44 GB/s刚好卡在 50 GB/s 需求线下方——这就是为什么真正的 400G 双口卡会要求 Gen5 x16 并且强烈建议 BIOS 里关掉 ASPM。第三是内存侧网卡 DMA 写内存会消耗内存带宽。DDR5 单通道大约 38.4 GB/s4800 MT/s × 8 Byte一个 8 通道系统理论 307 GB/s看上去很宽但 CPU 同时还要跑业务。我一般的经验值是给网卡留出的内存带宽不超过总量的 20%超过之后业务侧的性能抖动会明显变大。按这个口径307 GB/s × 20% 61 GB/s勉强够 400G 单向双口 400G 就需要额外的内存通道或者更高效的写合并策略。端口速率单向需求PCIe 要求含冗余内存侧建议余量100GbE12.5 GB/sGen4 x8 起≥ 30 GB/s200GbE25 GB/sGen4 x16≥ 60 GB/s400GbE50 GB/sGen5 x16≥ 120 GB/s800GbE100 GB/sGen6 x16 或片内直连≥ 240 GB/s3.4 NUMA 与亲和性端点的“位置”比“数量”更重要在 IO Die 架构下一块网卡是严格挂在某一颗 IO Die 上的它天然属于某个 NUMA 节点。你在这张卡上收包数据落到内存如果处理这个包的 CPU 核在另一个节点那么每一次访问都要跨 die延迟多 60 到 100 ns带宽还要打对折。我做过一组对比测试同一块 200G 卡、同样的包率绑定在同一节点和跨节点的结果差得离谱同节点时 P99 收包延迟 8.2 μs跨节点直接到 21 μs而且 CPU 利用率更高——多出来的部分全花在跨节点缓存同步上。这个差距不是调参能补回来的只能靠拓扑对齐。做法很简单三步就够先确认卡的 NUMA 节点再确认要用的 CPU 核属于哪个节点然后把中断亲和性写死。别指望 irqbalance 的默认策略它在多卡多队列场景下的判断经常是反的。# 1. 卡在哪个节点 cat /sys/class/net/eth0/device/numa_node # 2. 该节点有哪些核 lscpu | grep NUMA cat /sys/devices/system/node/node0/cpulist # 3. 把某个队列的中断绑到指定核示例IRQ 128 绑到 node0 的 8-15 核 echo 00ff /proc/irq/128/smp_affinity cat /proc/irq/128/smp_affinity_list4. 实操把端点侧的带宽与延迟算清楚并压出来4.1 第一步确认 PCIe 链路真的跑在了协商速率上这一步看起来低级但它是排查顺序里的第一位。我遇到过至少三次“性能不对劲”最后都定位到 PCIe 链路降速一次是转接卡布线问题把 Gen5 降到了 Gen3一次是 BIOS 里某个功耗策略把链路压到了 Gen1还有一次是插槽物理上只支持 x8而所有人都以为它是 x16。# 看当前协商的速率和宽度 lspci -vv -s 03:00.0 | grep -E LnkCap|LnkSta输出里要盯三个字段。LnkCap是链路能力硬件上限LnkSta是当前状态还有LnkSta后面括号里的降级原因。如果看到Speed 16GT/s (downgraded)或者宽度显示Width x8 (ok)那就要分头查是硬件不支持是卡没插牢还是 BIOS 里 PCIe 的速率策略设成了自动降速。还有一个容易漏的点某些平台的 IO Die 上不同 PCIe 控制器能跑的最高代际不一样靠近内存控制器的那个控制器可能支持 Gen5 x16靠外的只支持 Gen4 x16。这种事只有主板手册和lspci的输出一起看才能确认标称“支持 Gen5”和“每个槽都跑 Gen5”是两回事。4.2 第二步把队列、中断、内存三者的亲和性对齐这一步的目标很明确让一个包从网卡进来到被 CPU 处理完全程不跨 NUMA 节点。实现它需要三个绑定同时成立。第一是队列数与 CPU 核数的匹配。多队列网卡通常按 RSS 把流量哈希到不同队列队列数一般设成可用收包核数的整数倍。注意队列数不是越多越好队列太多会导致每个队列的环变浅、中断向量紧张、cache 局部性变差。我的经验值是每个核一到两个队列超过之后收益递减很快。第二是中断亲和性。上面给的smp_affinity写法是最直接的但要注意 mask 是十六进制位图。核数多的时候手算很容易错用smp_affinity_list更安全直接填核号列表。第三是内存分配。收包路径上的缓冲区、描述符环这些内存必须来自网卡所属节点的本地内存。用 DPDK 的话--socket-mem参数要按节点分别给用内核栈的话靠的是进程的 NUMA 策略和numactl --cpunodebind --membind。# 一次性把某块卡的所有队列中断都绑到指定节点 NODE0 CPUS$(cat /sys/devices/system/node/node${NODE}/cpulist) for irq in $(grep eth0 /proc/interrupts | awk -F: {print $1}); do echo $CPUS /proc/irq/${irq}/smp_affinity_list done注意smp_affinity_list接受的是如8-15或8,9,10这样的格式直接填 CPU list 的原始字符串通常就能用不需要自己转成位图。填完一定要回头cat一遍确认。4.3 第三步压测矩阵——不同包长、不同流数、不同方向单跑一个iperf3得出“能跑满”的结论是没有意义的。端点侧的性能必须用一个矩阵来描述因为它的瓶颈项会随着包长和并发流数变化。我常用的矩阵是三个维度包长64B / 128B / 512B / 1500B / 9000B流数1 / 8 / 64 / 512方向单向 / 双向。每个组合记录三件事吞吐、平均延迟、P99 延迟。这个矩阵跑下来通常要一两个小时但它能立刻告诉你瓶颈在哪。比如小包单流跑不满那基本是包率瓶颈看的是 PPS 而不是带宽大包双向跑不满看的是 PCIe 或内存带宽多流小包 P99 暴涨看的是队列分配和中断亲和性。工具上带宽用iperf3 -P或ib_write_bw包率用sockperf throughput延迟用sockperf ping-pong或ib_write_lat。要注意iperf3默认会开很大的 socket buffer测出来的延迟偏乐观我一般会额外跑一轮关闭 buffer 自动调整的版本。# 带宽多流 iperf3 -c 10.0.0.2 -t 30 -P 8 -l 1500 # 延迟ping-pong 模式 sockperf ping-pong -i 10.0.0.2 -t 30 --mpsmax -m 64 # RDMA 侧 ib_write_bw -d mlx5_0 -s 65536 -q 16 -a ib_write_lat -d mlx5_0 -s 2 -a4.4 第四步观测与判读——哪些计数器值得盯着看压测跑起来之后真正有价值的信息在计数器里。ethtool -S输出的动辄几百行但常用的就那么几个我把它们整理成一张速查表。计数器含义涨了说明什么rx_missed_errors收到的包因为没有描述符被丢环太浅或 CPU 处理不过来rx_nombuf/out_of_buffer缓冲区分配失败内存带宽紧张或分配策略有问题rx_fifo_errors片上 FIFO 溢出包处理流水线跟不上线速tx_carrier_errors物理层链路问题光模块、线缆、对端端口pause_frames_xoff收到对端流控对端端点被压住了问题在对面rx_discards_phyPHY 层丢弃FEC 纠错失败或误码率偏高我判断问题的顺序是先看丢包类计数器再看流控类最后看错误类。因为丢包是性能问题流控是竞争问题错误是硬件问题三者的排查路径完全不同。配合perf还能看到更细的东西比如 LLC miss 率和跨节点的远程内存访问比例perf stat -e cache-misses,LLC-load-misses,LLC-store-misses,node-load-misses -a sleep 10 numastat -p $(pgrep myapp) # 进程内存的节点分布4.5 BIOS 与内核侧的几个关键开关软件层面能做的事情有限很多时候你必须回到 BIOS。这几个我基本是默认必查的ASPM 关掉省那点功率换来的是延迟上限Above 4G Decoding 打开否则大 BAR 分配不到多队列和大环都用不起来C-state 限制到 C1 或者直接关闭延迟敏感场景PCIe 速率策略设成固定代际不要自动协商NUMA 保持开启别为了“看起来一致”把它关掉那只会把所有问题藏起来。内核命令行里pcie_portsnative让内核直接管 PCIeiommupt让直通设备跳过地址翻译开销intel_iommuon或者对应的 AMD 选项在需要隔离时必须开。这几个参数组合起来能明显改善大页和 DMA 场景下的表现。5. 常见问题与排查实录5.1 常见问题速查表现象最可能的原因先查什么单口能满双口一起跑就掉IO Die 仲裁或内存带宽竞争两块卡是否在同一 Root Complex、numastat小包包率上不去CPU 却不高中断亲和不均或队列太少/proc/interrupts分布、ethtool -l大包吞吐正常小包延迟抖动大C-state、中断合并、ASPMBIOS 设置、ethtool -cRDMA 带宽只有预期一半队列对数量、MTU、PCIe 降速ibv_devinfo、lspci -vv跨节点流量性能差一倍亲和性没对齐numa_node、进程绑核绑内存压测一段时间后突然掉速温度触发降频或流控传感器数据、pause计数器虚拟机里网卡性能差SR-IOV 未启用或 VF 队列太少lspci看是否 VF、ethtool -l5.2 几个容易误判的场景第一个误判是把丢包当成带宽不足。rx_missed_errors涨了很多人第一反应是“加带宽”其实绝大多数情况是收包核处理不过来导致描述符耗尽。正确做法是先看收包核的%soft占用再决定是加核、加深环还是降低每包开销。第二个误判是把延迟抖动归咎于网卡。我碰到过一次 P99 从 5 μs 跳到 300 μs 的情况查了两天网卡固件最后发现是同机器上的另一块卡在做大规模 DMA触发了 IO Die 的写通道仲裁抖动。这类问题的特征是抖动和业务流量不相关但和机器上其他设备的活动强相关。排查方法是把其他设备逐个下线看抖动是否消失。第三个误判是忽略虚拟化层的开销。SR-IOV 的 VF 虽然直通但 VF 的队列数、中断向量数通常远少于 PFHypervisor 的 IOMMU 映射也会带来额外延迟。如果你在虚机里测出来的延迟比物理机高 3 到 5 μs这属于正常范围别往网卡上找原因。5.3 踩过的坑和一些不太写在文档里的经验第一别迷信网卡的标称队列数。规格书写的 1024 队列实际可用往往受限于中断向量数、MSI-X 表大小和驱动实现尤其在某些联合驱动场景下真正能开起来的可能只有几百个。选型时我会直接问厂商“在什么内核版本、什么固件版本下能实际开满”这个答案比规格表有用。第二BIOS 升级会改拓扑。有一次客户升级 BIOS 之后网卡对应的 IO Die 编号变了所有绑核脚本失效性能掉了一半。我的建议是把自己的 NUMA 拓扑信息写进部署脚本的校验环节每次上线前对一遍。第三温度对端点的隐形影响。高速 SerDes 对温度很敏感机箱风道不好时长时间压测会让误码率上升触发 FEC 纠错甚至重传表现出来就是“跑了一段时间之后吞吐慢慢掉”。这种情况在计数器里能看到rx_discards_phy缓慢增长别去查软件去查风道。第四描述符环的预取策略要配合业务。我做过一组对比把环深从 512 提到 4096小包场景的 P99 延迟反而变差了。原因是环太深预取引擎会一次性拉很多描述符进来cache 占用上升反而挤压了真正需要的热数据。环深不是越大越好它是和包率、包长、cache 容量一起算出来的。第五个小经验是关于测试方法本身的。很多人用单线程工具测完就下结论但端点侧的性能是并行系统单流测出来的数字基本只反映单核能力。我一般会先用单流建立基线再用多流看扩展性曲线当曲线在某个流数之后开始走平那个点就是端点的真实并发上限。第六个是关于多代际混插的。老卡和新卡在同一个 IO Die 下混用往往拉低整体性能因为不同卡的 MTU、流控策略、中断频率都不一样共享通道时仲裁会更频繁。如果是关键业务我建议同一下游只放同代际同型号的卡。5.4 一个完整的排查案例从 400G 跑不满到定位到 IO Die最后讲一个完整的案例因为它几乎把上面所有环节串起来了。现象一块 400G 双口卡单口压测能到线速的 88%双口同时压测掉到单口的 55%也就是整体只有 48% 左右。CPU 利用率不高没有明显丢包。第一步查链路。lspci -vv显示 Gen5 x16速率正常宽度正常没有降级。排除链路问题。第二步查内存带宽。numastat显示进程内存全在 node 0卡的numa_node是 0看起来对齐了。但用perf stat看 node-load-misses发现远程访问比例有 18%说明有一部分流量其实在跨节点。进一步查发现中断亲和性虽然设置了但irqbalance服务在运行会定时把设置覆盖掉。停掉服务、重新绑核之后远程访问降到 2% 以下。第三步查 IO Die 竞争。两块卡分别在两个不同的 PCIe 控制器上但这两个控制器属于同一颗 IO Die。用lspci -tv确认拓扑后把两块卡的中断分散到不同 CPU 核并调整了中断合并参数让两块卡的中断不要在时间上重叠。第四步调环深。把描述符环从默认的 1024 提到 2048tx侧同时提高。双口并发时丢包消失。最后结果是双口并发能到单口的 92%整体利用率 81%。剩下的 19% 里一部分是 PCIe 和 IO Die 仲裁的固有开销一部分是内存带宽的物理上限。到这一步就没法再优化了属于架构决定的边界——这也是我一开始说“端点是更难的那一半”的原因算法能把网络侧推到 95%但端点侧的最后 15%你要跟硅片商量。我个人在实际项目里的体会是端点调优最忌讳的就是“只改一个参数看效果”。网卡、PCIe、IO Die、内存、NUMA、BIOS 这几层是强耦合的一个参数的变化往往会通过仲裁和亲和性传到其他层。所以我现在做任何调优都是先把拓扑和基线完整记录下来改一个变量、做一次矩阵压测、存一份计数器快照。这套流程慢但它能保证你最后拿到的不是一个偶然跑出来的漂亮数字而是一个可复现、可解释、别人接手也能看懂的结果。
返回列表