尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

PFC原理与排障实战:从暂停帧到Buffer规划,保障无损网络稳定

PFC原理与排障实战:从暂停帧到Buffer规划,保障无损网络稳定 前几天帮我维护的一个存储集群做性能交接客户反馈说某几个节点的 IOPS 波动特别大应用侧偶尔还报超时。登录交换机一看端口上的计数器跳得我心头发紧priority pause frames 那一列的数字在大幅增长。说白了就是 PFCPriority-based Flow Control基于优先级的流量控制在疯狂工作。PFC 这个东西在数据中心网络里是绕不开的角色它让以太网能承载 RoCE、FCoE 这类对丢包极度敏感的流量没有它无损网络基本无从谈起。但你千万别以为“开了 PFC 就万事大吉”配置不对、Buffer 规划不合理、链路有隐患它随时能把问题放大成故障。这篇文章我结合自己的运维和排障经验把 PFC 的工作原理、配置要点、Buffer 规划和踩坑记录一次讲清楚适合正在接触存储网络、RoCE 网络、或者准备做无损数据中心改造的工程师。先说明一个容易混淆的点网络领域的 PFCPriority-based Flow Control和电源领域的 PFCPower Factor Correction功率因数校正是两个完全不同的东西。本文只聊网络方向的 PFC而且内容围绕数据中心以太网环境展开。1. 传统以太网拥塞控制的短板丢包重传遇上性能敏感流量1.1 从“丢了就重传”到“不能丢”存储与 AI 网络的无损需求传统以太网从设计之初就没打算做得太“精致”。它假设上层协议能容忍丢包比如 TCP 有确认和重传机制丢了包大不了 RTO 超时重传对网页浏览、文件传输这类业务没什么致命影响。可到了数据中心内部情况完全不同了。以 RoCERDMA over Converged Ethernet为例它的设计目标是让网卡绕过 CPU、绕过内核协议栈直接用 RDMA 读写远端内存。问题是 RDMA 的传输层没有像 TCP 那样的“丢失重传”机制数据包一旦在网络上被丢弃发送端不一定能感知要么等很长的超时要么直接导致应用异常。同样的道理也适用于 FCoEFibre Channel over Ethernet这类承载存储流量的协议。存储网络对可靠性的要求几乎是“宁死不丢”一个包都不能丢丢了就是业务抖动。所以数据中心网络必须做到一件事——即使出现瞬时拥塞也尽量不让报文被丢弃。怎么做到一个朴素的想法是拥塞的时候让上游设备先停一停。这正是 PFC 要做的事。1.2 链路级 Pause 为什么会被 PFC 淘汰在 PFC 之前IEEE 802.3x 定义了链路级流控Link-level Flow Control机制非常简单接收端的 Buffer 快满时向对端发一个 Pause 帧对端收到后暂停整个端口上的所有流量一段时间接收端 Buffer 缓和了再发一个带零计时器的 Pause 帧解除暂停。听起来思路没问题但这个机制有个致命缺陷它是“一刀切”的。暂停帧作用的是整个物理端口而端口上通常同时承载多种流量包括普通 TCP、管理流量、VoIP、存储流量等。一旦某一种流量突发把 Buffer 占满端口就会把整条链路上的所有流量全部暂停。结果就是存储流量还没解决普通业务先被打断TCP 超时重传、VoIP 抖动、管理通道中断一起爆发。更麻烦的是802.3x Pause 的暂停行为可以被“累加”。多台设备串在一条链路上每一跳都可能在极端情况下向上游发 Pause形成链式依赖。一旦某个中间节点的 Buffer 分配不公平某个方向的数据堆积所有经过这条路径的流量都得跟着遭殃。所以业界需要一种更精细的流控机制——不再以整个端口为单位暂停而是按流量的优先级来区分处理。这就是 PFC 的出发点。1.3 “先分类、再暂停”才是 PFC 的破局思路PFC 的核心思想可以概括为八个字先分类再暂停。数据在以太网帧的 VLAN TAG 里带着 802.1p 优先级字段Priority Code PointPCP一共 3 bit可以表达 0 到 7 共 8 个优先级。交换机和网卡可以把不同 PCP 值的流量映射到不同的内部队列里。每个队列独立运行“接收端检测水位、发送端暂停队列”的逻辑。这样一来收到暂停帧时设备只暂停对应优先级的队列其他队列照常转发。比如你把存储流量放在优先级 3 队列里拥塞时这个队列被暂停而优先级 0 的普通 TCP 流量不受影响。这比全局 Pause 精细得多也是它能被广泛应用在无损网络中的原因。另外还需要注意到PFC 是逐跳生效的链路层机制。交换机出口队列发生拥塞时它会向“上一跳”设备发暂停帧让上游也停下来如果中间隔了多台交换机每一跳都会向上游反馈最终压力一级一级传递到发送端网卡。理解这一点对后面排查问题非常重要。2. PFC 通话原理拆解暂停帧、优先级队列和 Buffer 水位2.1 一个暂停请求的完整旅程我一直觉得要掌握 PFC最有效的办法是跟一个数据帧走一遍它被暂停的完整过程。假设发送端 A 往接收端 B 高速传输存储数据中间经过交换机 S。第一步数据到达 S 的入端口。交换机根据报文携带的 VLAN 优先级把它分配到优先级 3 的队列里等待转发到出端口。第二步出端口的发送队列开始积压。如果某个瞬间从多个入端口涌进来的流量大于出端口带宽队列长度会快速增长。第三步队列长度达到预先设置的高水位阈值Xoff 阈值交换机内部逻辑认为“要扛不住了”于是从出端口向发送端 A 发一个 PFC 暂停帧。第四步发送端 A 收到这个暂停帧后检查它的“优先级位图”确认是在暂停自己的优先级 3 队列于是把该队列的发送动作挂起一段时间。第五步队列长度因为暂停而逐步下降降到**低水位阈值Xon 阈值**以下后接收端再发一个 PFC 暂停帧这次位图中该优先级的暂停计时器为 0表示恢复发送。这个过程中有一个关键点暂停帧不是把链路物理断开而是让对应优先级的队列“等待”队列里的数据仍然留在 Buffer 里只是不再往线上发。2.2 暂停帧的报文结构优先级位图与计时器PFC 的暂停帧是基于 MAC 控制帧格式定义的标准是 IEEE 802.1Qbb2011 年左右随数据中心桥接 DCB 系列标准一起发布。它的目的 MAC 地址是 01-80-C2-00-00-01属于 MAC Control 帧不会被交换机当作普通数据帧转发。关键字段有两个字段作用说明优先级位图标志本暂停帧作用于哪些优先级8 bit 一一对应 8 个优先级1 表示暂停生效暂停计时器数组每个优先级独立的暂停时长单位是 pause_quanta1 个 quanta 512 bit 时间相比 802.3x 的 Pause 帧只有一个公开的暂停计时器PFC 的暂停帧里同时携带 8 个优先级的暂停时长。发送方收到后提取对应优先级的计时器值如果大于 0就把该优先级的发送暂停这么长时间。如果多个暂停帧连续到达计时器会被刷新——以最新收到的值为准。这样可以防止老旧的暂停帧把队列卡住太长时间。有个细节值得注意PFC 也靠“计时器归零”来隐式恢复不需要显式的解除帧。这样设计的好处是避免“恢复帧丢失导致永久暂停”的极端情况。但很多厂商实现里仍然会在水位降至 Xon 阈值时主动发一个计时器为 0 的恢复帧让对端尽快恢复。2.3 优先级怎么进入队列802.1p 标记与队列映射PFC 说“暂停优先级 3 队列”这里的“优先级 3”是怎么来的其实就是在以太网帧的 VLAN Tag 里有 3 bit 的 PCP 字段数值 0 到 7。数据进入交换机后设备会根据映射表决定它进入哪个硬件队列。不同厂商的默认映射并不完全一致但思路相同。下面是一个典型的 8 队列映射示例802.1p 优先级典型用途队列行为0尽力而为流量默认普通队列允许丢包1低优先级批量流量普通队列2普通业务流量普通队列3RoCE/存储无损流量无损队列启用 PFC4FCoE 等存储流量如有无损队列启用 PFC5语音/视频/控制面优先队列6网络控制流量优先队列7网络控制流量优先队列很多场景下 RoCE 会默认映射到优先级 3一方面是因为 QoS 默认习惯另一方面也是厂商之间的兼容性考虑。但这不是绝对的不同厂家、不同虚拟化平台有自己的约定。真正重要的不是“固定用 3”而是全网所有设备、所有虚拟机接口、所有网卡的映射必须完全一致。你发端的网卡把 RoCE 标成 PCP 3中间交换机却把 PCP 3 映射到了普通队列且没开 PFC那 PFC 就形同虚设拥塞时照样丢包。2.4 逐跳反馈的本质PFC 是链路层机制不是端到端控制这里必须澄清一个很容易被误解的概念。很多人以为“开了 PFC拥塞直接从源头开始降速”其实不对。PFC 的暂停帧只在“相邻的两个以太网接口”之间传递它是逐跳per-hop的。举个例子服务器 A - 接入交换机 S1 - 汇聚交换机 S2 - 存储节点 B。如果 S2 的出口拥塞S2 会向 S1 发 PFC 暂停帧让 S1 的对应队列暂停。如果 S1 的队列因此也开始堆积S1 又会向服务器 A 发暂停帧最终让网卡暂停。这个过程是压力逐级回溯的每一级都需要足够的 Buffer 来“吸收”上游继续发来的数据。如果中间某一级 Buffer 太小还没来得及发暂停帧就已经把数据丢了那 PFC 就没完成它的任务。所以说PFC 本质上是在“每个链路上做刹车的动作”而不是像 TCP 那样的端到端拥塞控制。它无法感知真正的业务流也不会去调整发送窗口。一旦链路数量和层级很多逐跳反馈的延迟、Buffer 需求和排队复杂度都会上升。3. 让 PFC 真正落地的配置实践交换机、网卡与 Buffer 规划3.1 部署前先回答三个问题我见过不少团队直接照搬厂商文档“开启 PFC”然后就把问题甩给网络。实际上 PFC 不是开关它是一套需要统筹设计的机制。动手配置之前建议先回答三个问题第一个问题这条链路上真的有无损流量吗如果链路只承载普通 TCP 或可容忍丢包的业务PFC 不但没用反而可能引入暂停风暴影响整条链路。只有 RoCE、FCoE 这类“不能丢包”的流量才需要 PFC。第二个问题无损流量走哪些 VLAN、哪些 802.1p 优先级这决定了交换机要启用哪个队列的 PFC以及网卡要打什么标记。第三个问题Buffer 够不够PFC 的前提是“拥塞时不丢包”不丢包就需要把数据暂时存放在 Buffer 里。如果不给无损队列预留足够的 BufferPFC 就是一个空转的假把式——暂停帧发了但队列还是爆了包还是丢了。这些问题想清楚之后再进入具体配置。3.2 交换机端配置示例不同厂商的命令有差异但核心概念差不多。以常见的数据中心交换机为例配置通常包含三部分全局开启 PFC、指定某个优先级为 no-drop、设置该队列的暂停阈值和恢复阈值。一段典型的配置形态如下具体可参考你的设备手册这里给出通用形态interface Ethernet1/1 priority-flow-control mode on priority-flow-control priority 3 no-drop priority-flow-control priority 3 pause-threshold 30000 priority-flow-control priority 3 resume-threshold 100含义解释一下mode on表示使能 PFCpriority 3 no-drop表示把优先级 3 的队列设置为“不丢弃”队列pause-threshold是触发暂停的高水位一般用 buffer cell 为单位队列占用超过这个值就发暂停帧resume-threshold是恢复发送的低水位队列下降到这个值以下允许对端恢复发送。如果你用的是华为、H3C 等设备命令风格会不一样但要素是相同的interface 10GE1/0/1 priority-flow-control enable priority-flow-control priority 3 no-drop华为设备的思路是先把接口使能 PFC再声明哪个优先级是 no-drop。有些平台需要把 no-drop 队列同时配置为调度优先级和带宽保证否则虽然不丢包但可能出现“停着不走”的调度问题。3.3 主机网卡与驱动侧的对应配置光配交换机远远不够。RoCE 流量是从网卡里发出来的如果网卡不配合PFC 永远无法真正生效。服务器端的配置主要有三个层面第一网卡驱动要开启 DCBData Center Bridging相关功能。多数 RoCE 网卡比如 Mellanox/ConnectX 系列默认支持 PFC但需要把对应的流量类型绑定到指定的 802.1p 优先级。第二操作系统的 QoS 映射要正确。Linux 下可以用tc或网卡厂商工具配置 priority mapWindows 下则通常在网卡高级属性里设置。第三如果主机走的是虚拟化平台比如 ESXi 或 KVM还需要在虚拟交换机的端口组上设置 VLAN 优先级标记否则虚拟机发出的帧可能不携带 PCP 字段。我曾经遇到过一个案例交换机上已经开好了 PFC但虚拟化平台发出来的 RoCE 报文 PCP 全为 0全部落进了普通队列。结果存储流量一拥塞就丢包客户还以为是网络设备的问题。后来通过在分布式交换机上配置 QoS 标记把对应 VLAN 的流量重新标为 PCP 3问题才彻底解决。这个坑非常典型排查时需要第一时间确认“报文的实际 PCP 值到底是什么”不能只看配置界面。3.4 Buffer 规划无损队列的容量怎么算Buffer 规划是 PFC 配置里最容易被忽略、也最影响成败的一步。PFC 能保证不丢包的前提是从“队列开始拥塞”到“对端完全停发”的这段时间里所有继续到达的数据都有地方放。这个量在工程上通常用 BDP带宽时延积来估算无损队列 Buffer ≈ 链路带宽 × 端到端时延 ÷ 8举个例子100Gbps 链路端到端时延如果是 1 微秒那么需要的 Buffer 大约是 100 × 10^9 × 10^-6 ÷ 8 12.5 KB。这看起来很小但实际上这里的“端到端时延”不是物理链路时延而是要考虑暂停帧传递时间、对端处理时间、报文序列化时间等多方面因素。如果跨机柜、跨机房RTT 变成毫秒级需要的 Buffer 就是百 MB 甚至 GB 级这在交换机硬件上根本不现实。所以你在真实网络里看到的无损队列通常只开在同一机房、低时延路径上。跨广域网、跨数据中心的场景单纯靠 PFC 是无法做到严格无损的。这也是为什么无损网络方案通常要配合 ECMP 的负载均衡策略、控制路径长度并想尽办法降低 RTT。在具体设备上配置 Buffer 时有几个实操经验可以分享无损队列的 Xoff 阈值不宜设置得过小。建议先配一个合理默认值然后通过观察交换机上的 buffer watermark 统计来持续调整而不是一步到位压极限。不要让 no-drop 队列吃掉所有共享 Buffer。有些交换机共用一个 Buffer 池某个队列占满后其他普通队列会没有空间可用导致 TCP 等其他流量被“殃及池鱼”。合理做法是给每个队列设置 buffer limit 或共享池权重防止单个队列独占。如果设备支持 PFC Watchdog一定要在实验环境充分验证后再决定是否全局启用。Watchdog 能检测长时间暂停并自动恢复但触发策略不合理时可能主动丢包反而破坏无损语义。3.5 配置里最容易踩的几个坑前面提到了几个配置常见的坑这里集中列一下方便对照检查。第一个坑全局开 PFC而不是按需在路径上开。正确的做法是只在承载无损流量的物理链路上开启 PFC未承载无损流量的端口保持关闭状态。否则 qos 队列的暂停逻辑会把普通流量也卷进去。第二个坑PCP 映射不一致。交换机上改优先级网卡没改或者虚拟机端口组设置的 PCP 和物理交换机不一致。这种问题很难一眼看出来建议配置前后抓包确认或者对比接口的 PFC 计数。第三个坑只配置了 no-drop没有配置对应的调度带宽。无损队列带宽得不到保证PFC 暂停会让存储流量吞吐变得忽高忽低应用侧表现为“间歇性卡顿”。4. PFC 引发的事故复盘死锁、拥塞扩散与监控预警4.1 事故一PFC 暂停帧暴增存储 IOPS 大幅下降回到文章开头说的那起故障。现象是存储节点的 IOPS 突然从 30 万掉到 8 万应用侧偶发超时。我登到接入交换机上一看连接存储服务器的端口上priority pause frames received 和 sent 都在快速上涨伴随队列 buffer watermark 居高不下。第一反应是检查是不是有广播风暴或者链路 CRC 错误。查了一圈物理层干净没有错包端口速率也正常。再顺着流量的来源查发现同一台接入交换机上有几个虚拟机节点正在做大数据分析产生了大量突发流量。这些流量和存储流量走了同一条上行链路而且它们的 802.1p 优先级都被设成了 3和 RoCE 挤在了同一个队列里。结果就是普通计算流量突发把无损队列的水位顶到了 Xoff 阈值PFC 开始暂停存储节点的发送。存储流量本身并没有拥塞纯粹是被“同队列的其他流量”连坐了。这个事故的教训很直接PFC 是按优先级隔离的不是按应用隔离的。如果你把多个互不相关的业务放进同一个 no-drop 队列任何一个业务的突发都会堵住所有同队列的业务。后来我们做的改动是把所有非存储流量全部改标为 PCP 0/1存储流量单独用 PCP 3同时在出向调度上给 no-drop 队列设置独立的带宽保障避免被尽力而为流量挤压。调整后同样的业务模型下PFC 暂停计数回归正常水平IOPS 也稳定了。4.2 事故二成环拓扑下的 PFC 死锁另一次事故比第一次严重是半夜被值班电话叫起来处理的。现象是存储网络整体性能归零交换机上大量端口出现长时间暂停PFC 暂停计数疯狂跳动业务完全不可用。当时网络拓扑是叶脊结构叶交换机之间通过 MLAG 做了双活互联。某个存储设备出现异常持续向网络里发送大量数据数据在叶脊之间的多个路径上形成了循环传播的趋势。由于 PFC 是逐跳的A 交换机因为出站拥塞向 B 交换机发暂停而 B 交换机也因为另一个方向的拥塞向 A 发暂停。这样一来两个方向互相暂停形成一个循环等待的状态谁也没法继续发送。这就是所谓的 PFC 死锁。PFC 死锁的排查难点在于问题不在“某一条链路”而在“链路之间的依赖关系”。从交换机的视角看每个端口都在正常收暂停帧、发暂停帧仿佛一切正常但整个网络的数据流却是静止的。排查了很长时间最后是通过关闭相关端口的 PFC 功能人为打破暂停循环网络才恢复。这个事故给我的启发是PFC 并不自带“死锁恢复”机制。如果真的需要高强度可靠性要么在硬件层面启用 PFC Watchdog 并配置合理的自动恢复策略要么在架构层面避免多路径环路与 PFC 的无损语义叠加。比如在 MLAG 或 ECMP 场景下要仔细评估多路径是否会在特定故障态下形成反向暂停依赖。4.3 应该盯紧的 PFC 监控指标经历过这两次事故之后我把 PFC 相关的监控项整理成了一个清单运维团队日常盯这五项足够指标含义预警建议Priority pause frames sent / received每个优先级下发的暂停帧数量持续增长说明对端 Buffer 不足或拥塞未缓解No-drop queue buffer watermark无损队列 Buffer 占用最高水位频繁接近 Xoff 阈值说明容量规划偏紧No-drop queue dropped packets无损队列丢包计数正常应为 0一旦出现即为重大异常Link CRC / error counters物理层错误计数有错包先查光模块、线缆和端口协商ECN marked packets如果启用拥塞标记报文数量配合 PFC 判断拥塞扩散范围在告警阈值方面不建议只看“是否不为 0”因为正常业务波动也会产生暂停帧。更合理的做法是建立基线先观察一周的正常运行数据记录 PFC 暂停帧的“正常波动范围”再设置告警线。比如基线是每秒不超过 1000 个暂停帧超过 5 倍就告警。4.4 什么时候应该关掉 PFCPFC 不是所有场景都适用。如果你排查到以下情况可以考虑在该链路上关闭 PFC改用其他手段解决链路上已经没有 RoCE/FCoE 等无损协议只剩下 TCP/UDP 流量。应用能够通过自身重传机制容忍偶发丢包不需要严格无损。拥塞现象频繁触发但根源是物理链路负载超限这时候 PFC 只能掩盖问题不能解决问题。网络中存在环路或未收敛的状态PFC 会助长暂停风暴。相反只要链路还在承载 RoCE 等无损业务就不要轻易关闭 PFC。正确的思路是围绕 PFC 做“配套治理”尽可能减少同队列业务混跑、优化 Buffer 阈值、监控暂停计数、推动应用侧对拥塞做出反馈。这正好引到本文最后一个话题。5. PFC 之外从无损链路到端到端无损数据中心5.1 ECN 与 PFC 如何分工PFC 本质是链路层的“刹车”但它有一个天然盲区它不知道拥塞的根源在哪里也不知道该让哪个发送端减速。如果不同时做端到端的拥塞控制PFC 就只是把丢包变成排队把所有拥塞压力堆积在交换机 Buffer 里。就好比高速公路上出了事故你只在每个入口处拦住车辆但不知道哪辆车该绕行最终只会让整条路越来越堵。ECNExplicit Congestion Notification显式拥塞通知补上了这个短板。交换机检测到队列拥塞时不再直接丢包而是在 IP 报文头上打一个 ECN 标记CE接收端收到标记后通过拥塞通知报文反馈给发送端发送端据此主动降速。ECN 解决的是“源端感知拥塞并调节发送速率”PFC 解决的是“在调节生效之前不让缓冲队列彻底爆掉”。两者是配合关系ECN 负责端到端的速率调整PFC 为这个调整过程兜底。打个比方ECN 是前车的刹车灯告诉后车“该减速了”PFC 是安全带防止刹车不及时的时候人飞出去。你不能只靠安全带不踩刹车也不能只踩刹车不系安全带。5.2 DCQCN把拥塞信息送回源端在 RoCEv2 无损网络里最有代表性的端到端拥塞控制算法是 DCQCN。它的工作流程大致是这样交换机在队列超过阈值但对还未超过丢包阈值时对报文做 ECN 标记接收端 NIC 发现带 ECN 标记的报文后生成 CNPCongestion Notification Packet报文反馈给发送端发送端收到 CNP 后按概率降低发送速率并进入慢启动恢复阶段。这套机制的巧妙之处在于它把拥塞检测放在交换机把速率调节放在服务器网卡两者各司其职。有了 DCQCN 这类机制PFC 在正常情况下的触发频率可以被压得很低。很多人理想中的无损网络状态是ECN 负责 99% 的拥塞控制PFC 只作为极端突发情况下的最后一道防线。如果你发现某条链路的 PFC 暂停帧计数非常高通常说明 ECN 阈值配置不合理或者端到端算法没有正常工作而不是单纯怪 PFC 本身。5.3 我的一点个人体会做了这么多年网络运维我对 PFC 的态度经历了三个阶段最开始觉得它就是个高级流控开关打开就行后来踩了坑觉得它是个惹祸精动不动就把业务搞挂再后来理解了它的底层逻辑和配套机制才意识到——PFC 是一把工具好不好用取决于你会不会用。现在我做无损网络方案时一定会先问清楚几个问题流量从哪里来要到哪里去哪些业务绝对不能丢包哪些业务可以容忍丢包网络 RTT 大概是多少设备 Buffer 容量到底够不够。这些问题想清楚之后PFC 的配置反而是顺水推舟的事。如果你现在正准备在网络上开启 PFC我的建议是先小范围试点把监控打牢对着基线数据调参再逐步扩大范围。不要指望一次配置一劳永逸因为业务模型一变Buffer 水位、暂停频率、ECN 阈值这些参数都得重新评估。PFC 本身不复杂复杂的是它所在的那张网络。希望这篇文章能让你少走一些弯路。
返回列表