NNetpath
原理深入预计 40 分钟

RoCEv2 与无损以太网:PFC、ECN 与 DCQCN

把 RDMA 跑在以太网上,全部难点集中在一件事:不能丢包。

学完这节你能做到

  • 解释 PFC 与 ECN 的分工,说出只配一个会怎样
  • 看懂 PFC 风暴与死锁的形成条件
  • 列出交换机与主机两侧必须对齐的配置项

建议先学跳过这几节会看不懂本节的部分推导

RoCEv2 就是把 RDMA 塞进 UDP

报文结构很朴素:

[ 以太网头 ][ IP 头 ][ UDP 头(目的端口 4791)][ IB 传输头 ][ 数据 ][ ICRC ]

外层是标准 IP/UDP,所以:

  • 能被普通三层交换机转发,能跨网段路由,不需要专用的 IB 交换机
  • 能被 tcpdump 抓到包头(但抓不到内容,数据从没进过内核)
# 确认 RoCE 流量真的在跑
tcpdump -i bond0 -nn udp port 4791 -c 20

看着很美好。但代价藏在一个假设里:RDMA 假设网络不丢包。

为什么 RDMA 受不了丢包

TCP 丢一个包,靠 SACK 精确重传那一个包,代价很小。RDMA 的可靠传输不一样, 传统实现丢一个包要 go-back-N:从丢的那个位置开始,后面全部重发。

在 400 Gbps 上这意味着什么?0.1% 的丢包率就能让有效带宽掉到个位数百分比。 这不是"性能下降",是雪崩。

所以 RoCE 部署的全部难点,就浓缩成一件事:让这条路上永不丢包。而以太网天生是允许丢包的, 拥塞了就丢——这是它设计上的自由。要把它改造成无损,得用两套机制。

PFC:按优先级踩刹车

Priority Flow Control(802.1Qbb)。交换机某个优先级队列涨到水位线时, 向上游发一个 PAUSE 帧:这个优先级你先停一下。

下游交换机队列涨到阈值
      │
      ▼  发 PFC 帧(只针对某个优先级)
上游端口暂停发送该优先级
      │
      ▼  队列泄下去后恢复

关键在"按优先级"——只让 RDMA 那条队列停,普通 TCP 流量不受影响。

PFC 的两个严重副作用

1. 反压会层层传导(congestion spreading)

A 堵了让 B 停,B 的队列于是涨起来,B 又让 C 停……一个端口的拥塞可以扩散到整个 fabric, 表现是全网莫名卡顿,但找不到哪里在丢包

2. 可能死锁

如果反压形成环路(A 等 B、B 等 C、C 等 A),所有端口互相等待,整片网络永久停摆, 只能重启交换机。这在有环路的拓扑或者路由配置不当时会真实发生。

!PFC 是最后防线,不是主力

把 PFC 当作主要拥塞控制手段是最常见的架构错误。它的正确定位是"兜底": 在 ECN 来不及反应的瞬间保住不丢包。长期依赖 PFC 说明网络设计有问题。

判断依据很直接:看 PFC 帧计数。

ethtool -S bond0 | grep -iE 'pause|prio.*pfc'

正常情况下这个数应该很少且不持续增长。如果每秒都在涨几千,说明拥塞控制没起作用, 网络在靠踩刹车硬撑。

ECN 与 DCQCN:真正的主力

ECN(Explicit Congestion Notification)的思路完全不同:不停流量,而是让发送端自己降速。

交换机队列超过阈值
      │
      ▼  在 IP 头里打个标记(不丢包、不暂停)
接收方网卡看到标记
      │
      ▼  回一个 CNP(拥塞通知包)给发送方
发送方网卡降低发送速率
      │
      ▼  一段时间没再收到 CNP 就慢慢加回来

这套端到端的闭环叫 DCQCN(Data Center QCN),是当前 RoCE 拥塞控制的事实标准。

它和 PFC 的分工:

机制作用范围反应速度定位
PFC逐跳(hop-by-hop)快(微秒级)兜底,防止瞬时丢包
ECN/DCQCN端到端慢(一个 RTT)主力,从源头压住流量

水位线要错开配置:ECN 的标记阈值必须低于 PFC 的触发阈值。 这样正常拥塞时先由 ECN 温和降速,只有突发来不及时才轮到 PFC 踩刹车。配反了, PFC 会天天触发,ECN 形同虚设。

优先级映射必须端到端一致

这是实际部署中失败率最高的环节。RDMA 流量要被识别成"那条特殊队列", 靠的是报文里的优先级标记,而这个标记在不同层有不同名字:

