第266篇:数据中心 PFC(优先级流控制)死锁故障

关键词

PFC 死锁、优先级流控制、无损网络故障、反压传播、Credit 耗尽、头阻塞、死锁检测


一、PFC 死锁的本质

1.1 什么是 PFC 死锁

PFC 死锁是多个交换机相互等待对方释放缓冲区,导致流量永久停滞的状态:

PFC 死锁示意图:

                100G 链路
Leaf1 Leaf2 ▼ ▼ 双方都收到 Pause,都不发 Class 3 流量 双方都在等对方恢复发送 → 死锁! ← PFC Pause(Class 3) Class 3 流量 ─────────────────────► ← 我也 Pause 你

死锁特征: 1. 某个或多个优先级持续处于 Pause 状态 2. 该优先级上的流量完全停滞 3. 即使链路空闲,也没有数据发送 4. 所有涉及设备相互等待

1.2 死锁发生的必要条件

PFC 死锁的四个必要条件:

条件 1:环路拓扑 + 无损流量

  ┌─────────► Leaf2 ──────────┐
  │                            │
  │                            ▼
  Leaf1 ◄─────────────────── Leaf3

  如果所有链路上 Class 3 都开启 PFC:
    循环反压可能发生

条件 2:缓冲区全部耗尽

  每个交换机的 PFC 缓冲区(Headroom)被填满
  没有空间接收新的报文

条件 3:相互等待

  Leaf1 在等 Leaf2 发送(才能释放 Leaf1 的缓冲区)
  Leaf2 在等 Leaf3 发送
  Leaf3 在等 Leaf1 发送
  循环等待!

条件 4:没有打破机制

  没有 PFC 死锁检测
  或检测但无恢复动作

二、死锁的根因

2.1 微突发 + 缓存不足

最常见的死锁触发场景:

场景:Leaf1 向 Leaf2 发送大量 RoCE 流量

  正常情况:
    Leaf1 发 ↘ ↗ Leaf2
              X
    Leaf3 发 ↗ ↘ Leaf4

    流量分散,缓冲区足够

  突发情况:
    多个 GPU 同时发送计算结果
    100G 链路上瞬时 400G 流量
    Leaf1 出端口队列急剧增长
    PFC 阈值触发 → Leaf2 收到 Pause

    如果此时 Leaf2 也在向 Leaf1 发送:
      Leaf1 出端口 Pause → Leaf1 入端口停止收
      Leaf2 出端口队列填满 → Leaf2 发 Pause 给 Leaf1
      Leaf1 和 Leaf2 相互 Pause → 死锁!

2.2 Credit 耗尽

基于 Credit 的流控与 PFC 的关系:

PFC 本质上是一种 Credit 机制:

  Sender 有 N 个 Credit(缓冲区配额)
  每发一个报文,消耗一个 Credit
  Credit 为 0 → 发送端必须停止

  正常流程:
    发送端有 Credit → 发报文 → 消耗 Credit
    接收端处理完报文 → 释放 Credit → 通知发送端

  死锁流程:
    发送端 Credit = 0 → 停止发送
    接收端缓冲区满 → 无法释放 Credit
    → 死锁!

PFC Credit 耗尽的原因:

  1. 接收端处理速率 < 接收速率
     AI AllReduce 场景最典型
     64 入 1 出 → 入远超处理能力

  2. 接收端也要发送(双向流量)
     RoCE 的 READ/WRITE 是双向的
     两边都要发送 → 都可能被 Pause

  3. 链路不对称
     一边 100G,另一边 40G
     低速端必然积累 → Pause

2.3 头阻塞(HOL Blocking)

PFC 的头阻塞问题:

PFC 基于优先级,但同一优先级内部不同流之间会互相影响:

Leaf1 的 Class 3 队列:

F1 F2 F3 F4 F5 F6 ← 队列头部
├─ F1:输出到 Spine1(空闲)→ 可以发送
├─ F2:输出到 Spine2(空闲)→ 可以发送
├─ F3:输出到 Spine3(拥塞)→ Pause!
├─ F4:输出到 Spine4(空闲)→ 被 F3 挡住
├─ F5:输出到 Spine1(空闲)→ 被挡住
└─ F6:输出到 Spine2(空闲)→ 被挡住

问题: 同一优先级使用 FIFO 队列 F3 的路径拥塞 → PFC 反压 但 F1/F2/F4/F5/F6 的路径是空闲的!

