请想象快递员阿邮入职“同城快送”公司的十年。刚入职时,他骑一辆单车,一次只能驮一个包裹:从网点取件、骑车、送货、骑车回网点,再取下一件。客户抱怨,30 件包裹有时要等一上午。后来公司买了大卡车,把包裹统一装进标准货箱,一趟能拉几百件——可全城只有一条高速路,修路堵车时,满载的大卡车也只能停在原地,一车货谁都收不到。直到公司给每件包裹配了专属无人机:每架飞机飞自己的航线,一架遇雨返航,其他几十架照常送达。单车、卡车、无人机,正是 HTTP 协议从 1.1 走到 2 再走到 3 的进化之路:从文本时代的单连接逐包传递,到二进制分帧的多路复用,再到 QUIC 独立流的彻底畅通。读完这篇文章,你会明白每一次“换车”究竟解决了什么,又留下了什么瓶颈。

岗位关联

掌握 HTTP 版本演进,等于握住网络传输的底层地图。AI 从业者在部署大模型推理、多模态数据传输、RAG 检索管线时,能精确定位延迟瓶颈出在协议的哪一层,不再被“忽快忽慢”的玄学折腾。

目录
  1. 可视化演示
  2. 文本传输时代
  3. 二进制分帧
  4. QUIC革新
  5. 队头阻塞根因
  6. 连接复用进阶
  7. 头部压缩演进
  8. 流优先级控制
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

交互式对比HTTP/1.1、HTTP/2和HTTP/3的核心特性差异,展示从文本协议到二进制分帧再到QUIC的演进历程,包括多路复用、头部压缩、0-RTT握手等关键改进。

本节配有交互动效(进入视口后自动加载,约 3KB)。

HTTP协议版本对比 HTTP/1.1:文本协议,队头阻塞,每次请求需新建连接 HTTP/2:二进制分帧,多路复用,HPACK头部压缩 HTTP/3:基于QUIC,0-RTT握手,解决TCP队头阻塞

文本传输时代

阿邮刚入行的日子最苦:网点规定,一辆单车一次只能装一件包裹,必须把这件送到、骑车回网点,才能领下一件。更麻烦的是,每次出车都要在门口盖章登记——相当于建立一条新连接。HTTP/1.1(1997 年发布)就是这样的单车时代:浏览器与服务器之间一次只能跑一个请求,请求和响应都是纯文本,像手写信一样逐行书写,人类用记事本都能直接读懂。

为了解决“每件包裹都重新登记”的浪费,HTTP/1.1 引入了 Keep-Alive 长连接,让同一辆单车在同一个村落里来回跑。但载客规则没变:一个连接上同时仍只能有一个请求在途。浏览器要加载网页里的 HTML、CSS、JS、图片等几十个资源时,只能排队——第一个资源没到,第二个请求根本发不出去,哪怕它只是一个小小的图标。

这种“前一个请求挡着后一个”的现象,就是队头阻塞(Head-of-Line Blocking)。它的延迟是串行叠加的:N 个资源要等 N 次往返。再加上新建连接时的 TCP 三次握手与 TLS 协商,每次连接都额外付出约两个往返时延(RTT)。在跨洋场景下 RTT 动辄上百毫秒,体验自然雪上加霜。

阿邮后来统计过:一个村子 30 个包裹,他要骑单车在同一条巷子里往返 30 趟,每趟还要回网点盖章。他说“我不是在送快递,是在排队”。HTTP/1.1 时代优化者的所有手段——开多个连接、拆多个域名——本质上都是“多雇几个阿邮”,可单车道的拥挤,并没有真正被解决。

