程云来 / 杭州
返回文章·计算机网络
·约 12 分钟

网络面试(十九):复用 HTTPS 连接为什么更快?

用明确的 RTT 预算比较新建、复用、会话恢复和 0-RTT,追踪 TLS 票据与 PSK,再区分 SNI、ALPN 和 HTTP 目标名字。


“第二次访问更快”,省的是哪一步?

客户端已经访问过 shop.example.com,再请求订单详情。可能直接使用 HTTP 缓存,可能在同一条连接上发请求,也可能连接已经关闭、但保留了 TLS 恢复材料。

这三种情况都叫“第二次访问”,但省下的工作不同。连接复用使用已有通道;会话恢复在新连接上利用先前建立的认证与密钥材料;响应缓存则可能连请求都不需要。

本章讨论 TLS over TCP 的成本。时间、票据和报文流程均为教学设定,不声称测量了浏览器、真实网站或早期数据重放。

先把三种“保留”分开

保留的东西下次怎样使用是否必然新建 TCP/TLS
HTTP 已存响应按第 16 章的匹配与新鲜度规则提供内容本地直接复用时无需本资源请求
已建立且可用的连接在已有 TCP/TLS 通道上发新请求不需要重新建立这条通道
TLS 会话恢复材料在新连接握手中提出恢复仍需新连接,不能复活已关闭的 TCP

HTTP/1.1 通常默认使用持久连接,不要求每次额外发送 Connection: keep-alive 才能复用;但必须正确处理消息边界、完整读取响应等规则。响应要求关闭、远端空闲超时或网络故障,都可能使连接不再可用。RFC 9112:持久连接

HTTP 的持久连接,不等于 TCP Keepalive 探测。前者允许多个请求共享通道,后者按配置检查空闲连接的对端存活,不能证明订单业务正常。连接池检查与实际发送之间仍可能发生关闭,重试要遵守第 14 章的业务契约。

复用也有范围限制:协议、证书、目标身份、代理配置与客户端隔离策略都会影响哪些请求能共用连接,不能把“两个域名指向同一 IP”当作通用复用许可。HTTP/2、HTTP/3 的多路复用和连接规则到下一章讨论。

一个可手算的 RTT 预算

设 RTT 为 R=80ms,DNS 已完成,响应足够小,忽略计算、排队、传输量、丢包与网络变化;不用 TCP Fast Open、TLS False Start 等额外优化,也没有握手重试。HTTP 一轮计到收到首字节,不计正文下载和页面渲染。

本节路径TCP 等待TLS 的额外等待请求至首字节理想合计
新建 TCP + TLS 1.2 完整握手1R2R1R4R=320ms
新建 TCP + TLS 1.3 完整握手1R1R1R3R=240ms
新建 TCP + TLS 1.3 恢复,不发早期数据1R1R1R3R=240ms
复用已有可用 TLS 连接001R1R=80ms
新建 TCP + TLS 1.3 早期请求被接受1R请求与握手重叠,不额外等一轮1R理想 2R=160ms

第五行的请求与 ClientHello 一起进入客户端首批 TLS 消息,服务器能按规则接受并响应,才得到这个预算。0-RTT 描述发送早期数据前不等待服务器的 TLS 回复,不是响应零耗时,也不替 TCP over TLS 路径省掉 TCP 建连。

表中 TLS 1.3 恢复与完整握手的轮次数相同,这并不表示恢复没价值:它可以省下证书链传输与验证、部分认证计算等工作。实际收益取决于实现和负载,不能只看 RTT,也不能给一个固定提升倍数。

这些数字是受前提约束的推导,不是性能测试结果。早期数据被拒绝、HelloRetryRequest、响应大、网络拥塞等都会改变等待;真实页面还有 DNS 与资源依赖,不能用本表直接预测“页面多久打开”。

动手比较五条联网路径

先保持 R=80ms,比较完整握手、恢复与复用。再改变RTT,检查早期请求被接受时省掉的究竟是哪一轮;这些预算不代表创建订单可以安全早期执行。

第二次访问,究竟省了哪段等待?

DNS已完成,需要获取响应。各路径使用同一个RTT,观察建连、TLS与请求等待。

TCP等待
1R = 80 ms
TLS额外等待
1R = 80 ms
请求至首字节
1R = 80 ms

教学预算至小响应首字节,不计DNS、正文下载、渲染、计算、排队、丢包及握手重试。没有TCP Fast Open/TLS False Start;不模拟早期拒绝后的重试。HTTP缓存直接复用可无需本资源请求,不在这五条联网路径内。非性能测量或0-RTT部署建议。

TLS 1.3 恢复:票据不是旧连接

