第96期 | 32Kbps 跌到 40bps 那天,网络学会了呼吸

操作系统 · · 九羲科技

第12章第二期。上一期讲了 socket 怎么把整张网缩进一个整数,这一期跟一个包进内核走一趟:从网卡到 socket 队列,它要过几道关;再看 1986 年 10 月的那场崩溃——400 码的距离,吞吐量跌掉一千倍,网络是在那一天学会认错的。

一、包进内核,先过三道关

网卡收到包,先经 DMA 搬进内存的环形队列,再"敲门"——给 CPU 发一个中断。90 年代这么干天经地义;到了千兆时代,一秒几十万个包,每个包敲一次门,CPU 就只剩下开门了。Mogul 和 Ramakrishnan 在 1996 年的 USENIX 上把这病说了个透:病名叫"接收活锁"——系统没有死锁,但 100% 的时间都在应付中断,吞吐量归零¹。药方也直白:忙时别敲门,改轮询。

Linux 的解法叫 NAPI。Kuznetsov、Salim、Olsson 三人磨了三年多,2001 年发表《Beyond Softnet》,2003 年合入 2.5 开发线²。规矩是"闲时中断、忙时轮询":第一个包敲门,内核应门后立刻掐铃——后面的包先攒着,我轮询来取,取净了再开铃。第一个吃螃蟹的是乌普萨拉大学的校园网²。

进了门的包要办"通行证":sk_buff,简称 skb。它不是包本身,是包的文书——一串指针(head、data、tail、end),指着包真正躺的地方³。1996 年就有人吐槽它"长成了一头怪兽"⁴,可怪兽自有道理:层层上交、剥头,靠的不是拷贝,是挪指针——data 往前一划,头就"让"过去了。1999 年,2.2 内核给它加上引用计数⁵,一张通行证,多人传看。

三道关走完,包进了 socket 接收队列,read() 能读到了。上一期那个整数,此刻才算真正连上远方。