T1.1=N×RTT+2×RTT\displaystyle T_{1.1} = N \times RTT + 2 \times RTT
公式说明:N 个资源逐个排队往返,总时间是 N 个 RTT 相加,还需加上建立连接的两轮握手开销。
  1. 请求数量 N页面里待下载的资源个数,每个资源对应一次请求-响应的完整往返
    NN
  2. 往返时延 RTT一个数据包从浏览器到达服务器再返回所需的时间,单位常为毫秒
    RTTRTT
  3. 串行累加 N×RTT请求一个接一个完成,总等待时间随 N 线性增长,这就是“排队”的数学代价
    N×RTTN \times RTT
  4. 握手开销 2×RTTTCP 三次握手加 TLS 协商约需两次往返,每次新建连接都要付这笔“登记费”
    2×RTT2 \times RTT

二进制分帧

转机出现在 2015 年:公司引进了“集装箱化”——所有货物无论大小,一律拆装进统一规格的标准货箱,货箱上印着订单号,一辆大卡车可以同时装载几十个订单的箱子,到了同一条街,按订单号分发给不同客户。这就是 HTTP/2 的核心思想:二进制分帧层(Binary Framing Layer)。

HTTP/2 把请求和响应切成一个个二进制“帧”(Frame):9 字节固定头部 + 最多 16KB 载荷。帧头里最重要的字段是 4 字节的流标识(Stream ID),它标注了这箱货属于哪个“订单”(流)。因为数据被切成带编号的小块,多个流的帧就能在同一条 TCP 连接上交错发送——你的请求和我的请求像混编在同一趟地铁车厢里的乘客,到站各自找门下车。

这种交错传输就是多路复用(Multiplexing):一条连接同时承载成百上千个流,任何一个资源都不用等前面的资源完成。它从根上消灭了 HTTP 层的队头阻塞。帧按用途分为 HEADERS、DATA 等类型;流则有客户端发起的双向流与服务器发起的单向流之分,后者正是服务端推送的载体。帧的小而规整还带来额外红利:更细的传输粒度、更均匀的带宽占用,也为头部压缩创造了条件。

集装箱化的好处立竿见影,但阿邮很快发现新问题:卡车再能装,走的还是那条唯一的高速公路——TCP。公路上一旦修路(丢包),所有车、所有货都得停下来等交警放行(重传)。下一节,我们把目光投向这条“老公路”。

η=LL+9\displaystyle \eta = \frac{L}{L + 9}
公式说明:帧效率指载荷字节在总帧长中的占比,帧头固定 9 字节,载荷越大效率越高。
  1. 载荷长度 L一个帧携带的业务数据字节数,最大可达 16384 字节
    LL
  2. 帧头开销 9每个帧固定 9 字节头部,包含流标识、帧类型、长度等元数据
    99
  3. 帧总长 L+9一个帧在线上传输的总字节数,是载荷与帧头之和
    L+9L + 9
  4. 效率比值 η比值越接近 1,说明协议把越多字节花在“真数据”上,而不是元数据上
    η=LL+9\displaystyle \eta = \frac{L}{L + 9}

QUIC革新

2022 年,公司彻底换了玩法:给每件包裹配一架专属无人机。无人机自己带导航、自己报航线,完全不依赖地面的红绿灯和收费站。这就是 HTTP/3 的赌注——把传输层从服役四十年的 TCP 换成基于 UDP 的 QUIC。

为什么敢用“不可靠”的 UDP?因为 QUIC 在用户态(应用程序里)自己实现了可靠传输、拥塞控制、加密和流管理:相当于无人机自带飞行控制系统,不需要地面交警。TCP 做不到的事它都能做:每个流独立编号、独立确认、独立重传;连接用 Connection ID 标识而不是 IP 加端口;还能复用 TLS 1.3 的会话凭证,实现快速重连。

QUIC 有三张王牌:第一,独立流——一个流的丢包只重传自己,其他流照常送达,TCP 层的队头阻塞被彻底拆除;第二,0-RTT 握手——首次连接 1 个 RTT 即可发出请求,带会话恢复的重连甚至 0 个 RTT,而 HTTP/1.1 走 TCP+TLS 需要 2 到 4 个 RTT;第三,连接迁移——手机从 WiFi 切到 4G,连接不断、请求不丢,因为连接不再认“门牌号”(IP+端口),只认“身份证”(Connection ID)。