一次已认证的 TLS 1.3 连接中,服务器可以发送 NewSessionTicket。客户端保存票据以及相关恢复材料;恢复 PSK(预共享密钥)按协议从这次连接的秘密材料派生。

下一次新建 TCP 后,客户端在 ClientHello 中提出票据对应的 PSK 身份,并给出 binder,证明它持有相应秘密且把证明关联到此次 ClientHello。票据可以是服务器状态的索引,也可以采用封装状态的实现;客户端不能把它当作任意可解释的登录资料。

下面是恢复 PSK + 新的临时密钥交换,不发 0-RTT 的简化路径:

正在绘制图表…
查看 Mermaid 源码
sequenceDiagram
    participant A as 客户端 A
    participant S as shop 服务器 S
    Note over A,S: 首条 TLS 连接已完成认证
    S-->>A: NewSessionTicket
    Note over A: 保存票据与相关恢复材料
    Note over A,S: 旧连接关闭;新 TCP 已建立
    A->>S: ClientHello:票据身份、binder、key_share
    Note over S: 检查恢复条件,验证 binder,选择 PSK
    S-->>A: ServerHello:选择 PSK,提供 key_share
    Note over A,S: 结合 PSK 与新交换派生握手密钥
    S-->>A: 加密的扩展与服务器 Finished
    Note over A: 验证 Finished,派生相应应用密钥
    A->>S: 客户端 Finished + 受保护的 HTTP 请求
    S-->>A: 受保护的 HTTP 响应

Mermaid 大图

可滚动查看图表,点击缩放比例可恢复 100%。按 Esc 关闭。

服务器可以拒绝恢复,例如票据过期、密钥轮换、策略或参数不兼容。客户端要能退回适用的完整握手,不能把恢复成功当成必然。TLS 1.3 也有纯 PSK 模式;本图限定带新交换的模式,不把每次恢复都描述成完全相同的密钥路径。RFC 9846:恢复与 PSK

成功的 PSK 恢复通常不重新发送服务器证书和证书签名,但不等于“没有认证”:它依赖先前建立的可信关系与正确绑定的恢复材料。客户端仍要管理目标身份、寿命和适用参数,不可拿某站点的材料去无条件认证其他站点。

每次新握手也不是原样重复使用上一条连接的所有应用密钥。派生过程与本次握手相关;票据、PSK、当前流量密钥分别有不同用途。TLS 票据不等于 Cookie,也不等于 HTTP 登录 Session;它不能替订单接口确认用户和订单权限。

0-RTT:加密了,为什么还能重放?

拥有允许早期数据的恢复材料时,客户端可以在收到本次服务器握手回复前发送受保护的应用数据。服务器可以接受,也可以拒绝;不是所有票据、客户端或部署都支持。

早期数据缺少普通握手应用数据的同等保证,包括跨连接防重放,以及与新临时交换相关的前向安全保证。攻击者未必需要解密,只需让同一份受保护请求在另一次可接受的上下文中再次出现,业务就可能再次执行。RFC 9846:0-RTT 与防重放

设早期数据是“创建订单”,第一次生成 O204,再次接受可能生成 O205。TLS 密文完整性校验能说明数据未被随意修改,不能因此推出业务只执行了一次。

请求意图早期数据需要判断什么不能只靠什么保证
获取公开且允许重复访问的指南重放、访问日志与资源成本是否可接受仅看方法名 GET
创建、支付或消耗一次性凭据重复与顺序变化是否产生业务效果“内容已经加密”
使用同一业务请求键重试去重范围、原子性、保留期及各实例一致性仅有一个名为 idempotency 的字段

安全或幂等的方法属性不是所有早期数据风险的完整判据。即便预期资源状态不变,重复访问的成本、响应差异、顺序与访问上下文也需评估。业务去重也不能消除早期数据全部安全限制。

服务端可拒绝 TLS 早期数据,或在适用位置延迟处理。HTTP 的 425 Too Early 表示服务器不愿承担可能重放的处理风险;支持该机制的客户端按规则重试时,不能再次把这次重试放进早期数据。RFC 8470:425 与重试

代理还可能通过 Early-Data 字段传递上一跳的早期数据信息。源站只等待自己这条连接握手完成,不能抹掉上一跳已经可能重放的事实;多实例需要一致处理策略。对本例创建订单,不应为了省一轮等待就未经分析启用早期执行。

SNI 与 ALPN:先告诉谁、再决定说什么

一台服务器的 443 端口可以承载多个站点和协议。TLS 握手发生在 HTTP 请求解析之前,因此仅依赖之后的 Host 选择最初服务器证书,时序就太晚了。

