只消除了一半。HTTP 层的排队没了,TCP 层的队头阻塞还在——一个包丢了,整条连接上的所有流都得停。 而且它得浏览器和服务器同时支持才有效,这注定它活不长。
上一节把 SPDY 的好处量出来了,这一节量它的边界。 结论是:它治的是应用层的病,传输层的病它碰不到。
一、它治的确实是应用层
上一节那 105 毫秒、120 毫秒是真的省下来了,但那是在「网络本身没问题」的前提下测的。 一旦底下丢一个包,情况就反过来。 TCP 的交付是按字节序的:第 5 个段丢了,第 6、7、8 个段就算已经到了,也得在接收缓冲区里等着, 直到第 5 个重传回来。这叫 TCP 层队头阻塞。 HTTP/1.1 里这个问题不严重,因为一条连接上本来就只有一队。 SPDY 把几十条流塞进一条 TCP,一丢包,几十条流一起停——受害面反而变大了。 这一条本机造不出可控丢包,我不给数字,只把机制说清楚。 谁要验证,得在能配丢包率的路由器或 netem 上做。
二、它需要两边同时改
SPDY 不是浏览器单方面能用的东西:浏览器要支持,服务器也要支持,中间那些代理和防火墙最好别捣乱。 任何一环不支持,就得退回 HTTP/1.1。 这就注定它是一个过渡品。 2014 年写这本书的时候,谷歌、推特、脸书这些大站已经上了,但绝大多数网站没有。 更麻烦的是它从没成为正式标准——只有草案,没有 RFC。 没有标准,就没有「必须支持」的压力,也就没有生态。
三、它还活着吗:去问一台真服务器
TLS 握手时有个 ALPN 扩展,双方在这一步商量「接下来跑什么协议」。
只报 spdy/3.1 去问,回来的选择是空——服务器不认识它。
换成报 h2 和 http/1.1,服务器立刻选了 h2。
同一台机器、同一个端口,态度完全不同:SPDY 已经不在它的名单里了。
时间线是这样:SPDY 2009 年出草案,HTTP/2 在 2015 年成为 RFC 7540,
浏览器在 2016 年前后陆续把 SPDY 删掉。
所以这本书里「SPDY 是 HTTP/2 的基础」这句话是对的,但 SPDY 本身已经不在了。
再往后一步:HTTP/2 仍然跑在 TCP 上,所以 TCP 层那个队头阻塞还在。
这正是后来 QUIC 把传输换成 UDP 的原因——那是这本书之后的事,这里只提一句,不展开。
四、动手 Demo:拿 ALPN 去问,再量一次省下的到底是什么
连一台真实的服务器,分别只报 SPDY、只报 h2、只报 HTTP/1.1,看它各选什么。 然后回到本机,量 60 个请求走 1 条连接和走 6 条连接的差别。
ctx = ssl.create_default_context()
ctx.set_alpn_protocols([u'spdy/3.1']) # 只报 SPDY
s = ctx.wrap_socket(connect(HOST, 443), server_hostname=HOST)
print(s.selected_alpn_protocol()) # 空
ctx.set_alpn_protocols([u'h2', u'http/1.1']) # 只报 h2 和 1.1
print(s.selected_alpn_protocol()) # h2
实跑输出:
--------------------------------------------------------------------
SPDY 还在不在:拿 ALPN 去问服务器
--------------------------------------------------------------------
只报 SPDY:谈成 (空) / TLSv1.3
只报 h2+1.1:谈成 h2 / TLSv1.3
只报 1.1:谈成 http/1.1 / TLSv1.3
第一行是关键:服务器不认识 spdy/3.1,所以没得选。
SPDY 从来没成为正式标准(没进 RFC),只以草案形式存在;
浏览器 2016 年前后陆续移除它,接替者是 2015 年成为 RFC 7540 的 HTTP/2。
── 那多路复用省下的是什么:连接数
60 个请求走 1 条连接 360.9 毫秒
60 个请求走 6 条连接 63.1 毫秒
差 297.8 毫秒,5.7 倍
这是 SPDY/HTTP/2 想解决的那个数:少排队就快。但要说清楚两点——
1. 它没有减少字节,一个字节都没少,只是让等的时间不叠在一起;
2. TCP 层自己的队头阻塞它治不了:一个包丢了,整条连接的流都得停。
这一条本机造不出可控丢包,我不给数字,只说机制。
只报 SPDY,谈成的是空,TLS 版本照旧 TLSv1.3。
意思是:加密握手成功了,但应用协议没谈拢——服务器不认识 spdy/3.1。
只报 h2+1.1,谈成 h2;只报 1.1,谈成 http/1.1。
同一台服务器,三行输出就把 SPDY 的结局说清楚了。
回到本机:60 个请求走 1 条连接 360.9 毫秒,走 6 条连接 63.1 毫秒,差 5.7 倍。
这就是多路复用要抢的那块时间。
但注意第二句:它一个字节都没少。所以它不是「压缩」技术,是「别让人排队」的技术。
30 秒实验
- 把
spdy/3.1换成h3再问一次,看能不能谈成——想想为什么。 - 把 60 个请求的耗时改成每个 20 毫秒,看 1 条与 6 条的倍数怎么变。
- 想一想:如果你的网站只有一个大文件要下载,多路复用还有用吗?
常见误区
- 「多路复用能治所有队头阻塞」——TCP 层那一层它治不了,反而受害面更大。
- 「SPDY 是 HTTP/2 的旧名字」——思路被继承,但协议不是同一个,SPDY 已废弃。
- 「多路复用能省带宽」——它省的是等待,字节数不变。
自测三问(点开对答案)
1. SPDY 没解决的那个队头阻塞在哪一层? —— TCP 层:一个段丢了,后面已到达的段也得等重传,整条连接的所有流一起停。 2. 为什么 SPDY 注定是过渡品? —— 它需要浏览器和服务器同时支持,而且从未成为 RFC 正式标准。 3. 只用 ALPN 报 spdy/3.1,结果是什么? —— 选择为空——服务器已经不支持它了;改报 h2 立刻谈成 h2。SPDY 的位置让给了 HTTP/2.0。但 HTTP/2 也是「还跑在 TCP 上」的那个 HTTP/2。
- ☐ (本节完,下一节 9.3.1 WebSocket的设计与功能)