窗口流控的"自时钟"——发送方把恰好填满"带宽×时延"这根管道的包送进网络,ACK 回来一个才发下一个;"进去一个,才能再发一个",这就是"包守恒"。据 V. Jacobson、M. Karels《Congestion Avoidance and Control》(ACM SIGCOMM '88)Figure 1 重绘。

二、1986,一场崩溃教会网络谦卑

1986 年 10 月,互联网第一次"拥塞崩溃":LBL 到伯克利分校,直线 400 码、隔两个 IMP 跳,吞吐量从 32Kbps 跌到 40bps——一千倍,说没就没了⁶。Jacobson 和 Karels 去查,凶手竟是 TCP 自己:越堵越重传,越传越堵。

1988 年 SIGCOMM,Jacobson 交出《Congestion Avoidance and Control》⁶。灵魂只有一句话:"包守恒"——平衡时,"进去一个包,才能再发一个包"。落到实现是两个变量:cwnd(拥塞窗口)与 ssthresh。起步 cwnd=1,每收到一个 ACK 加 1,指数涨——这叫"慢启动",名字谦虚,性子最烈;过阈值后每轮只加 1;一丢包,窗口砍半。慢启动的实现,Jacobson 说:一个新状态变量,加三行代码⁶。就这三行,互联网再没崩过。这是最地道的发展性研究:没发明新原理,只把一句朴素道理工程化成能跑的代码。

维纳说,控制就是"感知—比较—执行"的回路⁷。拥塞控制是 OS 里最诚实的一个回路:承认看不见全网,只认一个信号——丢包。丢了退半步,没丢往前探。不预测,不逞强。

推演一步。如果 AI 的操作系统先出现,"连接"不会长成今天这样。2026 年 10 月 26 日,HealthTech 报道美国一家医院的电子病历重构:存储流量跑在 NVMe over TCP 上,直连以太网⁸。存储延迟,如今系在 cwnd 的锯齿上——毫秒级 RTT 调出来的参,要伺候微秒级的 IO。而另一头,AI 训练最吃带宽的集合通信早走 RDMA 直达网卡、绕开内核;QUIC 把可靠连同拥塞控制搬进用户态(RFC 9000,2021)⁹。协议栈被两头掏空:最讲究延迟的走了旁路,最讲究灵活的搬去用户态,内核 TCP 守着中间,吃四十年前的参。

言外之物:Jacobson 的谦卑立在"端到端"分工上——网只管尽力,聪明放两头。可今天两头太聪明了:GPU 聪明到绕开协议栈,QUIC 聪明到重写可靠性。旧抽象没错,只是老了——反馈回路追不上算力的心跳。范式之眼看的正是这处错位:反馈不该再按毫秒级 RTT 调参;当算力主体是微秒级响应的向量阵列,"感知—比较—执行"得换一副更快的身手。

三、亲手量一量,你的拥塞窗口

手边任何一台 Linux 机器,今晚就能看见 cwnd:ss -ti,每个 TCP 连接一行,rtt、cwnd 全在上面——论文里的变量,变成活生生的数字。/proc/net/snmp 里 Tcp 开头的行,重传计数器记着每一次"退半步"。

小实验,看见反馈回路本尊:sudo tc qdisc add dev lo root netem loss 5%,给回环加 5% 丢包;另起终端跑 iperf3 -s 与 iperf3 -c 127.0.0.1,看吞吐从 Gbps 跌到 Mbps;同时循环 ss -ti,看 cwnd 被一次次砍半、再爬回去。玩完删规则:sudo tc qdisc del dev lo root。

这套手感搬去"私有化 AI 落地"现场:token 流式输出抖不抖,流走 TCP 还是 UDP,拥塞算法用 CUBIC 还是 BBR——这不是"网络调优",是用户体验的第一公里。先量,再调。一家企业的视频 AI 平台、私有智能中心走进机房,调的正是这一公里。

觉 然 小 注

网络上最美的波形,是拥塞窗口的锯齿:涨一点,退半步,再涨一点,像呼吸。丢包不是惩罚,是网络在递话——凡发生必有利于我,每一次退半步,都是带宽在告诉你它的边界。慢启动敢从 1 个包起步,相信指数增长会把它带上去,这是出生勇气,也是相信相信的力量;加性增、乘性减,让所有连接最终平分带宽,不争不抢,这是留在爱中。而那个涨涨跌跌的窗口本身,如梦幻泡影——从来就没有一个实有的"窗口"存在过,只有不断调整的步伐¹⁰。

引 用 与 出 处

  1. [1] Jeffrey C. Mogul, K. K. Ramakrishnan. Eliminating Receive Livelock in an Interrupt-Driven Kernel. USENIX Annual Technical Conference, 1996;ACM Transactions on Computer Systems, 15(3), 1997. http://usenix.org/legacy/publications/library/proceedings/sd96/full_papers/mogul.txt
  2. [2] New API. Wikipedia 词条. https://en.wikipedia.org/wiki/New_API
  3. [3] Linux Kernel Network Subsystem. Internals for Interns. https://internals-for-interns.com/posts/linux-kernel-network-subsystem/
  4. [4] Erik Lindsley. LINUX Socket Buffers (Introduction). 1996. http://www.ittc.ku.edu/Projects/Wireless_ATM/linux/linux-skbuff.html
  5. [5] Jonathan Corbet. The case of the prematurely freed SKB. LWN.net. https://lwn.net/Articles/715811/
  6. [6] Van Jacobson, Michael J. Karels. Congestion Avoidance and Control. ACM SIGCOMM '88. 修订版:http://ccr.sigcomm.org/archive/1995/jan95/ccr-9501-jacobson.pdf(一手核对:32Kbps→40bps、400 码、两个 IMP 跳、七个算法、慢启动三行代码,均出自原文)
  7. [7] Norbert Wiener. Cybernetics: Or Control and Communication in the Animal and the Machine. MIT Press, 1948.(思想化用)
  8. [8] HealthTech Magazine, 2026-10-26(经"服务器存储日报"2026-10-30 转引,二手转引)
  9. [9] QUIC. Wikipedia 词条. https://en.wikipedia.org/wiki/Quic
  10. [10] 鸠摩罗什译《金刚般若波罗蜜经》第三十二分.(思想化用)

· · ·

← 返回资讯中心