阿邮的无人机再也不怕“修路”了:哪怕一架飞机被大雨淋了返航,其他几十架照样把包裹准时送到。用户感受到的,就是视频不再转圈、游戏不再瞬移——这正是弱网环境下 HTTP/3 的杀手锏。

T首次=1×RTT,T恢复=0×RTT\displaystyle T_{首次} = 1 \times RTT,\qquad T_{恢复} = 0 \times RTT
公式说明:QUIC 首次连接只需 1 个 RTT 就能发出请求;携带上次会话凭证的客户端重连可以做到 0 RTT。
  1. 首连握手 1×RTT首次连接时,客户端与服务器通过 1 个往返完成传输参数与密钥协商
    T首次=1×RTTT_{首次} = 1 \times RTT
  2. 会话恢复凭证客户端保存上次的 TLS 票据,重连时直接携带加密的会话参数,省去握手
    T恢复=0×RTTT_{恢复} = 0 \times RTT
  3. 对比旧方案 2~4×RTTTCP 三次握手 1.5 RTT 加 TLS 1.2 协商 1~2 RTT,旧方案建立通道明显更慢
    T旧=2∼4×RTTT_{旧} = 2 \sim 4 \times RTT

队头阻塞根因

让我们停下来,把“队头阻塞”这口锅看明白。它其实有两层:第一层在应用层——HTTP/1.1 的请求排队,像单车道的巷子里所有车只能鱼贯而行;第二层在传输层——TCP 的按序交付,像全城唯一的高速路有一段在修路,所有车都必须停下等待放行,哪怕你既不经过修路段,车上装的还是加急件。

HTTP/2 用多路复用拆掉了第一层——请求们不再排队了;但第二层它无能为力,因为所有流的数据最终都混进同一条 TCP 字节流,TCP 的规矩是“必须按顺序交给应用层”。一个数据段丢失后,后到的所有数据都要躺在接收缓冲区里等重传,即使它们属于其他毫发无损的流。这就是 HTTP/2 的“阿喀琉斯之踵”。

数学上这代价有多重?经典的 Mathis 公式给出了 TCP 连接的吞吐上限:吞吐 B 约等于最大报文段 MSS 除以 RTT 与丢包率平方根的乘积。丢包率从 0.1% 升到 1%,吞吐量就要掉到原来的约三分之一。在丢包率 1% 以上的弱网环境(移动、跨洋、卫星链路),这种退化肉眼可见。HTTP/3 的解法是“流”级别的独立:QUIC 里每个流都有独立的字节序列和确认机制,丢包的流自己慢慢等重传,其他流的数据立即上抛给应用——修你那一段路,其他车走自己的高架桥。

所以“队头阻塞”不是 HTTP/2 的 bug,而是 TCP 时代的地基缺陷。阿邮比喻成:卡车时代,只要高速路上有一段在修,满车包裹都困在源头;无人机时代,每架飞机有自己的航线,修路与我无关。理解了这一层,你就看懂了为什么所有云厂商都在抢着部署 HTTP/3。

B≈MSSRTT×p\displaystyle B \approx \frac{MSS}{RTT \times \sqrt{p}}
公式说明:TCP 连接吞吐量与 RTT 和丢包率的平方根成反比,丢包越频繁,整条连接越“堵”。
  1. MSS最大报文段大小,约 1460 字节,相当于一辆卡车的标准装载量
    MSSMSS
  2. RTT一个数据包往返一次的时延,时延越大,单位时间内能跑的往返越少
    RTTRTT
  3. 丢包率 p数据包丢失的概率,p 越大触发重传越频繁
    pp
  4. √p 的影响吞吐随丢包率的平方根衰减,例如 p 变为 100 倍时吞吐只剩约 1/10
    p\sqrt{p}
  5. 吞吐上限 B整条 TCP 连接在给定网络条件下的最大传输能力,近似为 MSS 除以两者的乘积
    B≈MSSRTT×p\displaystyle B \approx \frac{MSS}{RTT \times \sqrt{p}}

