📘 第一章 了解Web及网络基础
📄 一句话概括

HTTP/1.1 定于 1999 年,之后十几年只有补丁没有新版。 卡住它的不是想不出办法,而是改协议要动全世界。

📝 本节和前面几节的关系

上一节说网页越来越重,这一节说协议为什么跟不上。 这里算的三种走法,是第九章 SPDY 与 HTTP/2 的直接动机。

一、为什么改不动

HTTP/1.1 是文本协议:人能读懂,代理能改写,中间设备能塞私货。 这是它流行的原因,也是它改不动的原因——中间有太多设备在解析它,动一个字都可能让某台老设备失效。 所以十几年里的进展都是「加法」:加首部、加方法、加状态码,从不敢动请求行的形状。 真正的换代必须等中间设备换代。

二、瓶颈一:每个资源一个往返

HTTP/1.0 默认「一个资源一条连接」,用完就关。六个资源就是六次握手,六次挥手。 Demo 里按跨城 40 毫秒算:每资源一条新连接要 510 毫秒, 换成持久连接(复用一条 TCP)降到 310 毫秒,省掉 39%。 省下的全部是握手——这就是 2.7 节「持久连接」的价值。

三、瓶颈二:队头阻塞(HOL)

管线化(pipelining)能把六个请求一口气塞进去,理论上只要 110 毫秒,比持久连接再省 65%。 它 1999 年就写进标准了,却几乎没人用。 原因是响应必须按请求顺序回。 第一个资源如果是个慢接口,后面五个就算早就算好了也只能等着——这就是队头阻塞。 瓶颈在协议,不在带宽,加带宽没用。 HTTP/2 的解法是给每个请求编号、允许乱序交错回(多路复用)。 但它在 TCP 上跑,一旦丢包,整条连接的所有流一起等——所以 HTTP/3 干脆换到 QUIC(跑在 UDP 上)。

四、动手 Demo:六个资源,三种走法的时间账

不测网络,只算模型:给定往返 40 毫秒、每资源传输 5 毫秒,三种走法各要多久。 数字由代码算,不是估的。

rtt, xfer, n = 40.0, 5.0, 6
# ① 每资源一条新连接:握手 + 请求 + 传输
serial = n * (rtt + rtt + xfer)
# ② 一条持久连接:握手一次,之后每个资源一个往返
keepalive = rtt + n * (rtt + xfer)
# ③ 持久连接加管线化:一次把请求全塞进去
pipelined = rtt + rtt + n * xfer

实跑输出:

--------------------------------------------------------------------
HTTP/1.1 卡在哪儿:六个资源的两种走法
--------------------------------------------------------------------
  假定单程往返               40 毫秒
  资源个数                   6 个
  每资源传输                 5 毫秒

  ① 每资源一条新连接         510 毫秒
  ② 持久连接(串行)         310 毫秒
  ③ 持久连接加管线化         110 毫秒

  ②比①省                     200 毫秒(39%)
  ③比②再省                   200 毫秒(65%)
  管线化看着最划算,但响应必须按请求顺序回,队头那个一卡,后面全堵——这就是 HTTP/1.1 停在原地的原因。

510 / 310 / 110 三个数,对应「每资源一连接 / 持久连接 / 管线化」。 注意 ③ 只有理论值——现实中因为队头阻塞拿不到。 ③比②再省 200 毫秒(65%) 这个比例高得可疑,是因为模型里每个资源的传输时间只有 5 毫秒、 往返却有 40 毫秒,往返被放大成了绝对主角。资源越碎,这个比例越夸张。

30 秒实验

  1. 把 n 从 6 改成 60,重跑,看三种走法的差距是被拉大还是缩小。
  2. 把 rtt 改成 5(同机房),再跑,看管线化的优势还剩多少。
  3. 把 xfer 改成 200(大文件),看「省往返」这件事还值不值钱。

常见误区

  1. 「上了 HTTP/2 就没有队头阻塞」——TCP 层的队头阻塞还在,一个包丢了整条连接一起等。 要根治得换 QUIC。
  2. 「管线化能解决问题」——标准里有,浏览器全线关掉了。
  3. 「HTTP/1.1 太老所以慢」——它慢在「一个连接一次只能有一个在途请求」,不是老。 同机房小文件场景它依然够快。
自测三问(点开对答案) 1. 持久连接省下的是哪一段时间? —— TCP 三次握手(以及慢启动)。请求本身的一个往返省不掉。 2. 管线化为什么没人用? —— 响应必须按请求顺序返回,一个慢响应会堵住后面全部,而且中间代理对管线化支持很差。 3. HTTP/2 解决了什么、没解决什么? —— 解决了 HTTP 层的队头阻塞(多路复用);没解决 TCP 层的——丢一个包全连接等。

协议卡住的原因说清了。接下来回到最底层:这些协议是怎么分层的。

相关笔记