因为 F3 在队列头部挡住了后续所有流
这些"无辜"的流也被 Pause → 带宽浪费

解决方案: 多队列(Per-egress-port queuing) 或 PFC 不用的优先级不开启 PFC


三、死锁的检测

3.1 检测方法

PFC 死锁检测的几种方法:

方法 1:基于持续 Pause 时间

  检测:某个优先级持续处于 Pause 状态超过阈值
  阈值:通常 100-500ms
  判断:连续 Pause → 可能是死锁

  配置:
    priority-flow-control dead-detect enable
    priority-flow-control dead-detect interval 100  # 100ms
    priority-flow-control dead-detect count 3       # 3 次

方法 2:基于计数器

  display dcb pfc interface 100GE1/0/1

  正常情况下:
    Pause Frame TX:缓慢增长
    Pause Frame RX:缓慢增长

  死锁迹象:
    Pause Frame 在一段时间内持续高频率
    或某个优先级 Pause 状态不恢复

方法 3:基于流量观测

  display interface 100GE1/0/1

  正常情况下:
    端口持续有流量(In/Out 稳定增长)

  死锁迹象:
    某优先级速率跌零
    其他优先级速率正常
    链路物理状态正常(Up)

3.2 华为 PFC 死锁检测配置

华为 CloudEngine 系列 PFC 死锁检测:

# 全局死锁检测配置
dcb
 pfc dead-detect enable                     # 全局开启
 pfc dead-detect interval 100               # 检测周期 100ms
 pfc dead-detect count 3                    # 3 次连续判定
 pfc dead-recover auto                      # 自动恢复
#
# 接口级别配置
interface 100GE1/0/1
 priority-flow-control dead-detect enable
 priority-flow-control dead-detect interval 100
 priority-flow-control dead-detect count 3
#

# 查看死锁状态
display dcb pfc dead-detect

  Interface       Priority  DeadLock Status    Count
  100GE1/0/1      3         Normal             0
  100GE1/0/2      3         Normal             0
  100GE1/0/3      3         DeadLock           3   ← 已死锁 3 次
  100GE1/0/4      3         DeadLock-Re        ← 恢复中

四、死锁的恢复

4.1 自动恢复机制

华为 PFC 死锁自动恢复流程:

检测到死锁:

交换机检测到优先级 3 持续 Pause 300ms 恢复动作: Step 1:停止向该优先级发送 Pause Step 2:强制清除该优先级的 Pause 状态 Step 3:丢弃该优先级的部分缓存报文 (丢弃多少取决于配置策略) Step 4:恢复发送 恢复后: 流量重新开始流动 丢弃的报文由 RDMA 层重传 (RDMA 的 Go-Back-N 机制会重传)

丢弃策略配置: # 死锁恢复时丢弃策略 dcb pfc dead-recover drop-mode tail-drop # 丢弃尾部报文 pfc dead-recover drop-packet-count 100 # 最多丢弃 100 个报文

4.2 人工恢复操作

手动恢复 PFC 死锁的操作步骤:

Step 1:确认死锁

  display dcb pfc dead-detect
  display dcb pfc interface 100GE1/0/3
  → 确认优先级 3 处于 DeadLock 状态

Step 2:尝试策略

  # 方案 A:关闭再开启 PFC
  interface 100GE1/0/3
   undo priority-flow-control enable
   priority-flow-control enable

  # 方案 B:关闭该优先级上的 PFC
  interface 100GE1/0/3
   undo priority-flow-control priority 3

  # 方案 C:重启端口(最严重情况)
  interface 100GE1/0/3
   shutdown
   undo shutdown

Step 3:确认恢复

  display dcb pfc interface 100GE1/0/3
  → 确认 Pause 状态清除
  → 确认流量恢复

五、预防措施

5.1 架构层面的预防

从架构设计上预防 PFC 死锁:

1. 避免 PFC 环路

  不佳设计:
    Leaf ── Spine ── Leaf ── Spine ── Leaf
    ↑                                  │
    └──────────────────────────────────┘
    存在环路的拓扑更容易死锁

  推荐:
    标准 Spine-Leaf 无环拓扑
    不需要 STP 防止环路
    ECMP 所有链路可用但仍无二层环路