连接复用进阶

聊完阻塞,再看“连接”本身怎么被一路优化。阿邮刚入职时,每送一单都要回网点重新盖章登记——每个请求都新建 TCP 连接,效率极低。HTTP/1.1 引入 Keep-Alive,让单车在同一个村落里反复使用,不用每次都登记;但规则仍是“一车一单”,单车道上依旧排队。

浏览器工程师们的对策很粗暴:开多条并行车道——为每个域名建立约 6 条连接(连接池管理),再把资源拆分到多个子域名上,让 6 条车道变成 18 条。代价是每条新连接都要付一次 TCP+TLS 握手的“登记费”,服务器也要维护海量连接的内存与文件描述符。HTTP/2 的答案完全不同:把 6 条小车道合成 1 条大高速公路,所有流在这条路上多路复用,只需要登记一次。

连接数量从多到少、从短到长,是三个版本最直观的演进线。HTTP/1.1 一请求一连接;HTTP/2 所有流共享一条 TCP 连接;HTTP/3 仍是一条连接,但这条连接是“打不死”的——QUIC 用 Connection ID 标识连接,设备换了 IP(WiFi 切 4G、DHCP 换地址),连接照样存活,应用层毫无感知。协议协商方面,浏览器通过 TLS 的 ALPN 扩展在握手时告诉服务器“我支持 HTTP/2 还是 HTTP/3”,双方选一个都能懂的语言,就像乘客上车前先确认坐几路公交。

阿邮的体会是:过去六辆小车排着队过收费口,每辆都要停车扫码;现在并成一辆大挂车,交一次费、一起进城。省下的时间在跨洋 RTT 超过 100ms 的场景里,是肉眼可见的“快了两三秒”。

T节省=(C−1)×2×RTT\displaystyle T_{节省} = (C - 1) \times 2 \times RTT
公式说明:把 C 条并发连接合并成 1 条,就省下了其中 C-1 条连接各自的握手时间。
  1. 并发连接数 CHTTP/1.1 时期浏览器为提速并联的通道数,通常为 6 条
    CC
  2. 单次握手 2×RTT每条连接建立 TCP+TLS 通道约需两次往返
    2×RTT2 \times RTT
  3. 合并省 C−1 次HTTP/2 只用 1 条连接承载所有流,其余 C−1 条的握手时间全部省下
    (C−1)×2×RTT(C - 1) \times 2 \times RTT

头部压缩演进

阿邮每天最烦的是填快递单:同一个客户,姓名、电话、地址几乎不变,但他每寄一次包裹就要手写一次。HTTP/1.1 的请求头就是这张“重复填写的快递单”——User-Agent、Accept、Cookie、Host 等字段每次请求全量发送,动辄几百字节,而真正变化的内容往往只有几个字节,典型页面打开一次就要重复几千字节的头部。

HTTP/2 的 HPACK 压缩算法改变了规则:快递公司建了会员档案室。静态表预置 61 个常见字段的固定编号,比如"method: GET"直接用一个编号代替;动态表记录本次连接里新出现的字段,同一连接后续请求只需发一个索引号;再加上 Huffman 编码压缩长文本值。平均而言,一个 700 字节的请求头可以被压到 8~10 字节,体积约为原来的百分之一。

为什么头部压缩对 HTTP/2 尤其重要?因为多路复用下,一条连接承载大量小请求,头部的体积占比被放大了——如果每次请求都带全量头,前面公式里的帧效率 η 会被拖垮。而 HTTP/3 的 QPACK 是 HPACK 的“乱序适配版”:QUIC 的流可以乱序到达,动态表更新不能依赖“先到先查”的顺序,所以 QPACK 用专门的单向流同步表更新,让解压不依赖到达顺序。

会员档案建好之后,阿邮只需对着老客户喊一声“老地址”,对方就心领神会。头部压缩的道理一模一样:省下的不仅是流量,更是每一个请求的传输时间——在即时通信、网页加载这类短请求密集的场景里,收益被成倍放大。

