
简介《QoS网络技术白皮书》是一份面向网络运营商、行业用户及网络工程师的解决方案型技术文档系统梳理了IP网络服务质量保障的完整知识体系。文档从Best-Effort、IntServ、DiffServ三种服务模型入手阐述QoS的产生背景、技术优点并详细讲解流量分类与标记、拥塞管理CQ/PQ/CBWFQ、拥塞避免RED/WRED、流量监管与整形、链路效率机制以及MPLS QoS等核心实现覆盖从理论到落地的完整链条。结合VoIP、视频会议、在线游戏等时延敏感业务以及企业内网和数据中心流量调度场景给出了可参考的优化思路与部署建议。资源为单个docx文档压缩包约2.53MB目录层级分明并附缩略语对照便于快速定位与系统学习。已有110人浏览学习适合需要深入掌握QoS机制、从事网络规划、运维或方案设计的读者作为常备手册。1. QoS到底在解决什么先分清“带宽不够”和“延迟不稳”开会开到一半视频会议开始马赛克网盘的下载任务还在后台跟语音抢带宽。这时候有人把一份《QoS网络技术白皮书.docx》甩进群里你翻完前面几页看到“分类、标记、队列、调度”这些词感觉都认识回到设备前却不知道第一条命令该敲在哪。QoS网络技术解决的是“拥塞时谁先走”的问题当出口带宽被打满时语音、视频、核心业务必须比后台同步和下载更快到达而不是所有流量一起平均受苦。这个方向适合三类人对着一堆队列名词无从下手的网络工程师、买了设备却只配过限速的运维以及想用最少改动保住会议体验的团队负责人。2. 从DSCP标记到信任边界QoS的分类体系必须从接入层就立住在项目里我见过太多这样的翻车现场调度器配置得很漂亮限速也生效了可关键流量还是卡。查到最后问题几乎都出在“分类”没做对——报文从终端进入交换机再穿过核心、网关、运营商任何一跳把优先级标记抹掉后面所有队列策略全部白做。所以做QoS的第一步不是配队列而是搞清优先级写在哪个字段、由谁来写、写完之后到哪为止。2.1 DSCP写在IP头还是以太网头三层与二层标记的对应关系DSCP是IP头里6个比特取值0到63它决定了一个报文在整个三层网络里被对待的方式。常用的几个值要背下来EF是46给语音AF41是34给视频会议AF31是26给重要业务数据CS0是0表示尽力而为。二层也有自己的优先级字段802.1p用3个比特取值0到7写在VLAN Tag里也就是常说的CoS。三层和二层之间通常有映射关系比如EF对应802.1p的5AF41对应4这种映射的意义是让二层交换机在链路上也能把语音和视频放进高优先级队列。实际网络里二层交换机在转发时看不到IP头里的DSCP它只认802.1p三层路由器则主要看DSCP。所以报文从接入层往上走标准做法是“接入交换机上行口信任DSCP并把DSCP映射成802.1p”到了核心三层设备再直接读DSCP。如果全程跑纯二层DSCP反而传不出去所有优先级都靠802.1p撑着。如果中间有GRE、IPSec隧道或者MPLS优先级字段还会被第二次封装里的对应字段接管这就是后面要讲的“隧道丢标记”问题的根源。2.2 信任边界设在哪别让终端自己给自己印高优先级信任边界是一个经常被忽略的配置。默认情况下大多数交换机的端口是“不信任”状态也就是把终端发来的优先级字段全部清掉按普通数据对待。但很多网络管理员图省事把端口设成信任DSCP于是一台开着迅雷的PC也能给自己打的包标成EF语音流量反而被挤掉QoS等于白做。正确的信任模型是终端连着的下联口不信任进来就重标记连接交换机上联、路由器、服务器的口才信任DSCP。这个边界应该设在“能认出业务类型的第一跳设备”上通常就是接入交换机。如果放到核心交换机才做接入层到核心之间的链路已经拥塞过了队列排队发生在错误的位置优先级标签也就失去意义。我在实际环境里见过一个很典型的错误把信任边界设在出口防火墙上结果内网一段全是垃圾队列堆积语音在接入交换机里根本没有被优先处理出口QoS做得再精细也补不回这段延迟。2.3 用iptables给VoIP流量打DSCP 46的最小规则在Linux网关上基于源地址和端口做标记是常见做法因为很多业务端口是固定的。给VoIP的RTP流打EF标记给视频会议服务器打AF41标记iptables -t mangle -A PREROUTING -i eth1 -s 10.10.1.0/24 -p udp --dport 1234 -j DSCP --set-dscp 46 iptables -t mangle -A PREROUTING -i eth1 -s 10.10.1.88 -j DSCP --set-dscp 34这里放在PREROUTING链是因为网关要转发报文在路由决策之前把DSCP改好之后报文从WAN口出去排队时tc过滤器看到的已经是改完的TOS字段。注意-s和--dport可以组合也可以单独按IP段分类如果业务用的是动态端口就得用连接跟踪或者应用识别规则会复杂很多。提示iptables改的是IP头里的DSCP它不会自动帮你重写二层802.1p。如果前面还有一台纯二层交换机必须在交换机上配置信任DSCP并映射到802.1p否则接入层的队列不认这个标记。3. 队列调度器选型与HTB参数把语音、视频和下载分开排队的落地配置标记做得再漂亮到了拥塞点没有队列调度一样没用。QoS的排队只发生在“端口真的塞不下”的时候所以先要找到全链路最窄的那一段通常是WAN出口或者上联口。这一章不讨论具体设备厂商命令只说Linux上最常用的HTB队列以及它背后调度策略的取舍。3.1 队列调度策略怎么选语音走严格优先级下载走公平队列调度策略决定了一个报文在队列里等多久。严格优先级队列也就是PQ或SP高优先级类不出空低优先级类永远得不到服务加权轮询WRR/DRR则按权重分配带宽每种流量都能轮到但要牺牲一点绝对优先性WFQ按照流会话的多少动态分配权重适合大量短连接并发。实际项目里的选型非常简单语音流放进严格优先级队列限制在一个固定带宽内避免一个恶意的VoIP终端把整条链路霸占视频会议放进次高优先级队列给它一个较高的权重和带宽上限默认数据流量全部丢进公平队列让下载、网页、邮件之间互相公平竞争谁也不饿死。常见做法是把语音队列的速率设成固定值即rate等于ceil这样语音最多只能占用这么多带宽但在这部分带宽内它永远最先被发送。3.2 HTB为什么适合做出口限速而不建议用CBQ老一代的CBQ队列通过链路空闲时间估算来限速参数多、计算周期长调起来有很强的“玄学”成分不同内核版本表现还不一样。HTB用的是令牌桶每个类有自己的速率和上限配置直观只要记住rate和ceil就行。HTB的另一个好处是类可以嵌套形成树状结构根类对应整条物理带宽叶子类对应具体业务队列结构清晰出了故障也容易排查。3.3 HTB队列配置示例与关键参数说明下面是最小可用的HTB结构语音类、视频类、默认数据类分别对应三个叶子类。# 删除旧的根队列保证脚本可重复执行 tc qdisc del dev eth0 root 2/dev/null # 创建根队列默认类指向1:30 tc qdisc add dev eth0 root handle 1: htb default 30 # 根类对应物理出口总带宽10Mbps tc class add dev eth0 parent 1: classid 1:1 htb rate 10mbit # 语音类固定2Mbps优先转发 tc class add dev eth0 parent 1:1 classid 1:10 htb rate 2mbit ceil 2mbit prio 0 # 视频类保证3Mbps突发最多8Mbps tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 8mbit prio 3 # 默认数据类保证4Mbps可突发到9Mbps tc class add dev eth0 parent 1:1 classid 1:30 htb rate 4mbit ceil 9mbit prio 7 # 叶子队列语音用极浅的pfifo数据用fq_codel消除缓冲膨胀 tc qdisc add dev eth0 parent 1:10 handle 10: pfifo limit 50 tc qdisc add dev eth0 parent 1:20 handle 20: fq_codel tc qdisc add dev eth0 parent 1:30 handle 30: fq_codel几个关键参数要记住rate是承诺速率即使有富余带宽也不会低于这个速率ceil是上限在父类带宽空闲时可以借用到这个值prio的数值越小优先级越高但HTB不是严格意义上的绝对优先它是在满足各个类令牌约束的情况下优先服务prio更小的叶子类所以语音类要用rate等于ceil来卡死上限。burst参数控制单次令牌桶发放的突发量太小会削掉TCP突发导致吞吐下降太大又会让瞬时流量尖峰逃过限速。常见做法是burst取一个相对较小的值比如15k字节约等于十几个MTU大小既能容忍瞬间突发又不会让限速失效。fq_codel放在叶子队列是近几年的标配。普通pfifo队列又深又长一旦限速生效报文会在队列里等几百毫秒延迟反而被QoS做坏。fq_codel通过CoDel算法主动丢包把队列延迟稳定在几个毫秒级别这对语音和游戏来说是质变。4. 在Linux网关上从零配一套最小QoS完整脚本与验证指标前面讲的是模块这一章给一个能直接抄走的完整落地脚本。假设网络拓扑是内网eth1接办公网段外网eth0接运营商线路上行带宽被限制在10Mbps。语音网关地址是10.10.1.20视频会议服务器是10.10.1.88。整个方案的思路是先在PREROUTING打标记再在eth0的出口挂HTB用u32过滤器按TOS字段分流。4.1 先画流量模型哪些业务保活、哪些业务必须限速动手配置之前先独立一张分类表把端口、DSCP、目标队列、预期行为写清楚。这个表比任何配置片段都重要因为后面调整带宽参数、排查故障时你依赖的是这张表而不是记忆。业务端口/特征DSCP队列预期行为VoIP语音UDP 1234EF(46)1:10延迟最低固定2Mbps视频会议服务器10.10.1.88AF41(34)1:20优先保障突发8Mbps普通上网其余所有CS0(0)1:30公平竞争不饿死网盘下载特定目的IP段CS0(0)1:30不单独保护受限速约束注意网盘下载我不建议单独建一个类去“禁用它”而是让它在默认类里跟其他流量公平竞争。真正要限速的是那些持续占用带宽、又不要求低延迟的后台任务比如备份、更新推送这类流量如果确认是带宽大头可以再加一个专门的叶子类并给很低的ceil。4.2 网关落地脚本iptables标记、HTB队列和过滤规则一次到位完整脚本如下可以直接保存成qos-up.sh执行#!/bin/bash # QoS setup: eth0WAN, eth1LAN WAN_IFeth0 LAN_IFeth1 UP_BAND10mbit # 1. 标记 iptables -t mangle -A PREROUTING -i $LAN_IF -p udp --dport 1234 -j DSCP --set-dscp 46 iptables -t mangle -A PREROUTING -i $LAN_IF -s 10.10.1.88 -j DSCP --set-dscp 34 # 2. 重建根HTB tc qdisc del dev $WAN_IF root 2/dev/null tc qdisc add dev $WAN_IF root handle 1: htb default 30 tc class add dev $WAN_IF parent 1: classid 1:1 htb rate $UP_BAND burst 15k tc class add dev $WAN_IF parent 1:1 classid 1:10 htb rate 2mbit ceil 2mbit prio 0 tc class add dev $WAN_IF parent 1:1 classid 1:20 htb rate 3mbit ceil 8mbit prio 3 tc class add dev $WAN_IF parent 1:1 classid 1:30 htb rate 4mbit ceil 9mbit prio 7 # 3. 叶子队列 tc qdisc add dev $WAN_IF parent 1:10 handle 10: pfifo limit 50 tc qdisc add dev $WAN_IF parent 1:20 handle 20: fq_codel tc qdisc add dev $WAN_IF parent 1:30 handle 30: fq_codel # 4. 过滤规则按TOS匹配到对应类 # 0xb8是EF左移2位的值mask用0xfc只比对高6位 tc filter add dev $WAN_IF parent 1: protocol ip prio 1 u32 match ip tos 0xb8 0xfc flowid 1:10 tc filter add dev $WAN_IF parent 1: protocol ip prio 1 u32 match ip tos 0x88 0xfc flowid 1:20脚本分四段。标记段放在PREROUTING保证报文在转发前就已经被改好DSCP。重建HTB段先删除旧的根队列这是为了方便调试时反复执行脚本不删的话第二次运行会直接报错“RTNETLINK answers: File exists”。队列段注意语音类用了pfifo limit 50因为语音报文不需要像TCP那样靠队列吸收突发队列越深延迟越高50个包的深度已经足够。过滤规则段用u32匹配TOS字段0xb8是EF左移两位后的值因为DSCP只占TOS高6位所以掩码用0xfc这样低两位ECN不会干扰匹配。如果瓶颈是入站方向情况会不同。Linux的ingress方向没有真正的队列调度只有限速和重定向所以常见方案是借助IFB虚拟设备把入站流量重定向到IFB上再做完整的HTB排队modprobe ifb numifbs1 ip link set dev ifb0 up tc qdisc add dev eth0 handle ffff: ingress tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0重定向之后流量就会进入ifb0的出口队列接下来在ifb0上挂一套和前面一模一样的HTB结构即可。4.3 验证命令看队列积压、丢包率和时延别只看“网络通”配置完不是ping通就算完。tc -s class show dev eth0会显示每个类实际发送的包数、字节数和丢弃数这是最直接的证据。正常情况下语音类的drop应该极低而默认数据类在高负载下有一定丢包是合理的说明限速在工作。还需要确认出口标记在物理线路上是否保留用tcpdump抓包看TOS字段tcpdump -i eth0 -v udp -c 50如果看到tos 0xb8说明语音报文的DSCP在出接口可见标记链路是通的。如果看到tos 0x0说明前面的交换机或者网关某处把DSCP清了要回到信任边界去查。5. QoS常见的坑与排查标记丢失、Bufferbloat和网卡队列反转这一章是我最想写的部分因为QoS项目八成以上的时间都花在排查这些问题上。每一条都是实际环境里反复出现过的按“现象、原因、解决”的顺序讲清楚。5.1 隧道和上联端口把DSCP清掉了现象在网关本地抓包能看到TOS 0xb8但到了对端机房抓包发现DSCP变成0。原因有两类一是GRE或IPSec隧道封装时没有继承内层报文的TOS字段二是运营商在骨干网入口把DSCP重标记了这在跨运营商专线里很常见。解决方法是先定位是哪一段被清在隧道两端各抓一次包对比内层和外层报文。GRE隧道可以用tos 0x2e强制设置外层头TOSIPSec则需要在隧道配置里找到“保留原TOS”或“复制TOS”的选项。运营商侧的重标记只能走商务协商让他们在PE设备上信任你的DSCP这不是技术能单方面解决的。5.2 多队列网卡让HTB排队失效现象HTB明明挂上了突发流量也限住了但延迟忽高忽低用ethtool -S eth0能看到流量散在多个硬件队列里。原因是服务器网卡开了RSS多队列每一条硬件队列独立收发QoS调度器在软件层只排了一个队列但报文从不同硬件队列发出去顺序和排队效果都被打散。解决思路是测试环境直接合并队列ethtool -L eth0 combined 1生产环境性能要求高的话用mqprio将硬件队列按优先级划分让高优先级流量固定走某个硬件队列。这里要提醒一句强行合并队列会损失吞吐只适合低带宽出口的网关所以我一般先合并验证效果再决定是否上mqprio。5.3 Bufferbloat队列变深QoS反而把延迟做坏现象加了QoS限速之后普通网页和游戏延迟从20毫秒涨到150毫秒语音也一卡一卡的。原因是HTB限速后叶子队列还是传统的深缓冲pfifoTCP的拥塞控制会把队列填满报文在里面排队的时间越来越长这种现象就是Bufferbloat。解决方法是把叶子队列从pfifo换成fq_codel并调小队列上限tc qdisc replace dev eth0 parent 1:30 handle 30: fq_codel target 5ms interval 100ms limit 300target是CoDel算法期望的排队延迟interval是采样周期limit 300限制队列里最多300个包。对网关设备来说这个组合比默认参数更激进一步但也更符合语音业务的要求。5.4 二层交换机只认802.1p不认三层DSCP现象网关QoS配置完全正确语音流量在出口也有TOS标记但接入交换机内部转发时语音还是跟下载流量一起排队。原因是二层交换机看不到IP头里的DSCP它的队列调度只认802.1p。解决办法是在接入交换机上配置信任DSCP并映射到802.1p各厂商的关键字不太一样常见的是qos trust dscp、mls qos trust dscp这类命令。如果不支持DSCP信任就要在接入层重写802.1p保证报文从接入层进入时优先级已经正确。这一步是整套QoS能否落地的关键也是最容易被忽略的。5.5 “QoS不如扩容”什么时候成立现象团队吵了很久有人说QoS没用不如直接加带宽。原因是持续拥塞的场景下QoS并不能创造容量它只是改变拥塞时谁先死的顺序。结论是如果出口带宽长期超过90%利用率扩容是唯一解如果只是每天固定两三小时拥塞比如上班高峰期视频会议集中QoS能把这段时间的会议体验保下来性价比远高于把带宽翻倍。先看监控曲线再决定方案这是我处理这类争执时的原则。6. 进阶验证用A/B对比证明QoS值不值得做很多网管配完QoS之后只会说“感觉不卡了”这不够。要把QoS做成可持续可迭代的方案需要一套能复现的A/B验证流程。我的做法分四步先打满链路建立基线再开QoS做对照记录关键指标最后判断是否值得推广。第一步打满上行带宽。用iperf3往对端持续发UDP流iperf3 -c 对端IP -u -b 9m -t 300这里的9m要略低于实际上行带宽10m目的是制造稳定拥塞同时避免把链路完全打爆导致所有指标失真。第二步在打流的同时模拟一路语音流量用ping带上TOS值测延迟和抖动ping -Q 0xb8 -i 0.2 -c 300 对端IP记录平均延迟、最大延迟和抖动这时候基线的“惨状”就出来了。第三步把QoS脚本跑起来重复上面两条命令。重点对比两个数字语音流的丢包率是否归零最大延迟是否从几百毫秒掉到几十毫秒以内。第四步用tcpdump确认标记链路没有断再看tc -s class show里各队列的分配是否合理。这套A/B方法最大的价值是一组数据作为判断依据。延迟第99百分位下降超过30%、丢包率从5%以上降到0.1%以下说明QoS值得长期维护如果指标变化不大说明瓶颈不在这一跳要回到流量模型重新画分类表。我自己做网络优化有个习惯拿到一份《QoS网络技术白皮书.docx》先翻分类表和参数表再决定要不要动手——表里的映射关系才是真正能复用的东西。跑完A/B记录一张基线表然后才决定把方案推广到所有出口能少让语音业务在关键时刻翻车。希望帮到你。本文还有配套的精品资源点击获取