BBR 拥塞控制
上一节末尾说:无论问路多保密,真正决定你多久能到的,是路上的车流怎么调度。这辆车速调度器,学名叫拥塞控制——§ 3.2 交代过它的身份:TCP 里那个"上高速先慢慢开、发现不堵就加速、看到刹车灯就减速"的试探逻辑。这套逻辑从 1988 年服役至今,居功至伟,但它有个刻在骨子里的假设:"堵车"要用"丢包"来证明。整条互联网公路上,几十亿辆车跑了三十多年,全都在等同一个信号——前面有人丢了货,才肯踩刹车。2016 年,Google 的工程师问了一个谁都该问却没人问的问题:为什么不直接测一下这条路到底能跑多快,而要靠"出事故"来猜?这个问题的答案就是 BBR。本节是网络篇的最后一节,我们用它收尾,还有一层用意:BBR 的故事浓缩了这一整章的母题——老协议的每一个"祖传设定"都值得被重新审问一遍;审问的武器不是更快的硬件,而是换一个更聪明的问题。
凌晨五点,高速公路空得能听见风。你开着一辆新款车上路,导航说前方畅通,你一脚油门到底。可你前面始终有一辆老货车,以六十公里的龟速稳稳占着超车道——不是它马力不行,是它的驾驶逻辑写死了:"只有看到前车刹车灯亮过、又灭了,我才敢加一点速;只要视野里有车并过来,我立刻松一半油门。"凌晨五点的空路上没有刹车灯,它就永远等不到"可以加速"的信号,一辆能跑一百二的车,凭本事跑出六十。
你按喇叭,司机摇下车窗喊:"我这套开法三十年零事故!"他没说谎——九十年代的晚高峰,这套"见刹车就怂"的规矩救过整条公路的命。可规矩没告诉你:路是空的。
这辆老货车就是跑了三十多年的丢包式拥塞控制:路(互联网)明明还有巨大余量,它却因为"没收到事故报告"而永远不敢踩油门——又因为"收到了一次事故报告"就把速度砍半。BBR 给车装上的是另一套东西:仪表盘和导航。不猜路况,直接测。
先把这一节的术语翻译成人话
本节概念不多,但每一个都值得掰开揉碎,先过表:
| 术语 | 翻译成人话 | 生活原型 |
|---|---|---|
| 拥塞控制 | 发送方给网络"掐车速"的自动装置 | 货车司机的油门逻辑 |
| 丢包 | 发出的包半路没了(丢了或被扔了) | 快递在途中丢失 |
| RTT | 一个来回的时间(§ 10.2 的老朋友) | 朝山喊话听回声 |
| 带宽 | 路最窄处单位时间能过的车流量 | 高架桥每分钟通行量 |
| 瓶颈 | 整条路上最窄的那一段 | 四车道并成一车道 |
| AIMD | 加一点油慢,踩一半刹车快 | 温水加薪、裁员一刀半 |
| Reno / CUBIC | 两代"看丢包踩刹车"的经典算法 | 老货车的两版说明书 |
| Bufferbloat | 缓冲区膨胀——排队排到延迟爆炸 | 收银台前排的长队 |
| BBR | 不猜、去测:测出带宽和延迟再定速 | 导航 + 仪表盘开车 |
| Pacing | 匀速发车,不搞成批批发 | 流水线节拍器 |
本节的行军路线先交代清楚,免得你在术语里迷路:先审旧世界(老算法靠什么信号、它的规矩从哪场灾难来、跑起来是什么形状),再数三处锈斑(无线误诊、长肥管道、缓冲区膨胀——三处病症,一个病根),然后看 BBR 怎么换掉病根(不猜拥堵,去测容量),最后看它落地时跟现实打的架(公平性、三代进化、与 QUIC 的合流)。带着这条线读,本节没有一处技术细节是凭空冒出来的——每一步都是上一步问题的答案。
温故知新:护"收方"的两扇窗,护"路"的一颗心
先把 § 3.2 讲过的地基夯实,本节所有讨论都站在它上面。TCP 的发送方头顶装着两个限速器:一个叫流量控制——接收方仓库堆不下了,会明确告诉你"别发了",这扇窗护的是收货的人;另一个叫拥塞控制——路上堵不堵没有任何人通知你,你只能靠"货怎么老是丢、走得怎么越来越慢"去猜,这颗心操的是路本身。说白了,一个是有人明说,一个是全靠推测——而"推测"二字,正是接下来一切故事的引线。
推测总得有个依据。1988 年,Jacobson 给出的依据朴素到令人心疼:网络没有仪表盘,但网络会"说话"——丢包和延迟变长,就是它发出的呻吟。包丢了,最可能是因为路由器队列满了、装不下、只好扔——所以丢包 ≈ 堵车。这个推断在有线骨干网时代几乎百发百中:当年路由器的缓冲区都很浅,队列一满立刻丢包,丢包确实是拥堵最诚实的信号。于是老算法(后来的 Reno、CUBIC 都是它的徒子徒孙)定下了那条铁律:丢包出现了,说明开太快了,速度砍半;没丢包,说明还有余量,速度加一点。慢加、暴减——学界给这套节奏起了个名字叫 AIMD(加性增、乘性减),好比温水式加薪、一刀半式裁员:涨薪一次加两百,裁员一次砍一半。
规矩的来历:1986 年那场全城瘫痪
要公平对待这套老规矩,就得回到它诞生的灾难现场。§ 3.2 讲过 1986 年 NSFNET(美国国家科学基金网,互联网的前身骨干)那场著名的拥塞崩溃,这里把另一半现场补全:那年秋天,骨干网的有效吞吐一度跌到正常水平的千分之几——线路还是那条线路、路由器还是那些路由器,什么都没坏,网络却实质上瘫痪了。原因是一个致命的正反馈:发送方发现包丢了就立刻重发,重发的包跟新包一起涌进本已堵塞的队列,队列更满、丢得更多、触发更多重发——路上全是"焦急重发"的复读机,真正的新数据反而挤不进去。用本节的语言翻译:没有车速调度的公路,司机的本能反应(丢了就重发 = 出了事故就原地掉头再跑一遍)恰好是压垮公路的最后一根稻草。
1988 年 Jacobson 的救火方案,本质上就是给每辆 TCP 车装了那套"见丢包砍半"的规矩。为什么砍半这么狠?因为在没有仪表的年代,只有剧烈的集体退让才能打断正反馈——每辆车一看到事故就把速度直接减半,全路的负载瞬间塌下来,崩溃循环被拦腰斩断。事后看,"乘性减"这个当时近乎粗暴的设计,恰恰是数学上被证明能收敛、能自愈的正确解。所以请记住这个背景再往下读:本节接下来数落老算法的每一条罪状,都不是因为它蠢,而是因为它太成功了——成功到全世界把它当成了默认值,而路,悄悄换了材质。老规矩锈蚀的剧情,永远是这样的顺序。
慢镜头:一次下载的锯齿一生
规矩定完了,看它跑起来的样子。不妨这样想:一次大文件下载的开始瞬间,发送方手里没有任何路况情报,只能从极小的发送量起步(几个包),然后每个来回把速度翻一倍——1、2、4、8、16……这段指数爬升学名叫"慢启动",虽然叫"慢",其实是拼命加速;爬到接近某个界限后,翻倍改成每个来回只加一格,进入"拥塞避免"的爬坡段;直到某一刻——丢包了,速度直接砍半,从半山腰重新一格一格往上爬;过一阵又丢,又砍半……如此循环到下载结束。
把这条速度曲线画在纸上,你会看到一个永恒的图形:锯齿。斜着慢慢爬上去,垂直地掉下来,再爬,再掉——一座接一座的小山,山脚永远比上次巅峰矮一半。这个锯齿就是老算法的一生,也是它全部的哲学:永远在"试探着超速"和"被惩罚后痛悔"之间震荡,把路的极限当作一条只有撞上去才摸得到的墙。其实说白了,它把网络当成一个"只能用身体去撞"的黑箱:撞疼了(丢包)就是撞到墙了,退两步,再试探着往前蹭。这个画面请记牢——后面你会看到,BBR 换掉的从来不是锯齿的某个参数,而是"用身体撞墙"这整个认识论。
天才设计的锈蚀:当"丢包"不再是"堵车"的同义词
把丢包当拥堵信号,在 1988 年是天才设计,锈就锈在这几十年网络本身换了材质。第一处锈斑是无线时代的到来。§ 6 章讲过:WiFi 和蜂窝网络靠无线电波传数据,而无线电波天生不稳定——隔一堵墙、进一部电梯、旁边微波炉一开,信号质量抖一下,包就可能在完全不堵的路况下丢失。这在有线世界里几乎不存在(网线里的丢包基本等于队列溢出),在无线世界里却是家常便饭。想象一下后果:你的手机在电梯里丢了两个包,老算法立刻拍板"网络堵了,速度砍半"——可电梯里的路明明空无一人。它把"信号不好"误诊成了"道路拥堵",于是开出了一张白白减速的药方。移动网络时代人人都遇到过"进个洗手间,视频清晰度掉一档",一部分锅就在这张误诊的药方上。
值得停一秒掂量这个误诊的量级。有线世界里"丢包=拥堵"的可信度接近百分之百;而无线链路上,物理层的信号抖动、切换基站、多径干扰都能制造"无罪丢包"——误诊率从接近零涨到了动辄百分之几。你可能会说:几个百分点而已?但这几个百分点砸在锯齿上是被乘性放大的——老算法的一生要爬几百座锯齿山,每次误诊都把速度打回半山腰,爬坡时间全部重来。误诊率涨一个点,平均吞吐可能塌一大截——这就是把"信号"全押在单一指标上的结构性脆弱:指标可信时它是效率,指标掺假时它就成了系统性的拖累。
第二处锈斑更隐蔽,也更致命——它关系到一个反直觉的物理事实:在高带宽、高延迟的路上,老算法天生就开不满。下一节细说。
长肥管道:明明路是空的,车却永远装不满路
把一根跨太平洋的海底光缆想成一根极长的水管:直径很粗(带宽巨大),长度惊人(RTT 一百多毫秒)。想让这根水管"满载输送",你必须一次性把整根管子的容积都灌上水——水不够,管子里有大段空气,实际流量就远低于直径允许的上限;水灌太多,水压超过管子承受力,接口处开始喷漏(丢包)。这个"整根管子的容积",网络术语叫BDP(带宽延迟积):带宽乘以前往返延迟。听着玄,其实就是"路的容量"四个字——不发够这么多在途数据,路就是空的;发超过这么多,路就要吐出来。你可以把 BDP 想成一根香肠的"灌满量":管子多长、肠衣多粗,能灌多少肉就定了,跟你想灌多快无关。
问题来了:老算法怎么知道该发多少?它不知道,它只会试探。丢包了,砍半;没丢包,每个来回多加一点。听起来能慢慢逼近,但在"长肥管道"上,这条爬坡路长得离谱——假设填满一根跨洋水管需要同时在途一万个包,而算法每轮试探只敢多塞几个,爬到满载需要成百上千个来回,每爬几个来回,还会被一次偶发丢包打回半山腰。结果就是:跨洋视频传输、国际会议这类场景里,老算法经常只把管子灌了零头,路上明明空空荡荡,数据却像个没吃饱的传送带慢慢悠悠。凌晨五点那辆老货车,在这里有了数学形象:不是不想快,是它的世界观里"没事故"永远不等于"可以快"。
缓冲区膨胀:排队排出来的"假繁荣"
如果说长肥管道是"路空车慢",那第三处锈斑正好相反:路堵了,系统却报"一切正常"。这就要说到路由器里一个善意的发明——缓冲区(队列)。工程师们想:队列满了就丢包太粗暴,不如把队列做深一点,高峰期先让包排个队,晚点再发。听着很贴心,可这个善意在"丢包=拥堵"的算法面前酿成了大祸:队列越深,丢包来得越晚,老算法就越晚才知道该减速。
推演一遍这条死亡螺旋:下载一个大文件,老算法一路试探加速,包越灌越多,全部排在路由器的深队列里——队列没满,不丢包,算法认定"路还有余量",继续加码;队越排越长,你发的每个包都要在队尾先站几十上百毫秒的队,RTT 从 20 毫秒一路飙到 300 毫秒。此刻带宽确实用满了,但延迟也炸了:同一时刻你打的游戏、你开的视频会议,全都排在下载流量后面罚站——游戏技能放不出来,通话对面全是延迟。更荒诞的是,老算法对这些视而不见:它只盯丢包,队排多长它不管。这就是缓冲区膨胀(Bufferbloat),本世纪初被点破后一度被称为"互联网最严重的隐藏性能问题"。它本质上就是一场"好心办坏事":工程师加大缓冲区的本意是少丢包,结果在丢包式算法的配合下,深队列变成了延迟的蓄水池。它对应的日常画面太常见了:家里有人开始下载,全家的游戏和视频会议瞬间集体变卡——不是网速不够,是有人在深队伍里替全网所有人排队。说穿了,排队不是通行能力:收银台前站一百人的超市,不比站十人的超市收款更快,只是让每个人多等十倍。
BBR 的换问:别猜拥堵,去测容量
三处锈斑——无线误诊、长肥管道装不满、缓冲区膨胀——病根其实是同一个:老算法从头到尾没测过任何一个真实的数。它手里只有一个二手信号(丢包),和一份写于 1988 年的"信号解读手册"。Google 的工程师(BBR 论文的第一作者 Cardwell 团队)的做法干脆利落:把手册扔了,给车装仪表。
BBR 的名字就是它的世界观——Bottleneck Bandwidth and RTT(瓶颈带宽与往返延迟):这条路的容量,由且仅由两个数决定。第一个数是瓶颈带宽:整条路最窄那一段每秒能过多少数据——好比高架桥无论多宽,过江隧道只有两车道,全桥通行量就被隧道锁死。第二个数是来回延迟的下限:光速跑完这段路的物理最短时间(§ 10.2 讲过,这个下限谁也优化不掉)。这两个数怎么测?概念上朴素得很:偶尔故意多发一点点,看吞吐是不是跟着涨——涨了,说明瓶颈还没到顶,更新"最窄段"的记录;偶尔故意少发一点点,看延迟是不是降了——降了,说明之前的队伍排空了一格,摸到了延迟的真实下限。两个测出来的数一乘,就是这根管子的容积(BDP):发送方把在途数据量贴着这个数巡航,路,既不空转,也不爆管。
体会一下这中间的换轴:老算法问的是"网络堵没堵"(用丢包猜),BBR 问的是"网络能跑多快"(用测量答)。打个比方,老算法是"看到前车刹车灯就松油门"的防御型司机,BBR 是"导航实时显示这条路段限速多少、当前路况如何"的数据型司机——前者被动响应事故,后者主动建模道路。丢包在 BBR 的世界观里降了级:从"拥堵的铁证"降为"众多参考信息之一",无线网络里丢了两个包?BBR 看一眼仪表盘:带宽没掉、延迟没涨——判定"信号抖动,非拥堵",油门不松。就这一下,电梯里掉清晰度的老毛病,药到病除大半。
匀速发车:Pacing 这个不起眼的配角
BBR 还顺手修正了一个老算法的坏习惯,这个配角值得单独一提。老算法放数据是"批发式"的:拥塞窗口每扩大一格,就一口气把整格数据全撒出去,等下一批。这种"批发"在网络里会造成瞬间脉冲——一秒内前 50 毫秒挤进一大坨包,路由器队列瞬间被顶出一个尖峰,然后又空转大半秒。就像食堂开饭,明明一小时内来三千人,偏要每十分钟放五百人冲一次窗口,每次都把打饭队列顶爆。BBR 的做法叫 Pacing(配速):既然测出了"这条路每秒恰好过这么多",那就按这个速率匀速发车,包与包之间掐着节拍出门——三千人匀速进场,窗口前的队伍从头到尾只有三五个人。听着只是"换个发车姿势",但在真实网络里,脉冲是很多丢包和延迟尖峰的直接元凶,匀速化等于把事故率从源头摁了下去。顺便呼应一个你可能已经悟到的规律:又是"把突发摊平成匀速"——QUIC 的握手合并省的是等待,Pacing 省的是脉冲,本质都是把"一惊一乍"改成"细水长流"。
退让的另一半:锯齿为什么"公平"
讲 BBR 的毛病之前,得先补一块拼图——老锯齿有一个 BBRv1 当年没有的优点:公平。想象同一条瓶颈路上跑着十条 AIMD 连接:大家一起爬坡,路被填满,开始丢包——注意丢包是随机洒下来的,砸到谁谁砍半。被砸的退下来,把空间让给别人,别人爬上去,下次砸中的换人……长期看,十条连接的吞吐会被这把"随机的大锤"锤得大体均分:谁也别想长期霸占,谁也不会被永久饿死。简单说,AIMD 的公平不是设计出来的善意,而是"随机惩罚 + 集体退让"博弈的自然均衡——像一群人在自动扶梯上被迫保持间距:挤的人先被挤下去,掉下去的人重新排队,队伍整体匀速前进。
把这个背景装进脑子,再看 BBRv1 的问题就一目了然了:它不参与这个"挨锤游戏"。BBR 测出路的容量后贴着容量开,丢包砸下来它看一眼仪表盘——"不是拥堵,不退让";而旁边的 CUBIC 连接挨一下锤就老老实实砍半,让出的空间立刻被 BBR 的稳速流量填上。一场混跑下来,BBR 连接稳稳占着大头,老算法连接在锯齿山脚下反复被锤。公平(大家一起挨锤)和高效(我一个人贴着极限开),在老架构里是一对此消彼长的冤家——这正是 BBRv2 要修的东西,也是理解"新算法不是纯粹升级"的关键:每一次换世界观,都要重新谈判一遍老世界攒下的默契。
配套的两味药:队列管理另一条战线
Bufferbloat 这味病,其实有两条治疗战线,BBR 只是其中一条(端上:发送方主动不喂长队)。另一条战线在路由器里,代表药方叫 FQ-CoDel(以及它的家用简化版 CAKE)——思路完全不同:与其寄希望于发送方自觉,不如让路由器的队列管理变得"刀法精准"。它在路由器上把不同流量分到不同小队列(你的游戏一个队、家人的下载一个队,互不挡道),并给每个队列立规矩:排队的包最多等一小段时间,等不到发出去的机会就主动丢弃——用可控的、早丢的小包损失,换掉失控的、晚到的大延迟。听着很矛盾?其实不矛盾:丢包式算法的世界里,早丢 = 早减速 = 队伍不堆积;与其让包在长队里罚站两百毫秒才被处理,不如一开始就礼貌劝退。打个比方,这是餐厅的叫号机:宁可让新客"过号作废重新取号",也不让门口的队伍排到马路牙子上。一条战线管发送方的油门,一条战线管路由器的队列,两条战线今天在家用路由器和服务器上同时部署着——现实世界的性能问题很少被单一银弹解决,多半是多味药按场景配伍。
慢镜头对照:同一条跨洋路,两种开法
把本章的主角拉到同一条赛道上跑一遍思想实验。赛道:一条 RTT 130 毫秒、容量 500 Mbps 的跨洋链路(管子容积约 8 MB——听上去不大,但要"同时在途"8 MB 数据才能灌满它)。发令枪响:CUBIC 车从几个包起步,翻倍、爬坡、被一次偶发丢包打回,再爬——第一个十秒,它大概率还在山腰挣扎,路是空的;几十秒后锯齿稳定下来,平均能吃到容量的一部分,每座锯齿的尖峰短暂触碰极限又摔下来。BBR 车起步同样谨慎,但前几个来回它一直在干一件事——测:吞吐还在涨,说明瓶颈没到,加速;延迟开始涨了,说明队伍开始排了,摸到下限了;两个数凑齐,容积算出,车速锁定,Pacing 匀速出车——此后大部分时间,它就贴着容量平稳巡航,路满,队短,延迟低。把两条曲线叠在一张图上:一条是永远在攀登和坠落之间震荡的锯齿山,一条是几乎水平的高原线——这就是 2016 年那篇 BBR 论文里最著名的那组对比曲线的通俗版。
从 YouTube 到全世界:BBR 的三代进化
BBR 的发展史本身就是一堂"算法要跟现实打架"的课。一代目(BBRv1,2016)随一篇论文登场,Google 随即将它部署到自家服务和 YouTube 的服务器上——效果立竿见影:尤其是跨洲长肥管道和移动网络这两块老算法最吃亏的战场,全球范围的连接吞吐显著抬升,视频卡顿率应声下降。这是"仪表盘开车"对"刹车灯开车"的一次公开处刑。
可大规模上路的 BBRv1 很快被现实上了一课。问题出在混跑:互联网上跑着 Reno/CUBIC 的老货车和装了 BBR 的新车要共用同一条路,而 BBRv1 仗着"我测过路,我知道极限在哪",贴着极限开,几乎不主动让路——老算法稍有丢包就乖乖砍半减速,让出来的空间立刻被 BBR 补上。短跑下来,BBR 车队呼啸而过,老货车被挤到路边龟行:单看 BBR 连接,性能漂亮;混在路上看,公平性出了名地难看。在浅缓冲的路由器上,BBRv1 还会因为在队列很短时测不准而吃亏退让。于是有了二代目(BBRv2):把丢包信号重新请回仪表盘(不是回到"丢包即拥堵",而是作为"该让让路了"的协调信号),专门修正与老算法的公平共处;再到三代目(BBRv3)继续打磨多连接共享与浅缓冲下的表现,至今仍在开源社区与 IETF 的轨道上持续演进、逐步落地。一代目证明"测"比"猜"快,二代目证明"快"还得跟"公平"谈判——这条进化轨迹,跟 § 10.4 里加密 DNS 从技术标准走到治理谈判,是同一个剧本:技术给出新能力,混居的旧世界逼它学会共处。
可插拔的红利:BBR 与 QUIC 的天作之合
§ 10.2 埋过一个伏笔:QUIC 把拥塞控制做成了可插拔的模块——协议只规定接口,算法随便换,发动机舱统一了标准,换引擎不用重造整车。现在可以揭晓为什么这个设计"被证明极具前瞻性"了:拥塞控制是整个协议栈里迭代最快的层之一。1988 年到 2016 年,底层算法从 Reno 换到 CUBIC 再到 BBR,而且这场进化远没有终点(BBRv3 之后还有 BBRv4 的讨论,学术界每年都有新算法论文)。如果算法烧死在协议里,每换一代就要等一轮全球设备换代——§ 10.2 已经算过这笔账:十几年起。而 QUIC 把它做成模块后,服务器升级一个软件版本就能换上更新的算法,试验和铺开的速度快了一个数量级。今天主流 HTTP/3 服务端普遍在 QUIC 上跑 BBR 系算法,正是"可插拔 + 用户态"两个红利叠加的结果。你甚至可以这样说整件事:QUIC 修好了路(传输层),BBR 是那辆真正把路跑满的车——第 10 章的两条主线,在这一节合龙。
你在什么时候感知到它:BBR 的现实存在感
先把期望值摆正:BBR 不是你家宽带提速器,它干的活儿是发送方的车速调度,管不了你家接入线路的物理上限(§ 1.6 讲过带宽和延迟是路的属性)。你真实感知到它的场景大致有三类。第一类,跨境内容:看海外视频网站的片子比想象中流畅、首屏快、卡顿少——因为服务器到你的路大概率是"长肥管道",恰好是 BBR 相对老算法优势最大的战场。第二类,晚高峰的视频与直播:黄金时段全网流量汹涌,CDN 出口人人自危,服务端用 BBR 把每条连接都喂到刚好贴着瓶颈,同样带宽多服务更多人,你少看几次转圈。第三类,移动网络下的稳定性:地铁里、电梯里信号抖动时掉的不是清晰度而是流畅度,无线丢包的误诊被修正后,体验普遍变稳。反过来说,如果你只是在家访问国内网站,感知会很弱——路近、延迟低、瓶颈就在你家门口的接入段,老算法在这个场景其实干得不差。还有一个冷知识值得收藏:Linux 服务器内核的默认算法至今仍是 CUBIC,不是 BBR——运营大型站点的工程师们会手动一行命令把出口服务器的拥塞控制切成 BBR。默认没换,不是技术保守,而是互联网的默认值动一次影响几十亿连接,这又是第 10 章的老剧本了。
一张对照表:三代调度哲学
| 维度 | Reno(1988) | CUBIC(2008,Linux 默认) | BBR(2016) |
|---|---|---|---|
| 核心信号 | 丢包 | 丢包 | 实测带宽 + 实测延迟 |
| 世界观 | 丢包即拥堵 | 丢包即拥堵(修复更快) | 给路建模,不猜拥堵 |
| 无线网络 | 误诊严重 | 仍误诊 | 区分信号差与真拥堵 |
| 长肥管道 | 严重装不满 | 明显改善但仍受限 | 贴着容量灌满 |
| 深缓冲区 | 排队到延迟爆炸 | 同样中招 | 主动探测延迟下限,不喂长队 |
| 发车节奏 | 批发脉冲 | 批发脉冲 | Pacing 匀速 |
| 混跑公平性 | 基准 | 温和 | v1 出名地霸道,v2/v3 修正 |
读表提示:三行算法不是"淘汰赛",此刻的互联网上三者同时在场——CUBIC 守着海量默认服务器,BBR 挂在大型站点与 QUIC 出口上,Reno 则活在教科书和某些嵌入式设备里。这又是本章那句老话的第 N 次应验:互联网从不删旧枝,只长新枝。理解了这一点,你也就理解了为什么"Linux 默认还是 CUBIC"和"HTTP/3 服务端普遍用 BBR"能同时为真——默认值属于所有人和所有场景,新算法属于愿意主动选择的场景。
顺手送你一副评估新算法的通用眼镜——以后无论再冒出什么拥塞控制新名字(学术圈年年都有新论文),拿这三问去套,八九不离十:第一问,它信什么信号?(丢包?延迟?显式通知?信号可信度决定误诊率);第二问,它对别人狠不狠?(混跑时的公平性——快而不让的算法注定要经历 BBRv1 式的舆论审判);第三问,它在什么路上强?(长肥管道、无线高抖动、深缓冲——没有全场景冠军,只有场景匹配)。通俗地说,这三问分别是"看什么"、"让不让"、"在哪强"——问完这三句,一篇论文你也能读出个大概骨架。这副眼镜不只适用于拥塞控制:评估任何"新方案 vs 老方案"的技术争议,这三问换个措辞照样能用。
老派管理(Reno/CUBIC):市政不发路况报告,只公布交通事故通报。所有司机领到同一本手册:"见到事故通报就减速一半,连续几周没事故就每周提速五公里。"于是——市中心车流稀疏的凌晨,大家还是按"事故手册"的节奏开(长肥管道装不满);郊区的信号灯坏了两天,事故通报变多,全市司机跟着踩刹车(无线误诊);高架入口排起三公里的队,因为"队还没排到入口"不算事故,大家继续往里涌,排得越久越晚知道该分流(缓冲区膨胀)。
新派管理(BBR):市政给每辆车装了导航和仪表盘。导航定期问路:"这段最窄处每分钟实际能过多少车?空车跑完全程要几分钟?"两个数一乘,得到这条路的真实容量,然后广播:"按容量的九成五匀速通行,别抢。"事故通报(丢包)降级成参考信息之一:导航看一眼仪表——车流没降、车速没降?那是路边蹭了辆车,不是堵车,别理它,继续匀速。
新老混跑的岁月里,装导航的车一度把按手册开的车挤到路边(BBRv1 的公平性问题),于是导航升级了两版,学会了在车流里主动让一让(BBRv2/v3)。这座城市最终没有禁掉任何一种车——手册派守着老城区的路口,导航派跑着跨城高速。
而整件事最深的一层:老派管理不是蠢,它是 1988 年那场全城瘫痪(拥塞崩溃)之后的应激智慧——在没有仪表的年代,事故通报是唯一可用的信息。BBR 的真正贡献,是先造出了仪表(测量),再重写了管理的世界观(建模而非猜测)。所有协议演进都是这个套路:不是把老答案骂倒,而是把老问题换掉。
动手清单:亲手摸一摸"车速调度"的存在
- 感受缓冲区膨胀:家里其他人开大流量下载时,你
ping一下网关和外网域名(§ 9.1 的功课)——如果延迟从几毫秒飙到一两百毫秒,你亲眼见到了"排队不是通行能力";下载停下,延迟立刻回落; - 对照观察 Pacing 的效果:同一个视频网站,把清晰度从 1080p 切到 4K 再切回来,观察起播速度和卡顿——码率变了,服务器发送策略(含 Pacing)在替你平滑过渡;
- 如果你有一台 Linux 服务器(或愿意用云服务器试):查当前拥塞控制算法
sysctl net.ipv4.tcp_congestion_control——大概率看到cubic;这就是"CUBIC 仍是默认"的活证据(改不改随你,本站不怂恿生产环境动手); - 移动网络实验:电梯或地铁里观察视频应用的清晰度策略——注意现在多数应用是"宁可降清晰度不断流",这个产品决策背后就有拥塞控制算法的锅从"误诊无线丢包"到"正确识别"的进化红利;
- 把本节的观察跟 § 9.5 的 netstat 联动:视频通话时看一眼
netstat -s(或 Linux 的ss -ti)里的重传计数——重传少而延迟稳,说明这条连接的车速调度运转正常。
常见误区
- 误区一:"丢包就是网络堵了"这是被老算法的世界观带偏的直觉。无线网络里,信号抖动导致的丢包跟拥堵毫无关系——路是空的,只是无线电波这一程没接住。区分"信号差"和"真拥堵",正是 BBR 对老算法最漂亮的修正之一。下次测速软件报丢包,先想想丢在哪一程。
- 误区二:"BBR 是 HTTP/3 或 QUIC 的一部分"分层搞混了。QUIC 是传输层协议(路),BBR 是拥塞控制算法(车速调度策略)——两者独立存在、自由组合:BBR 也能跑在 TCP 上(2016 年它就是从 TCP 起家的),QUIC 也能跑 CUBIC。它们的亲密关系来自 QUIC 的可插拔设计让 BBR 换装更方便,而不是从属关系。
- 误区三:"换成 BBR,网速就能翻倍"场景依赖非常强。跨境长肥管道、无线高抖动、深缓冲——这三类场景提升明显;反之,延迟低、瓶颈就在接入段的本地网络,老算法本来就能开满,BBR 提升有限。它调度的是发送方的车速能不能贴住路的容量,它变不出路本身没有的容量(带宽和延迟是路的物理属性,§ 1.6)。
- 误区四:"BBR 已经全面取代老算法了"远没有。Linux 默认仍是 CUBIC,海量服务器、家用路由器、嵌入式设备跑的仍是丢包系算法;BBR 主要活跃在大型站点出口、CDN、QUIC 服务端。互联网从不删旧枝——这句话本章从 HTTP/3 说到 IPv6 再说到这里,第三次应验。
- 误区五:"缓冲区越大网络越好"恰恰相反的部分最伤人:缓冲区只在"刚好吃下瞬时突发"时有价值,过深的缓冲在丢包式算法配合下制造的是延迟爆炸(Bufferbloat)。排队不是通行能力——收银台前排一百人的超市不会因此多收一分钱,只会让所有人多等。深缓冲是善意,但在错误的世界观里,善意会变成帮凶。
- 误区六:"拥塞控制只跟下载速度有关"它对你的延迟影响更大。游戏技能放不出、视频会议对方卡成PPT、语音通话互相抢话——这些"实时性"受害者的元凶常是缓冲区膨胀,而治它的药(测延迟下限、匀速发车)正是 BBR 系算法的强项。评估一个拥塞控制算法,永远要同时看吞吐和延迟两条曲线。
带走三句话。第一,老法则的锈不在快慢在假设:丢包式拥塞控制的三处失灵(无线误诊、长肥管道装不满、缓冲区膨胀)病根相同——把"丢包"当"拥堵"的独家证据,在换了材质的网络上批量制造误判。第二,BBR 的革命是换问题而不是换答案:从"网络堵没堵"(猜)换到"网络能跑多快"(测),测瓶颈带宽、测延迟下限、匀速发车——仪表盘代替事故通报。第三,进化从未收尾:BBRv1 快而霸道,v2/v3 学会公平,Linux 默认仍是 CUBIC——新枝与旧枝共生的图景,贯穿了整个第 10 章。
网络篇到这里收官。十章走完,你手里的地图已经完整:第 1 章认识网线和门牌,第 2 章看懂分层,第 3 章拆解三巨头,第 4 章跟完一次完整的网页加载,第 5、6 章摸清有线与无线,第 7 章走进云与边缘,第 8 章披上安全的盔甲,第 9 章配齐排错的工具箱,第 10 章看着老协议如何被逐个翻新。下一程,我们离开"网络"这层看不见的管道,去看人与机器之间那层看得见的皮肤——界面篇:GUI 是什么,像素从哪里来,点击如何变成回应。