H压缩≈H原始100\displaystyle H_{压缩} \approx \frac{H_{原始}}{100}
公式说明:重复字段被索引替换后,头部体积大约缩小到原来的百分之一。
  1. 原始头 H_原始未压缩的请求头约 500~800 字节,大半是雷同字段
    H原始≈700 BH_{原始} \approx 700\,B
  2. 静态表索引61 个高频字段按固定编号编码,几字节即可表达完整字段名
    index∈[0,61]index \in [0, 61]
  3. 动态表索引连接内新出现的字段被登记编号,后续请求复用编号,无需重发全文
    index动态←H新增index_{动态} \leftarrow H_{新增}
  4. 体积比 1/100静态表、动态表加 Huffman 三重压缩后,头部可缩小约两个数量级
    H压缩≈H原始100\displaystyle H_{压缩} \approx \frac{H_{原始}}{100}

流优先级控制

无人机多了,调度就成了艺术。阿邮的调度台屏幕上,任务分着轻重缓急:用户正在看的视频关键帧要立刻起飞,后台自动下载的安装包可以慢慢飞。HTTP/2 的流优先级机制,就是这个调度台。

每个流在创建时可以声明两件事:依赖关系(“我等 A 流先到”)和权重值(1~256 的整数,越大越优先)。服务器分配带宽时按权重比例切蛋糕:同级所有活跃流的权重之和是分母,某个流的权重是分子。这样浏览器就能让 HTML 和首屏 CSS 高权重快跑,让懒加载图片低权重慢飞,避免非关键资源抢占首屏的带宽。

流之间还能形成“优先级树”:父流先于子流,低优先级流可以给高优先级流让路。HTTP/3 沿用并强化了这套机制,还会在调度中加入抢占语义,让控制的颗粒度更细。一个现实例子:浏览网页时,如果图片下载和 CSS 下载同权重竞争,页面可能出现“样式闪变”;正确的优先级树能让 CSS 先行,画面一次渲染到位。

这就像医院分诊台:危重病人进抢救室,轻症患者排队候诊。调度台上的“优先级树”决定了用户体验的丝滑程度——首屏关键资源永远插队先飞,背景任务乖乖让路。阿邮说,真正的效率不是所有无人机一起抢,而是让该快的快、该等的等。

Ri=R总×wi∑jwj\displaystyle R_i = R_{总} \times \frac{w_i}{\sum_{j} w_j}
公式说明:流 i 分到的带宽 = 总带宽 × 该流权重占同级全部权重之和的比例。
  1. 流 i 的权重 w_i应用层为每个流声明的优先级权重,取值 1 到 256
    wiw_i
  2. 同级权重之和 Σw_j与流 i 同属一个父节点的所有活跃流权重累加
    ∑jwj\sum_{j} w_j
  3. 按比例分带宽每个流的带宽份额等于其权重占比,权重翻倍则分到的带宽翻倍
    Ri=R总×wi∑jwj\displaystyle R_i = R_{总} \times \frac{w_i}{\sum_{j} w_j}

AI 应用场景

大模型流式对话的低延迟并发

阶段:模型推理与 API 服务

解决的问题:LLM 应用一次用户提问往往要并发多个请求:主模型的 SSE 流式输出、Function Calling 的工具调用、记忆检索等。HTTP/1.1 下这些请求共用连接会排队,首 token 延迟被拉长;HTTP/2 多路复用让它们并行出发;HTTP/3 在弱网(移动端、跨洋)下还能避免一个慢工具请求拖住整场对话。就像阿邮同时接到三件加急件,单车只能一件件送,无人机调度台却能同时起飞。

具体案例:某客服机器人的一次提问触发 5 个 MCP 工具调用加 1 个主模型 SSE 流。串行时最坏要空等 5 个 RTT 才轮到主模型出第一个 token;改用 HTTP/2 多路复用后,首 token 延迟降低约 60%;手机弱网环境下切到 HTTP/3,工具流偶发重传也不再阻塞主模型打字。