SNI(服务器名称指示)在 ClientHello 中提供目标服务器名字,帮助选择站点与证书。它是客户端提供的路由线索,不是客户端身份,也不能替代客户端检查证书与目标名字是否匹配。RFC 6066:SNI

ALPN(应用层协议协商)表达本连接将使用的应用协议。客户端可以提出 h2、http/1.1,服务器从双方支持的协议中选择。TLS 1.3 的服务器 ALPN 选择放在 EncryptedExtensions 中,不能照搬 TLS 1.2 文档里的 ServerHello 位置。RFC 7301:ALPN、RFC 9846:扩展响应

名字或机制作用位置本例回答的问题
SNI 的 shop.example.comTLS 握手想连接哪个 TLS 站点?
ALPN 的 h2TLS 内协商此连接用哪种应用协议?
HTTP Host / :authorityHTTP 请求本次请求的目标 authority 是什么?

ALPN 不会把 HTTP/1.1 文本自动转换成 HTTP/2 帧。选择 h2 后,客户端必须真的使用 HTTP/2 的格式;“TLS 成功”也不等于应用协议已经正确使用。协议是否兼容,还会影响恢复与早期数据的适用条件。

普通 ClientHello 中的 SNI 往往可被链路观察。ECH(加密 ClientHello)有专门机制保护内部 ClientHello 的相关信息,但需要相应配置与协商;TLS 1.3 本身不保证每个部署都隐藏目标名字,ECH 也不会让 IP 和流量特征全部消失。RFC 9849:ECH

优化时,怎样定位真正省下的成本?

先判断这次有没有请求:若 HTTP 响应直接来自缓存,连接成本可能根本没发生。再确认是否新建 TCP、是否完整 TLS、是否成功恢复、是否接受早期数据,以及协商出的 ALPN。TLS 版本相同不代表这些路径相同。

现有第 18 章实验只打印 TLS 版本并验证身份,没有记录恢复标志、票据、ALPN 或抓包时序,不能用它证明本章的优化发生了。后面的排障章会把 DNS、连接、TLS 与 HTTP 等待放进实际观察链。

连接复用通常是先减少重复建连,再考虑恢复与早期数据的成本。仍要检查资源上限、空闲关闭和业务重试,不能靠无限保留连接保证可用。具体配置来自业务目标与测量,不由“长连接一定更快”这句口诀决定。

30—60 秒参考回答

复用已有 HTTPS 连接,可以省掉新的 TCP 与 TLS 建立;TLS 会话恢复则仍是新连接,只利用以前的认证和恢复材料。TLS 1.3 不发早期数据时,恢复通常仍需 1 RTT,但能减少证书与计算成本。0-RTT 让请求与握手重叠,不是响应零耗时,也不保证防重放;创建订单需要评估业务去重和所有实例的处理规则。SNI 指示 TLS 站点,ALPN 协商应用协议,HTTP Host 或 authority 表达具体请求目标,它们不互相替代。性能比较必须区分缓存、新连接、恢复、复用与早期数据路径。

四个追问及解析

1. TLS 会话恢复是否意味着旧 TCP 连接又打开了?

不是。旧 TCP 关闭后不能直接复活;恢复使用新的传输连接和握手,只复用允许使用的认证与密钥材料。已有连接继续发请求,才属于连接复用。

2. TLS 1.3 完整握手与恢复都 1 RTT,恢复还有用吗?

有可能。网络等待轮次相同,证书传输、验证和部分认证计算仍可能不同。需要结合 CPU、字节量与负载测量,不应只用“少一轮 RTT”解释所有收益。

3. 给 POST 加了请求键,就一定可以用 0-RTT 吗?

不一定。键的原子去重与寿命要足够,处理还要覆盖所有实例及可能的顺序变化;此外早期数据的保密和防重放边界仍存在。应评估具体接口,不从某个字段名推导通用许可。

4. 设置 SNI 为正确域名,就可以跳过证书名字验证吗?

不能。SNI 是客户端告诉服务器想去哪里;证书身份验证是客户端判断对方是否有资格代表该目标。第 18 章的信任链和名字检查仍不可省略。

两个易错辨析

“TLS 1.3 自动让每个请求都变成 0-RTT。” 首次连接没有本次恢复所需材料;后续票据也要允许,客户端与服务器都需支持并接受,业务还要评估早期执行。协议版本只是前提之一。

“有 Keepalive,就不会再超时或断线。” 持久连接允许复用,TCP 探测按配置检查存活;二者都不能阻止网络变化,也不证明业务正在响应。空闲关闭和结果未知仍需按层判断。

下一章比较 HTTP/1.1、HTTP/2、HTTP/3 的并发与阻塞,看看即便省掉握手,多个请求为何仍可能互相等待。