2. 减少 PFC 反压深度

  单跳反压优于多跳反压:
    服务器 ↔ Leaf(PFC 反压仅在接入层)
    Leaf ↔ Spine(不使用 PFC,改用 ECN + DCQCN)

3. 合理的超时设计

   交换机缓存足够吸收 50ms 的突发
   避免小型缓存交换机处理 RoCE 流量

5.2 参数调优

PFC 参数调优预防死锁:

1. PFC 阈值设置

  # 华为推荐
  dcb pfc buffer shared 4000               # 共享缓存
  dcb pfc buffer headroom 2000              # 头房缓存
  dcb pfc buffer xoff-threshold 1500        # 反压触发阈值

  注意:不要把所有缓存都给 PFC
        留部分缓存给其他优先级正常转发

2. ECN 与 PFC 配合

  确保 ECN 在 PFC 之前响应:
    ECN 标记触发:队列 200-400
    PFC 反压触发:队列 > 1500

  Kmin > 0
  Kmax < PFC 阈值
  让 ECN 有足够时间响应

3. 非无损优先级隔离

  不要在所有优先级上开启 PFC
  只有 RoCE(优先级 3)开启
  其他优先级(0)关闭 PFC

5.3 监控与告警

PFC 死锁监控体系:

监控指标:

  指标                    阈值        告警级别
  ─────────────────────────────────────────────
  PFC Pause Frame Rate    > 1000/s     警告
  PFC Deadlock Count      > 0          严重
  优先级 3 速率跌零       -            严重
  队列深度 > 80%          -            警告
  ECN 标记率 < 1%         -            注意(可能 ECN 失效)

采集方式:

  # SNMP OID(供网管采集)
  hwPfcPauseFrameRCv
  hwPfcDeadLockCount
  hwPfcQueueLength

  # Telemetry 流式采集
  telemetry
   sensor-group PFC_MONITOR
    sensor-path hwPfcPauseFrame
    sensor-path hwPfcDeadLock
   #

六、真实故障案例

6.1 案例:AI 集群死锁

现象:
  AI 训练集群每 2 小时出现一次"训练挂死"
  所有 GPU 通信超时
  网络端口的 RoCE 流量速率为 0

排查:
  登录 Spine1 → display dcb pfc dead-detect
  → 发现多个端口频繁出现 DeadLock

  Spine1 的 PFC 死锁 → 反压到 Leaf
  Leaf 收不到数据 → GPU 通信超时
  AllReduce 卡住 → 训练挂死

根因:
  ECN 阈值设置过高(Kmin=500)
  PFC 在 ECN 之前被触发
  Incast 场景下 PFC 频繁触发 → 最终死锁

修复:
  调整 ECN 阈值:Kmin=100, Kmax=300
  增加 Headroom 缓存:从 1000 到 2000
  开启 PFC 死锁自动恢复

效果:
  死锁次数:> 10 次/天 → 0 次
  训练效率提升 20%

七、总结

知识点 核心要点
PFC 死锁本质 交换机相互等待缓冲区释放,流量永久停滞
四个必要条件 环路 + 缓存耗尽 + 相互等待 + 无打破机制
根因 微突发、Credit 耗尽、头阻塞
检测 持续 Pause 超时(通常 300ms)
恢复 自动丢弃缓冲区报文并恢复发送
ECN 配合 ECN 在 PFC 之前响应,减少 PFC 触发
架构预防 避免 PFC 环路,控制反压深度
参数调优 合理设置阈值,隔离非无损优先级

八、思考

  1. PFC 死锁的四个必要条件是什么?为什么 Spine-Leaf 标准拓扑比三层拓扑更容易出现 PFC 死锁?
  2. 头阻塞(HOL Blocking)在 PFC 死锁中扮演什么角色?为什么同一优先级的一条流拥塞会阻塞其他正常流?
  3. PFC 死锁检测的原理是什么?如何区分正常的短暂 Pause 和死锁?
  4. 死锁自动恢复过程中丢弃的报文由谁负责重传?为什么这种机制是安全的?
  5. 在一个 AI 训练集群中,如果经常出现 PFC 死锁,应从哪些维度进行调优?(请至少列出 3 个调优方向)

下篇预告:第267篇《存储网络基础:FC-SAN 与 IP-SAN(iSCSI)》——传统存储网络的两种主流方案对比,FC-SAN 的架构与 iSCSI 的协议原理。