端侧模型热更新与回传

阶段:边缘部署与模型分发

解决的问题:无人车、无人机、机器人等边缘设备要频繁增量下载模型热更新包、回传推理日志,链路长、抖动大,TCP 一次丢包就会让整个下载卡顿。HTTP/3 独立流让模型分片并行传输,一个分片重传不影响其他分片落地;连接迁移让车辆穿隧道、切换基站时下载不中断。

具体案例:某巡检无人机的机载端每 4 小时同步一次模型增量(约 20MB),通过 HTTP/3 QUIC 分片传输,弱网下总耗时比 HTTP/2 缩短约 40%,且切换 4G/5G 基站时连接自动续传,不再从头开始。

RAG 多路召回的并行聚合

阶段:检索增强生成(RAG)管线

解决的问题:RAG 要同时查向量库、关键词索引、混合检索并做重排,几个子请求相互独立却要在网关处聚合。HTTP/2 的单连接多路复用让这些子请求并行而非排队;HTTP/3 则保证在跨地域部署(向量库和多路 API 分散在不同机房)时,单一链路的抖动不会拖垮整条聚合链路。

具体案例:某企业知识库 RAG 服务把“向量检索 + BM25 检索 + 权限过滤”三个请求并行发给不同微服务,网关用 HTTP/2 单连接汇聚结果,聚合 P99 从 HTTP/1.1 时代的 1.8s 降到 0.6s;远程分支机房接入 HTTP/3 后,偶发丢包不再引发整体超时。

Python 演示

python40 行
import random  def http11_latency(n_requests, rtt):    # HTTP/1.1: requests are serial, one RTT each    return n_requests * rtt  def http2_latency(n_requests, rtt, loss_p):    # HTTP/2: multiplexed but TCP is ordered, one loss stalls all streams    latency = rtt    for _ in range(n_requests):        if random.random() < loss_p:            latency += 3 * rtt  # retransmission timeout, every stream waits    return latency  def http3_latency(n_requests, rtt, loss_p):    # HTTP/3: independent streams, only the lost stream is delayed    latency = rtt    for _ in range(n_requests):        if random.random() < loss_p:            latency = max(latency, 3 * rtt)    return latency  def main():    random.seed(42)    n_requests = 10    rtt = 50  # ms    trials = 2000    for loss in (0.0, 0.02, 0.05):        l11 = sum(http11_latency(n_requests, rtt) for _ in range(trials)) / trials        l2 = sum(http2_latency(n_requests, rtt, loss) for _ in range(trials)) / trials        l3 = sum(http3_latency(n_requests, rtt, loss) for _ in range(trials)) / trials        print("loss={:.0%} http11={:.0f}ms http2={:.0f}ms http3={:.0f}ms".format(loss, l11, l2, l3))  if __name__ == "__main__":    main()
目的:用蒙特卡洛模拟对比三种协议在丢包环境下的延迟特性,直观展示 TCP 层队头阻塞的代价与 QUIC 独立流的优势。
  1. return n_requests * rttHTTP/1.1 串行:10 个请求就是 10 次往返时延,阿邮的单车只能一单一单送。
  2. latency += 3 * rttHTTP/2 中一次丢包,整条连接都要等超时重传,所有流一起买单。
  3. latency = max(latency, 3 * rtt)HTTP/3 中丢包只影响丢了的那个流,总延迟只看最慢的流。
  4. random.seed(42)固定随机种子,让每次运行结果可复现,方便对比实验。
  5. for loss in (0.0, 0.02, 0.05):分别模拟无丢包、2% 和 5% 丢包率下的三种协议延迟表现。

常见误区

误区既然 HTTP/2 有了多路复用,网页资源都能同时下载,队头阻塞就应该彻底消失了。网站还慢,那一定是服务器或带宽的问题,跟协议没关系。