字段取值范围
IP 层DSCP0–63
以太网层PCP(802.1p)0–7
交换机内部TC / 队列号取决于机型

一条链路上的每一跳——主机网卡、leaf、spine、对端网卡——都必须把同一个值映射到同一条无损队列。 任何一跳映射错,RDMA 流量就会掉进普通队列,拥塞时照常被丢,于是带宽断崖式下跌。

主机侧的相关配置:

# 查看/设置 QoS:哪些优先级启用 PFC、带宽如何分配
mlnx_qos -i ens1f0

# 例:只给优先级 3 开 PFC
mlnx_qos -i ens1f0 --pfc 0,0,0,1,0,0,0,0

# trust 模式:按 DSCP 还是按 PCP 判优先级(要和交换机侧约定一致)
mlnx_qos -i ens1f0 --trust dscp

NCCL 侧对应的参数是 NCCL_IB_TC。生产配置里常见 NCCL_IB_TC=106—— 不设的话 RoCE 流量没有优先级标记,一拥塞就会被当普通流量丢掉。

×GID 选错:连得上但性能不对

一张网卡有多个 GID 条目,分别对应 RoCEv1、RoCEv2、IPv4、IPv6。选错版本会出现 "能建链但性能异常"或"直接连不上"。所以每次测试前先确认:

# 只看 v2 条目,记下 index
show_gids | grep v2
DEV     PORT  INDEX  GID                                    IPv4          VER
mlx5_0  1     3      0000:0000:0000:0000:0000:ffff:0a68:1467 10.104.20.103 v2

然后把这个 index 传给测试工具:

ib_send_bw -x 3 -d mlx5_0            # server 端
ib_send_bw -x 3 -d mlx5_0 <server>   # client 端

NCCL 对应的是 NCCL_IB_GID_INDEX。默认能自动选对的情况居多, 但一旦出现诡异现象,先用 show_gids 核对

验收清单:怎么证明它真的无损

配完不能只看"能跑通"。下面五项过了才算交付:

# 1. 链路速率与状态:每张卡都要是预期速率
ibstat | grep -E 'Rate|State|Physical'

# 2. 点对点带宽:应达到线速的 90% 以上
ib_send_bw -x 3 -d mlx5_0 <server_ip>

# 3. 点对点延迟:同机房应在个位数微秒
ib_write_lat -x 3 -d mlx5_0 <server_ip>

# 4. 压力下 PFC 帧不应持续暴涨
watch -n2 "ethtool -S bond0 | grep -i pause"

# 5. ECN 标记应该有、但不应该失控
nstat -az | grep -i ecn

再加一项集群级验收:多机 NCCL AllReduce 的 busbw 达到理论峰值 90% 以上。 这一项过了,说明整条链路(网卡、交换机、拥塞控制、拓扑布线)都是对的。

RoCE 与 IB 的取舍,一句话版本

IB 的无损来自链路层 credit 机制,网络自带,不需要你配。RoCE 的无损要靠人配, 配对了性能相当,配错了比普通 TCP 还糟。

所以决策点不在性能,在团队:有没有人能长期维护 PFC/ECN 配置。 没有的话,IB 那笔额外的硬件钱买的其实是确定性。

检查点

检查点单选

RoCE 集群里 PFC 帧计数每秒增长几千,业务带宽还行但延迟抖动很大。该怎么判断?

检查点单选

RoCE 环境下 ib_send_bw 点对点能跑到线速的 95%,但多机 NCCL 一上量带宽就掉到三分之一。最值得先查的是?

检查点多选

关于 PFC 和 ECN 的分工,下面哪些说法正确?(多选)

这节课的落点

  • RoCEv2 = RDMA over UDP 4791,能被普通三层网络路由,抓包只能看到包头
  • RDMA 的可靠传输是 go-back-N,0.1% 丢包就能让带宽雪崩
  • PFC 逐跳踩刹车,反应快但会反压扩散、可能死锁 —— 只能当兜底
  • ECN/DCQCN 端到端降速,是主力;ECN 水位必须低于 PFC 阈值
  • DSCP / PCP / TC 映射必须端到端一致,任何一跳错都会让 RDMA 流量掉进普通队列
  • show_gids | grep v2 先确认 GID index,再跑 ib_send_bw -x <idx> -d <dev>
  • 验收要看五项:链路速率、点对点带宽、点对点延迟、PFC 帧、集群 busbw ≥ 90%

延伸资料