ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

深入理解DiffServ PHB:从DSCP映射到队列调度与排障实践

深入理解DiffServ PHB:从DSCP映射到队列调度与排障实践 DiffServ 里的 PHB全称 Per-Hop Behavior也就是每跳行为是我觉得整个 QoS 体系里最值得掰开揉碎讲的一个概念。很多人背下了 DSCP 取值表也知道 DiffServ 是“分类服务”而不是“端到端预留”但一到配置设备或者排障时还是会卡在同一个问题上报文到了每一跳路由器上到底是谁决定它进哪个队列、被丢弃还是优先转发答案就是 PHB。这篇文章不打算罗列术语而是用实际网络工程师的思路把 PHB 背后的设计动机、三类常见 PHBEF、AF、CS、最小可用配置和验证手段一次讲清楚。不管你是准备网络方向面试、复习 408 计算机网络还是在生产环境被 QoS 问题折磨过这篇文章应该能帮你把最后一块拼图补上。1. 聊 PHB 之前先把 DiffServ 的“服务边界”理清楚1.1 DiffServ 不是端到端“专车”而是“分段接力”要理解 PHB你不能只看 PHB 本身得先明白 DiffServ 到底想解决什么问题。早期的 IntServ/RSVP 模型走的是“全程专车”路线对每个业务流源端到目的端路径上的所有路由器都要协商并预留资源每个节点都要记住这个流的状态。这个模型理论上很完美但在互联网核心链路上根本跑不动——核心路由器上可能同时经过几十万甚至上百万条流如果每个路由器都要为每条流维护状态内存和 CPU 都会爆炸而且跨运营商协调预留资源的成本也高得离谱。DiffServ 换了个思路把复杂操作挪到网络边缘让核心设备尽量简单。具体做法是先划定一个“DiffServ 域”也就是一组采用相同 QoS 策略的网络设备集合。在域的入口边界设备上对进入的流量做分类、打标、限速也就是根据服务的优先级或业务种类给报文写入一个 DSCP 值当报文穿过域内的核心路由器时这些节点不再关心你是谁、你从哪来、你要去哪只看报文头里的 DSCP 值然后执行对应的转发行为。这个“转发行为”就是 PHB。可以打个比方IntServ 像你雇了一辆专车全程只送你一个人DiffServ 更像快递干线物流——每个中转站不看你的合同只看包裹上的标签按标签决定放哪个传送带、优先不优先。这样做的好处是核心节点几乎不需要维护状态扩展性极强。代价是“服务保证”变成了分段接力而非全程保证DiffServ 能保证的是“在这一跳、这个节点上你会被这样处理”至于整条路径上会不会被别的节点降级那要看边界之间的策略配合。所以学习 PHB 时脑子里要始终带着“边界”和“逐跳”这两个关键词。1.2 PHB 是把“服务质量”翻译成“转发动作”的那张表RFC 2475 对 PHB 的定义是一个 DS 节点对具有相同 DSCP 值的报文所采用的一种“外部可观察的转发行为”。这句话很绕说人话就是PHB 不是一条命令、不是一个队列的名字而是一组动作的集合包括如何排队、如何丢弃、如何修改标签甚至在某些场景下如何整形。“每跳”这两个字是真正的核心。报文从源到目的地要经过很多台路由器每一台路由器在自己的这一跳独立执行 PHB不需要知道报文在整个路径上曾经被怎么处理过也不需要知道后面还有多少跳。这跟 IntServ 那种“端到端预留状态”是完全不同的哲学。DiffServ 把全局的 QoS 目标拆解成了每个节点的本地动作这大大提升了可扩展性但也带来了一个隐含要求边界节点必须可靠地打标中间节点必须可靠地信任并执行 DSCP否则整个服务模型就塌了。还有一点容易误解PHB 和 DSCP 不是一回事。DSCP 是报文头里的一个 6 bit 字段本身只是一串二进制数字比如 101110PHB 是设备根据这个数字映射出来的行为集合。同一个 DSCP 在标准文档里通常对应一种建议的 PHB但设备厂商在实现时不一定完全一致所以不同厂商设备之间做 QoS 互通时关键不是两边都认识“DSCP 46”而是两边的 PHB 行为是否兼容。这也是“外部可观察行为”这个定义存在的意义——标准只约束行为不约束内部实现。2. 三种主流 PHB 逐层拆解EF、AF、CS2.1 EF PHB——给最敏感的业务开“快车道”EFExpedited Forwarding加速转发是 DiffServ 里优先级最高的标准 PHB定义在 RFC 3246推荐的 DSCP 是 101110十进制 46。它的设计目标是低丢包、低延迟、低抖动典型服务对象是 VoIP 语音、实时视频会议这类绝对不能被排队耽误的流量。EF 的实现方式通常是这样的把匹配 EF 的报文放进严格优先级队列PQ让它们在调度时永远优先于其他队列同时必须加一个令牌桶限速器给 EF 流量设定一个承诺速率CIR和突发大小CBS。为什么必须限速因为严格优先级队列有一个著名副作用——饿死。如果所有流量都标记成 EF 且不限速一旦高优先级流量持续涌来其他队列可能永远得不到调度机会而 EF 队列本身也会因为超长排队产生抖动和丢包反而毁了语音业务。所以 EF 的本质是“保证一条低时延通道”但这通道是有宽度限制的。实际规划 EF 带宽时有个简单的估算方法先算出业务需要的峰值带宽。比如语音场景一条 G.711 语音流大约 64kbps 码流加上 RTP/IP 头约 80-128kbps如果同时最多 20 路电话EF 带宽就需要 128kbps * 20 2.56Mbps然后再留出一点余量取 3Mbps 左右。配置 policing 的时候CIR 就设这个数CBS 可以按“单路语音包最大突发”估常见给 3000 到 5000 bytes。我试过把 EF 的 CBS 设太小结果语音刚接通的那几百毫秒经常丢包后来把 CBS 从 1500 加到 6000问题就消失了。2.2 AF PHB——用“四个类三档丢弃级别”消化拥塞AFAssured Forwarding确保转发定义在 RFC 2597它解决的问题和 EF 不太一样。EF 追求实时性AF 追求“在拥塞时按重要程度丢包”。AF 把流量分成四个类AF1 到 AF4每个类内部再分三个丢弃优先级所以一共 12 个 DSCP 编码从 AF11、AF12、AF13 一直到 AF41、AF42、AF43。注意命名规则第一位数字是类别第二位数字是丢弃优先级数字越大被丢弃的优先级越高。这 12 个编码的语义是关键。对于同一个类里的三个编码比如 AF31、AF32、AF33它们在调度上享受相同的带宽保证但在拥塞时的“待遇”不一样设备会在队列变深时优先丢弃 AF33 的报文其次是 AF32最后才是 AF31。实现上通常配合 WRED加权随机早期检测给不同丢弃优先级设置不同的丢包阈值。你可以把每个 AF 类想象成一个蓄水池池子快满的时候管理员先倒掉第三个桶里的水再倒第二个桶最后才动第一个桶。这里最容易踩的坑是把 AF1、AF2、AF3、AF4 理解成绝对优先级觉得 AF4 一定比 AF1 优先转发。其实不是。RFC 2597 定义的 AF 类之间是“带宽份额”关系不是“排队先后”关系。比如你配置 AF1 类保证 20% 带宽、AF4 类保证 40% 带宽在拥塞时两者按权重竞争剩余带宽AF4 一般会获得更好性能但没有“AF4 赢过所有 AF1 报文”这种硬保证。想让某个类绝对优先应该用 EF 或者部分厂商的 LLQ 优先级队列而不是单纯靠 AF 类编号。2.3 CS PHB——传统 IP 优先级的“兼容保留区”CSClass Selector是 DiffServ 里最容易被忽略的一组 PHB但它在现网里的存在感极强。传统 IP 报文头里的 ToS 字段有 3 bit 的 IP Precedence可以表示 0 到 7 共八级优先级。DiffServ 要把 DSCP 字段跟旧体系兼容最简单的方式就是保留前三位后三位补 0这就是 CS0 到 CS7。对应的 DSCP 值是 0、8、16、24、32、40、48、56。CS 的意义在于互通。很多老一点的设备、网络管理系统、核心路由器的路由协议报文仍然沿用 IP Precedence 语义。比如 BGP、OSPF 这类控制面报文在运营商网络里经常被标记成 CS6DSCP 48目的是让它们在任何拥塞下都能优先通过。网管类流量可能用 CS2 或 CS4。CS 本身不描述具体的调度和丢弃行为它更像一个“类别选择器”设备可以把 CS 值映射到不同的队列再配合自己的队列策略。说一个我在现网踩过的坑曾经为了“保护路由协议”把 BGP、OSPF 报文在边界设备上全部打成了 CS6并且放入最高优先级队列。结果某次链路拥塞时大量数据面流量因为配置错误也被打成了 CS6导致控制面报文和这些数据流量抢同一个队列BGP 的 keepalive 反而因为排队延迟而超时引发路由抖动。后来我改的策略是控制面协议优先依赖设备自身的保护机制而不是滥用 PHB 高优先级队列。CS 类可以用但要严格限制在控制面报文和明确的管理流量上别一刀切。PHBDSCP 十进制DSCP 二进制典型用途EF46101110VoIP、实时视频、在线游戏AF1110001010普通业务低丢弃概率AF1212001100普通业务中丢弃概率AF1314001110普通业务高丢弃概率AF4134100010关键生产业务低丢弃概率CS648110000路由协议、控制面报文CS756111000网络管理/最高优先级慎用3. 从规范到现网PHB 的配置落地与验证3.1 在路由器/交换机上配置一次经典 PHB理论讲完了来看实际怎么配。以 Cisco IOS 风格为例核心步骤是三段式定义 class-map 匹配 DSCP定义 policy-map 指定 PHB 动作最后把 policy-map 应用在接口的入方向或出方向。我先说一个设计原则PHB 配置一般放在 DSCP 标记已经完成之后的设备上。在边缘入口你可能有一个 policy 专门负责“分类打标”在核心设备上通常只需要“信任 DSCP 按 PHB 转发”。如果你把标记和 PHB 动作混在一个接口的同一个 policy 里也不是不行但排障时很难分清是哪部分出了问题。给你看一段最小配置思路! 定义 EF 类匹配 DSCP 46 class-map match-any EF-CLASS match dscp ef ! ! 定义 AF31/AF32/AF33 类 class-map match-any AF3-CLASS match dscp af31 af32 af33 ! ! 入口策略给 EF 做限速给 AF3 分配带宽 policy-map EDGE-IN class EF-CLASS priority 1024 police 1024000 conform-action transmit exceed-action drop class AF3-CLASS bandwidth remaining percent 30 random-detect dscp af31 percent 70 90 random-detect dscp af33 percent 50 70 class class-default fair-queue ! interface GigabitEthernet0/0/0 service-policy input EDGE-IN注意几个细节EF 类用了priority 1024含义是分配一个 1024kbps 的严格优先级队列后面又加了police做硬限速超出的 EF 流量直接丢弃。为什么要又配 priority 又配 police因为priority保证调度优先police防止高优先级流量泛滥。AF3 类用bandwidth remaining percent 30表示在剩余带宽中占 30%然后按 DSCP 不同配置 WRED 阈值。AF31 的 WRED 开始丢弃阈值是 70%AF33 是 50%所以 AF33 更容易被丢。配置里最常被忽略的问题是接口入方向的 trust 设置。很多交换机默认不信任 DSCP会在入方向重写标记你把 policy-map 挂上去也不会生效。所以遇到“配置了没效果”第一件事就是检查show policy-map interface并确认入方向是否允许 DSCP 字段原样进入。3.2 用 Linux tc 把 PHB 搬到实验环境对于学生党或者手边没有厂商设备的朋友Linux 的 tc 完全可以用来复现 PHB 的核心逻辑而且是免费的。思路其实很简单用 HTB qdisc 建立多个带带宽约束的类用 tc filter 按 DSCP 字段把报文送进不同的类最后通过tc -s class show dev eth0观察每个类的统计信息。我给一个最小可跑的配置# 创建 HTB 根队列默认类 1:30 tc qdisc add dev eth0 root handle 1: htb default 30 # 类 1:10模拟 EF带宽 1Mbpsil 1Mbps tc class add dev eth0 parent 1: classid 1:10 htb rate 1mbit ceil 1mbit # 类 1:20模拟 AF保证带宽 3Mbps最大可用 10Mbps tc class add dev eth0 parent 1: classid 1:20 htb rate 3mbit ceil 10mbit # 类 1:30默认尽力转发的类5Mbps tc class add dev eth0 parent 1: classid 1:30 htb rate 5mbit ceil 10mbit # 把 DSCP 46 的报文打进 1:10 tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dscp 46 flowid 1:10 # 把 DSCP 26AF31的报文打进 1:20 tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dscp 26 flowid 1:20这里有个细节怎么给测试流量打 DSCP如果你只想发 ICMPLinux 的 ping 支持-Q 0xb8因为 0xb8 就是 10111000高六位是 DSCP 46。想测试 AF31就用ping -Q 0x680x68 01101000高六位是 011010即 26。如果你要测试的是 UDP 业务流可以用 iptables 在 mangle 表里打标# 把本机发出的 UDP 5000 端口流量标记为 DSCP 46 iptables -t mangle -A OUTPUT -p udp --dport 5000 -j DSCP --set-dscp 46然后配合 iperf3 灌背景流量让链路产生拥塞再用tc -s class show dev eth0看每个类的发送量、丢弃量。我实测下来在没有背景流量时EF 类是抢不到多少性能优势的一旦用 iperf3 把链路的 100Mbps 塞满EF 类的包延迟会明显低于默认类AF 类在 WRED 配置下会有选择性的丢包。这个现象能在实验环境里还原出来对理解 PHB 特别有帮助。3.3 判断 PHB 是否真的在“每跳”生效配置完 PHB 之后怎么验证最朴素也最有效的办法是看两个指标队列统计信息和端到端延迟/丢包对比。队列统计信息在厂商设备上就是show policy-map interface会显示每个类的匹配包数、转发包数、丢弃包数、队列深度。如果在拥塞期间你看到 EF 类的丢弃计数一直为 0而 AF33 类有大量丢弃说明 WRED 和调度起了作用。在 Linux 上就是tc -s class show dev eth0里面会显示 bytes、pkt、drops 等字段。延迟对比的做法是向同一个目的地址发送两组 ICMP 或 UDP 流量一组带 DSCP 46一组 DSCP 默认 0。在正常状态下达 10 万次比较平均往返时间再开一路背景流量把链路打满比较拥塞状态下的延迟、抖动和丢包率。正常情况下EF 类在拥塞时的延迟和抖动应该明显优于默认类但如果发现两组数据差别不大大概率是中间某台设备把 DSCP 重写了或者根本没有配置 PHB 映射。抓包验证也是一定要做的。tcpdump 可以直接看 DSCP 字节比如# 抓 eth0 上 DSCP 字段相关的包并显示详细信息 tcpdump -i eth0 -v用-v打开详细输出后每一条 IP 报文会显示tos 0xb8之类的内容你就能确认报文从源到目的地的每一跳DSCP 是否被原样保留。这里有一个跨设备排查的要点要在每一跳设备的入口和出口分别抓包而不是只抓源端和目的端。因为“每一跳行为”意味着中间任何一跳都有权重写标记只有逐跳检查才能定位问题。4. PHB 学习与排障中的高频误区4.1 误区一DSCP 等于 PHB这个误区太常见了。抓包看到 DSCP 46就以为报文已经享受了 EF 的服务质量但 DSCP 只是报文头上的一个编号离“被优先转发”还差着十万八千里。真正起作用的是设备内部把 DSCP 映射到具体 PHB 的执行结果。如果某台设备没配 trust、或者没配映射表DSCP 46 的报文也可能被当作普通流量处理。我见过一个典型案例用户自己用软件给视频流量打了 DSCP 46终端到核心交换机这一段网络也确实看到了 DSCP 46但视频一到跨省链路就卡顿。排查后发现出口路由器的入方向没有使用基于 DSCP 的 class-map而是用了默认的映射表DSCP 46 被当成 IP Precedence 4 处理而设备上 IP Precedence 4 的队列优先级并不高。这就是 DSCP 和 PHB 脱节造成的。所以每次配置 QoS都要沿着报文路径检查每一跳的 PHB 映射表是否正确。4.2 误区二EF 越高越好所以把关键业务全放 EFEF 的队列是严格优先的但它的带宽是被限速的。很多朋友觉得“既然 EF 是最高优先级那我干脆把数据库同步、文件备份、视频点播全放 EF 好了”。实际效果往往适得其反大量流量涌进 EF 队列后超出限速的报文直接被丢弃而这些报文如果走 AF 或 best effort 队列至少大部分还能送达。我做 QoS 调优时有个习惯EF 流量比例控制在链路总带宽的三分之一以内。这不是标准规定但多数设备的 LLQ 最佳实践都会建议不要给严格优先级队列分配过大的带宽份额否则对低优先级流量的饿死效应会非常明显。EF 要留给那些真正对延迟和抖动敏感的业务比如语音、实时控制信令。文件传输、视频点播这类重流量业务丢几个包重传就是了完全不适合 EF。4.3 误区三AF 四个类之间是严格优先级关系很多教材为了好记会画一个阶梯图AF4 在最上面AF1 在最下面看起来像四个不同优先级的排队队列。但 RFC 2597 的模型不是这样的。AF1 到 AF4 强调的“类”是带宽分配单位而不是“绝对优先级排名”。在配置上你给 AF1 类 20% 带宽、AF4 类 30% 带宽拥塞时两者各按比例分享资源而不是 AF4 永远先走完再轮到 AF1。这是很多人直到动手配置或排障才会意识到的差异。如果你真的需要严格优先级关系比如“视频会议绝对不能因为后台下载而拥塞”那应该用严格的 PQ/EF 机制或者用厂商的 LLQ 把特定类放到严格优先级队列再配合策略去限制其他类。AF 适合的场景是“不同重要程度的流量共享链路拥塞时按一定概率丢包”并不适合当作硬优先级使用。4.4 排障实录一次“配置了 PHB 但语音依然卡顿”的追踪说一段真实排障过程。客户网络是企业广域网边界路由器做了 DiffServ 配置语音流量打 DSCP 46视频会议打 AF31目标是拥塞时语音优先。配置下发后用户反馈语音还是卡顿视频也断断续续。排查第一步看边缘入口的标记是否生效。抓包发现部分 IP 电话网关没有自动打标语音流量进入边界路由器时 DSCP 是 0边界路由器虽然配置了类匹配 DSCP 46但匹配不到任何报文语音全部走了默认类。重新在交换机接入端口按 VLAN/端口号打标后解决。第二步看核心设备的 trust 设置。核心路由器入方向默认信任的是 IP Precedence而不是 DSCP导致边界打好的 101110 被核心路由器拆成 IP Precedence 5 来映射映射表又不一致。修改后将接口改为trust dscp让 DSCP 穿透。第三步看隧道问题。站点到站点之间有 IPSec VPNIPSec 加密会新建外层 IP 头如果没有启用 QoS pre-classify外层 IP 头的 DSCP 是复制自内层还是置零各厂商行为不同。在华为设备上启用qos pre-classify后外层头保留了 DSCP语音报文在物理接口上才重新进入了 EF 队列。第四步检查 EF 限速参数。之前 CIR 给的是 512kbpsCBS 只有 1500 bytes但客户实测瞬时突发能到 800kbps导致超过速率的部分直接丢弃。把 CIR 调整到 1Mbps、CBS 调整到 6000 后语音质量恢复正常。整个过程就是典型的“PHB 配置链路断裂”问题不是某个单一节点错了而是标记、信任、隧道、限速四个环节中有三个脱节。所以排障时一定要把整条路径上的 PHB 执行情况拉通看不能只看单台设备。常见现象可能原因排查动作配置了 PHB 完全没效果入方向未 trust DSCP或 DSCP 被重写逐跳抓包比较 DSCP 值语音仍抖动EF 限速过严或 CBS 太小核对 CIR/CBS观察 police 丢弃计数关键业务拥塞时丢包严重业务误入 EF 或 AF 类权重设置不合理查看各类带宽占比与 queue depth隧道场景 PHB 失效IPSec/GRE 外层头未复制 DSCP启用 qos pre-classify 或总结外层头5. 从 PHB 到下一代网络SRv6、数据中心里的“每跳”新变化5.1 SRv6 场景下 PHB 依然被需要可能有朋友觉得SDN、SRv6 这些新架构都出来了传统 DiffServ 里的 PHB 是不是过时了其实没有。SRv6 解决的是“路由怎么选”的问题它通过 SID 里的 Flex-Algo、Segment List 去指定显式路径但报文到达每个 SRv6 节点后设备在本地转发的瞬间依然要决定这个报文进哪个队列、拥塞时丢不丢包。这部分决策还是依赖报文头里的优先级字段。SRv6 中用于承载 QoS 信息的主要是外层 IPv6 头的 Traffic Class 字段或者内层传输层的优先级标记。你可以把 SID 理解成路径导航把 TC 字段理解成那封快递上的“加急标签”两者完全不冲突。所以不管你用 Segment Routing、SRv6还是传统 MPLS最终落到每一跳的调度和丢弃策略仍然是 PHB 那一套。真要淘汰 PHB除非网络设备全都实现了端到端带宽预留否则“按优先级逐跳处理”这个基本动作永远存在。5.2 数据中心与广域网的融合PHB 换了个马甲但没消失数据中心网络这几年在无损网络、RoCE 低延迟场景下大量用了 PFC优先级流控、ECN显式拥塞通知、NIC 多队列等技术。表面上看这跟 DiffServ 的术语体系完全不同但本质依然是把报文分成不同流量类别在不同节点上执行不同转发行为。RoCE 流量被识别后交换机上的 PFC 优先级队列会按优先级暂停对端发流ECN 会在队列深度到达阈值时给源端打标记让源端主动降速。这些机制都可以理解成一种特殊的“每跳行为”。从这个角度说PHB 不会是过时的考试知识点它是理解一切 QoS 机制的基础原子。你现在把 DSCP 映射、队列调度、WRED 丢包这些动作搞清楚将来理解 PFC、ECN、AQM主动队列管理都轻松得多。计算机网络的核心思想是高度复用的换马甲不换内核。5.3 关于学习和排障的一些个人经验最后分享几条我自己的体会。第一条学 PHB 别只背表格一定要在实验环境里制造一次拥塞。你只有亲眼看到 EF 队列在拥塞时延迟纹丝不动、AF33 的丢包持续增长才能建立真正的直觉。第二条读 RFC 是最快的路径推荐先读 RFC 2475框架、RFC 2597AF、RFC 3246EF再去看厂商配置你会发现几乎所有的命令都是在落实这些行为描述。第三条也是最重要的一条做 QoS 排障时先确认一路上 DSCP 还在不在再谈队列、调度和丢弃。我见过太多人花几个小时调队列参数结果发现报文在入口就被重写成了 0。每跳行为PHB这个知识点说难不难说简单也不简单。它的精髓不在“行为”两个字而在“每跳”两个字边界设备把功夫下够核心设备只做机械化的分类转发整个网络的服务质量才能立得住。希望这篇文章能帮你把那块拼图补上。
返回列表