正解多路复用消灭的只是 HTTP 层的队头阻塞——请求不再排队了。但 TCP 层的队头阻塞依然存在:TCP 按字节序交付,一个数据段丢失,后续所有已到达的数据都得躺在接收缓冲区里等重传,哪怕它们属于别的流。好比卡车装满几十个订单的货箱,可全车走一条高速,修路段一堵,整车的货一起等。只有 HTTP/3 的 QUIC 独立流,才让每箱货各走各的运输通道。

为何常见:HTTP/2 的宣传聚焦多路复用,绝大多数资料很少深入 TCP 按序交付的实现细节,学习者容易把“应用层不排队”等同于“完全不阻塞”。

误区HTTP/3 就是 HTTP/2 加了个 UDP,UDP 天生比 TCP 快,所以性能提升全靠换传输协议。

正解不是简单换车。UDP 本身只提供数据报收发,QUIC 是在用户态用 UDP 重新实现了可靠传输、拥塞控制、TLS 加密和流管理,相当于给无人机装上导航、避障和自动签证系统,而不是把出租车换成公交车。真正的收益来自独立流(消除 TCP 层队头阻塞)、0-RTT 握手和连接迁移,单看“UDP 比 TCP 快”是完全跑偏的。

为何常见:人们喜欢找一个简单的归因。从表面看 HTTP/3 确实基于 UDP,“换协议所以快”听起来顺理成章,于是忽略了 QUIC 在用户态做的大量工程。

误区HTTP/1.1 时为了绕过 6 连接限制,我们把资源拆到多个子域名、把 JS/CSS 内联进 HTML。这些优化在 HTTP/2 下当然继续有效,应该保留甚至加强。

正解在 HTTP/2 下域名分片反而有害:每多一个域名就多一条连接,每条连接都要各自握手、各自慢启动,还会打散 HPACK 动态表,导致头部压缩率下降。内联和雪碧图在单连接多路复用下收益大减,反而拖慢首屏。正确姿势是收敛域名、用单连接的流优先级来调度关键资源。

为何常见:开发者从 HTTP/1.1 时代积累的优化套路根深蒂固,旧经验在协议换代后依然被惯性沿用。

误区QUIC 的 0-RTT 意味着连接永远不需要握手,无论第一次还是第 N 次都是秒连,延迟能省几百毫秒。

正解0-RTT 只对“会话恢复”生效:客户端保存了上次的 TLS 票据,重连时直接携带加密参数省去握手。首次连接仍然要 1 个 RTT。而且 0-RTT 存在重放攻击风险,服务端往往限制其幂等性。比喻:老客户报会员号直接进门,新客户第一次还是得登记办卡。

为何常见:"0-RTT"这个数字太抓眼球,断章取义时容易忽略前提条件,让人误以为所有连接都是零握手。

面试题

Q1. HTTP/1.1 在一条 keep-alive 连接上同一时刻只能处理一个请求,这种“前一个请求挡着后一个”的排队现象叫做什么?

单选题 · easy

  • A.拥塞控制
  • B.队头阻塞← 正确答案
  • C.慢启动
  • D.粘包

答案:B。队头阻塞指前序请求未完成时后续请求必须等待的现象,像单车道上被前车挡住。拥塞控制是网络层避免过载的机制,慢启动是 TCP 的带宽探测算法,粘包是数据流边界问题,均与排队现象无关。

Q2. HTTP/2 相比 HTTP/1.1 最关键的性能改进是什么?

单选题 · easy

  • A.头部压缩
  • B.多路复用← 正确答案
  • C.服务端推送
  • D.二进制帧

答案:B。多路复用让多条请求流在同一条连接上交错传输,消除了 HTTP 层的请求排队,这是本质改进。二进制分帧只是实现多路复用的手段,头部压缩是辅助优化,服务端推送更是锦上添花。

Q3. HTTP/2 依然存在队头阻塞,其根因在哪个层面?

单选题 · mid

  • A.应用层的请求排队
  • B.TCP 层的按序交付← 正确答案
  • C.HPACK 动态表
  • D.流优先级

