
做RoCE网络交换机这摊事做了好几年这个系列一路写下来也到了第七十二篇。前几篇在最小环境里验证了单台TOR交换机上的RoCE无损模型也就是模型01。这次要聊的模型02是把它从一台交换机扩展到多台、跨机柜、甚至带核心层的完整网络形态。标题里这个“02”不是版本号那么简单它意味着设计思路要从“验证可行”转向“规模可用”。RoCE网络交换机模型02确切地说是一套面向RoCEv2业务的多级交换网络配置与缓冲调优方案。它解决的核心问题是当服务器从几台变成几十台甚至上百台当流量从单打独斗变成incast、广播、多打一无损队列还能不能稳住端到端的时延还能不能压住。这套内容适合正好要搭建或改造RoCE集群的运维和网络工程师也适合已经被PFC风暴折磨过、想搞懂底层逻辑的人。1. RoCE交换机模型的核心设计思路1.1 模型01遗留的问题在模型01里我们验证的是单台TORTop of Rack交换机下挂几台服务器的情况。那时拓扑简单、队列浅、流量压力有限配置PFC和ECN之后跑perftest带宽能打满时延也好看。但模型01有几个问题根本没暴露出来。第一个是跨交换机路径的buffer分配问题。单台交换机时所有RoCE流量共享这一台设备的buffer头拥塞HOL blocking的影响范围有限。一旦接入层和核心层串起来每一跳的交换芯片都在独立管理自己的缓冲某个交换机缓冲耗尽PFC就会一路反压到源端造成所谓“PFC风暴”。模型01没法回答的是反压传导到第几跳就该停谁来当兜底。第二个问题是无损队列的“一刀切”。模型01里所有RoCE流量都丢进同一个无损队列这在测试环境没问题但真实业务里控制平面消息和存储IO混在一起如果全部走无损队列一个偶发的批量任务就能把整条链路拖垮。这个矛盾模型01完全没解决。第三个是拥塞信号和跨设备标记不一致。ECN标记是在交换芯片上打的模型01我们只在一台交换机上调了阈值。多设备之后每台交换机的队列深度基线不一样上游已经标记了下游还在全速转发E2E拥塞信号就是一锅粥。1.2 模型02的设计目标模型02一开始就从三个维度重新定义了目标链路无损、拥塞可见、故障可控。链路无损不是指每一跳都开PFC而是设计出哪几跳必须开、哪几跳靠ECN消化。通常的做法是在接入层到服务器这一侧开启无损队列汇聚和核心之间可以靠大缓冲显式拥塞通知来处理。这里要权衡的是跳数的数量——每多一跳无损PFC死锁的可能就多一分。环境越小越容易忽略这个问题等扩展到几十台交换机时死锁会非常频繁。拥塞可见指的是所有交换机对ECN标记阈值的理解要统一。模型02引入了整网ECN基准线的概念所有设备使用同一套kmin/kmax基线再根据端口速率做等比缩放。这样从服务器的视角看整条路径上收到的拥塞标记有明确意义而不是某台设备随机触发。故障可控则是指PFC还是会发生但我们要能快速定位是哪一跳、哪个队列触发的。为此模型02在每台交换机上单独维护了PFC死锁检测和计数器上送机制构建出一张全局反压传导图。这个在模型01里是完全没有的。1.3 从“无脑无损”到“业务分级”模型02里我最想强调的设计理念变化是放弃了“全无损”的执念。业界常见的误区是既然跑RoCE所有流量都应该进无损队列。实际操作下来会发现无损队列引入的是反压和排队对时延敏感的短流并不一定友好。模型02的思路是把RoCE流量根据特征分成三档。第一档是存储类的长流和控制同步消息需要极低的丢包进TC3无损队列。第二档是高突发但容忍微小的重传的业务放在TC2采用普通优先级调度但不启用PFC完全靠ECN拥塞控制算法扛。第三档是后台运维和日志流量直接进传统best-effort队列与无损彻底隔离。这个分级看着简单实际做起来需要每台交换机的队列模板全部对齐而且服务器网卡侧也要匹配。模型01里一张模板打天下的做法在这里会直接导致队列错配。所以模型02系列我把业务分级放在第一条因为后面所有buffer和调度的配置都基于这个前提。2. 无损链路怎么搭PFC与ECN的联动配置2.1 PFC无损队列的开关与死锁陷阱PFC的原理不复杂接收端交换机检测到某个优先级队列的占用超过门限就发送暂停帧给对端请它暂停发送指定优先级的流量。一帧PFC只能解决局部拥塞但当拥塞点深埋多条链路后面时暂停会一级一级向上传递最终把某个源端服务器死死按住。模型02里对PFC最重要的改变是只为真正需要无损的TC3队列开启PFC并为每个无丢包队列配了独立的watchdog定时器。这里我吃过亏某次调整后发现一台交换机上所有队列的流控都开着PFC风暴没征兆时就来了整网吞吐直接接近零。排查时打开show interfaces pfc一看TC0到TC7全是PFC enabled头都大了。具体的PFC参数设置上模型02采用的是推荐阈值开PFC的队列头阈值headroom按线速下的RTT时延来算。比如100G端口单跳RTT约2微秒结合线速换算至少需要预留约500KB的headroom。这不是拍脑袋定的在跨机柜测试时headroom不够的直接反应是远端拥塞时本端口反复出现丢包而PFC帧计数却在疯狂上涨。在具体启用PFC时还要做一步经常被忽略的操作关闭端口流控的自动协商手动指定PFC方向。有些厂商的交换机默认支持双向PFC协商也就是DCBX里把pfc enable的意愿发给网卡。在模型02环境里我碰到过网卡驱动对PFC自动协商支持不佳的情况明明是同一厂商的交换机链路对端服务器却起不来无损队列。后来统一改成手动模式指定发送和接收方向都开启这个问题才消失。2.2 ECN拥塞信号的两级阈值ECN的机制是在数据包经过交换机时如果队列深度超过配置的kmin阈值就在IP头里打上ECN标记。接收端看到标记后会通过拥塞控制机制通知发送端降速。ECN的最大价值是可以不经暂停帧直接“软”反馈给源端代价是需要RDMA整套拥塞控制配合。模型02里ECN配置的难点是如何同时配置好kmin和kmax。kmin太低链路稍有一点波动就直接标记等于制造了不必要的降速kmax太高标记生效就晚缓冲已经快满了。比较实用的参考是kmin设置为该端口带宽时延积的50%kmax设置为带宽时延积的2倍。按100G端口计算假设RTT 10微秒带宽时延积约125KB那kmin约64KBkmax约256KB。当然这只是一个起步数据实际运行还要观察监控曲线微调。还有一点容易漏ECN只有对应在ROCEv2的UDP包上才有效交换机必须能识别RoCEv2报文并对其队列应用ECN标记。很多交换机需要配置qos ecn对特定队列打开WRED如果只开了ECN却没关联到无损队列的WRED配置ECN标记根本不会生效。这个问题我在一次现场验证中才发现用iperf流量跑不出来打开队列计数才看到ECN包一直是0。2.3 参数组合参考表为了让配置可落地我把模型02里一套基础参数整理成参考注意不同芯片和交换机厂商的字段名会有差异。配置项接入交换机核心交换机备注RoCE队列映射TC3TC3使用DCB优先级8PFC使能队列TC3不使能核心靠ECN和buffer吸收ECN标记队列TC3TC3需配合WREDkmin端口速率的50% BDP端口速率的80% BDP核心阈值可适度调高kmax端口速率的2倍 BDP端口速率的3倍 BDP核心大缓冲优势利用headroom按RTT线速预留无需额外配置防止PFC触发后丢包WRED丢弃概率不丢弃不丢弃RoCE队列不开随机丢弃上面这套参数在测试环境跑出来的效果不错但关键是“必须每台设备都对齐”否则跨设备时延和标记行为无法预测。我记得有次联调核心交换机kmax少配了一位数结果看起来没丢包时延曲线却在每200毫秒出现一次尖峰抓包才看到是ECN不停地在阈值边缘抖动。3. 缓冲与调度交换芯片层面的关键细节3.1 Ingress与Egress缓冲的划分逻辑交换芯片内的buffer管理通常分为入方向和出方向两部分。入方向buffer负责暂时缓存在查表转发过程中来不及处理的数据包出方向buffer负责在端口发送队列中排队。模型02里要特别重视出方向buffer因为PFC及ECN判断的队列深度基本都是看egress队列的占用。很多人为了省事把buffer的大头全部划分给入方向。这在普通L2/L3交换业务里可行但对RoCE很危险。原因是RoCE流量的拥塞通常出现在出端口聚合处比如12台服务器同时向一台存储节点发数据出端口只有100G入端口加起来有1200G大量数据在出端口排队。如果egress buffer不足直接丢包PFC即使有headroom也救不了。我常用的做法是给RoCE相关队列的egress预留总buffer的70%以上uid的优先级最高。实际操作中某些交换芯片还需要把全局buffer池拆分到cell不能直接按端口百分比配置。这时要观察队列丢包计数逐步把共享池额度放大直到模型02压测场景下无丢包为止。3.2 Headroom与动态buffer的关系交换机在启用PFC的那个队列上需要留出一块专用空间叫headroom buffer。它的作用不是缓冲排队而是当PFC暂停帧已经发送但对端还在飞行中的数据这段数据需要一个落脚的地方否则就丢了。在模型02的多级网络中headroom的计算不再是单跳而是要考虑从PFC源发点到暂停接收方之间所有链路上的在途数据。对于100G端口飞行中的数据约等于端口速率乘以链路传播时延。但不同交换机内部还有无时钟对齐问题实际上每台交换机建议至少预留2倍的单跳RTT数据量作为安全余量。动态buffer的关注点在于PFC触发的时刻不是只由队列深度决定还受可用共享buffer大小影响。如果某台交换机全局共享buffer池被其他普通业务占满了RoCE无损队列即使没到阈值也可能拿不到buffer而直接丢包。在模型02配置里我通常将RoCE流量设为共享池中的最高优先级或直接给它分配独立buffer池双保险。3.3 队列调度与WRED队列调度层面模型02用的是严格的优先级调度Strict PriorityTC3排在最高位。这里不是拍脑袋做的最优解因为RoCE对时延极其敏感任何基于权重的调度都会引入额外的排队抖动。也许有人担心TC3一直占着线速让其他普通业务饿死实践里面TC3的业务通常控制在总带宽30%以内剩余带宽足够普通业务使用。WRED在这个模型里只针对非RoCE队列开启RoCE队列不做随机丢弃。如果漫无目的地对RoCE队列启用WRED任何丢包都会直接推高PFC触发次数结果就是链路抖动。我遇到过某厂商交换机默认把所有队列的WRED都开着团队最初没发现后来做长稳测试时总出现小概率丢包查了很久才定位到是WRED在RoCE队列上误伤了数据包。调度和WRED的调优有很强的现场性。模型02的一个经验法则是先跑一轮perftest看看带宽是否达标再把WRED的drop概率调成0并观察PFC计数变化。如果PFC计数不降反升大概率是调度上RoCE队列被次级队列插队了。这种问题只能逐台交换机看队列统计没有捷径。4. 从模型到落地完整部署与验证流程4.1 拓扑设计与VLAN/VXLAN规划模型02的典型拓扑是接入-核心两层结构。接入交换机承担服务器接入和RoCE队列终结核心交换机负责跨机柜转发。这里有个原则RoCEv2是三层可路由协议所以核心层使用IP路由而不是二层大广播域。如果不做路由隔离ARP广播会在全网扩散不仅浪费CPU还会周期性干扰无损队列。地址规划上建议每个机柜单独划一个RoCE网段例如默认网关放在接入交换机上。VLAN只作为二层隔离手段不建议跨核心传RoCE二层域。如果必须跨三层那就用VXLAN封装具备的负载分担能力会优于普通VLAN转发。在模型02里我租了用VXLAN测试多路径负载均衡饱满很多ECMP能更均匀地拆分流整个集群吞吐提升明显。4.2 交换机侧与网卡侧的配置清单实际配置时我习惯写一个统一的脚本模板每台交换机只改端口和IP部分。以下是一段简化后的模型02交换机侧配置示例以通用NOS风格编写。# 全局开启DCBX和QCN的硬件支持 dcb enable # 定义RoCE队列映射为TC3 class-map type qos match-any ROQUEUE match dscp 26 27 policy-map type qos QOSMAP class ROQUEUE set cos 3 set queue 3 # 在RoCE队列上配置ECN与PFC interface Ethernet1/1 service-policy type qos input QOSMAP priority-flow-control mode on cos 3 no flowcontrol random-detect ecn cos 3 random-detect minimum-threshold cos 3 64 random-detect maximum-threshold cos 3 256这里面的dscp 26 27对应RoCEv2默认的DSCP值很多环境实际走的是AF42或CS6需要根据网络团队已有的DSCP策略映射保持一致否则交换机根本不会识别。网卡侧配置同样关键。Linux主机上需要保证RoCEv2使用的DSCP出包与TC映射一致。命令大致是# 设置DCB priority到TC3允许PFC mlnx_qos -i enp1s0f0 -p 0,0,0,0,0,0,0,0,0,3 # 设置trust模式为DSCP mlnx_qos -i enp1s0f0 --trustdscp服务器侧如果没配置对交换机发出来的PFC暂停帧网卡不会响应整个无损链路就是名存实亡。我在模型02验证中最常翻车的点就在这交换机配置都正常网卡侧某台机器忘了同步脚本导致那台机器成为整网的“黑洞”拖累同机柜所有业务。4.3 验证、压测与微调链路配置完成后验证分三步走。第一步用perftest相关工具比如ib_write_bw测试单流和16流的带宽和时延。单流主要看是否有单点瓶颈16流能体现ECMP和多队列的负载均衡能力。第二步看交换机计数show hardware buffer、show interfaces pfc counters、show platform pm counters这类命令跟踪PFC触发次数和队列深度。如果PFC触发频繁说明某条链路经常接近拥塞需要调高ECN阈值或者调整流量分布。第三步是微调阶段。我会按1分钟粒度的监控观察ECN标记率。如果标记率低于0.1%可以放心如果高于1%就要预警然后一层层检查哪个端口的队列深度超限。模型02的经验是宁可让ECN标记稍微早一点也不要等到PFC介入。通过调低kmin 10%-20%观察收益经常能稳定整网。5. 避坑实录常见故障定位与修复经验5.1 配置了无损依然丢包这是现象调查里出现频次最高的问题。无损队列开着PFC计数却很少但应用偶尔超时或者看到RocE重传。按我的排查顺序首先是查服务器到交换机这一段有没有网络设备把PFC帧吃掉比如中间有网线转光模块、或者接了一个不被管理的媒体转换器这类设备通常不转发PFC控制帧等于静默丢包。其次看交换机对端口的flowcontrol自动协商状态。有些交换机接口默认flowcontrol receive on如果对端网卡也在协商两边可能会协商出不同的PFC参数导致交换机认为开启了无损实际上PFC从未生效。在模型02环境里我统一强制设置flowcontrol receive off只保留手动指定的priority-flow-control这样就不会被协商结果误导。5.2 PFC风暴导致整网异常PFC风暴的典型表现是某端口的TX PFC计数持续增长对端应用带宽骤降CPU占用升高。定位方法是用交换机的show interfaces priority-flow-control查看计数异常端口然后沿该端口逐跳向上追踪风暴源头。我在一次现场排障中发现根本不是拥塞导致的而是某台服务器的网卡驱动bug在队列溢出时不停发PFC暂停帧整机每秒发送几千帧把对端几十条RoCE流全停住。后来给那个网卡更新驱动问题立即消失。PFC风暴不一定来自交换机主机侧也要纳入排查范围。模型02里我建议所有无损端口启用deadlock detection功能例如设置一个超时时间当PFC暂停持续超过几毫秒就自动使能链路恢复机制。这个功能曾经在极端情况下被panic但多数时候它能把僵尸链路从死锁里救回来。5.3 定位工具与抓包要点RoCE抓包和普通TCP抓包比有很多差异因为数据本身是RDMA的UDP流有大量infiniBand头信息。排查过程中我主要用交换机的tcpdump抓RoCE控制面比如RoCE的CONN_REQ而不是抓数据面。数据面抓到后要看IP头的ECN标志位是否置位还要注意UDP目的端口4791这是RoCEv2的默认端口。定位ECN问题是可以用飞塔或Wireshark的过滤器统计ECN字段。例如ip[1] 0x03 ! 0能快速筛出打了标记的UDP包。如果某个服务器持续收到大量ECN标记包而该服务器又不在拥塞路径上那往往是交换机侧ECN阈值配低了反而不正常。5.4 几条保命经验结合这些年做过的RoCE项目最后分享几条真实心得。第一不要把无损队列扩展得太宽能不开PFC的链路就尽量不开无损只解决极少数长流场景多数转发交给ECN。第二所有交换机配置变更前先对比该交换机上的PFC、ECN计数器存个基线事故复盘全依赖这些数据。第三交换机的硬件buffer数据分析工具记下来新遇到的很多问题都靠它定性比方说突然丢一个大包计数器会告诉你到底是headroom不够还是共享池耗尽。RoCE网络交换机模型02这套东西不是一蹴而就的。从单台交换机验证走到多级网络每一步配置和调优都比较费心但把PFC、ECN、缓冲池这三件事想透之后整个集群的性能会很稳。后面我还想针对模型02里的动态拥塞控制算法做一轮实测对比找出更适合大规模加速卡集群的配参组合到时候继续更新系列。