答案:B。TCP 保证字节按序到达,一个数据段丢失后,后续已到达的数据必须等重传,从而阻塞所有流。应用层的请求排队已被多路复用解决,HPACK 和流优先级与阻塞无关。

Q4. QUIC 以哪个传输层协议作为基础?

单选题 · mid

  • A.TCP
  • B.TLS
  • C.UDP← 正确答案
  • D.SCTP

答案:C。QUIC 基于 UDP,在用户态自行实现可靠传输、拥塞控制、加密与流管理,相当于无人机自带飞行系统。TLS 只是其加密层而非传输层,SCTP 虽支持多流但未在 Web 生态普及。

Q5. 相比 HTTP/2,HTTP/3 新增的能力包括哪些?

多选题 · mid

  • A.0-RTT 快速握手← 正确答案
  • B.连接迁移← 正确答案
  • C.服务端推送
  • D.独立流消除 TCP 队头阻塞← 正确答案

答案:ABD。QUIC 支持会话恢复下的 0-RTT 握手、基于 Connection ID 的连接迁移,以及每个流独立确认重传,从而消除 TCP 层队头阻塞。服务端推送是 HTTP/2 就已具备的功能。

Q6. HTTP/2 的头部压缩算法是哪一个?

单选题 · easy

  • A.gzip
  • B.HPACK← 正确答案
  • C.QPACK
  • D.Brotli

答案:B。HPACK 用静态表加动态表加 Huffman 编码压缩头部。QPACK 是 HTTP/3 针对乱序流设计的升级版,gzip 和 Brotli 是通用实体压缩算法,与头部压缩无关。

Q7. 关于 HTTP/2 与域名分片(domain sharding)的关系,下列说法正确的是?

多选题 · hard

  • A.域名分片在 HTTP/2 下应继续加强
  • B.分片会破坏 HPACK 动态表的命中率← 正确答案
  • C.HTTP/2 鼓励把资源收敛到单连接← 正确答案
  • D.分片能彻底消除队头阻塞

答案:BC。HTTP/2 单连接多路复用后,域名分片增加握手与慢启动成本,并让动态表跨连接无法复用,降低压缩率,因此应减少域名、收敛到单连接。A 是把 HTTP/1.1 旧经验套到新协议,D 与 TCP 层队头阻塞的事实矛盾。

Q8. 在丢包率 p 固定时,TCP 连接吞吐量约与下列哪一项成反比?

单选题 · mid

  • A.RTT × √p← 正确答案
  • B.RTT ÷ p
  • C.√RTT × p
  • D.RTT² ÷ p

答案:A。Mathis 公式给出 B ≈ MSS / (RTT × √p)。丢包率越大吞吐下降越快,且吞吐与 RTT 成反比,因此正确项是 RTT 与丢包率平方根的乘积。

Q9. QUIC 使用 Connection ID 而非“IP + 端口”来标识连接,主要目的是什么?

单选题 · hard

  • A.提高加密强度
  • B.支持连接迁移← 正确答案
  • C.减少握手 RTT
  • D.提高拥塞控制精度

答案:B。Connection ID 让连接与网络地址解耦,设备切换 WiFi/4G 导致 IP 变化时连接依然存活,这就是连接迁移。加密强度靠 TLS 1.3,握手提速靠 0-RTT,拥塞控制精度与连接标识方式无关。

Q10. 关于 HTTP/3 的 QPACK 与 HTTP/2 的 HPACK,下列说法正确的有哪些?

多选题 · hard

  • A.QPACK 是为 QUIC 的乱序流设计的← 正确答案
  • B.HPACK 依赖“先到先查”的有序交付← 正确答案
  • C.QPACK 通过单向流同步动态表更新← 正确答案
  • D.两者都没有使用 Huffman 编码

答案:ABC。QUIC 流可乱序到达,动态表不能依赖到达顺序,故 QPACK 用专用单向流同步表更新;HPACK 则依赖 TCP 有序性。两者都使用 Huffman 编码压缩长文本,因此 D 错误。