HTTP 连接复用机制详解
文章目录
- HTTP 连接复用机制详解
- 为什么需要连接复用?
- 连接复用的实现方式
- HTTP/1.1 的 Keep-Alive
- HTTP/2 多路复用
- HTTP/1.1 的队头阻塞问题
HTTP 连接复用机制详解
HTTP 连接复用是 HTTP/1.1 及更高版本中的核心优化机制,旨在减少 TCP 连接建立和关闭的开销,以显著提升性能。
为什么需要连接复用?
说到这一点,其实就是在聊 HTTP/1.0 不使用连接复用,而是为每一次 HTTP 请求建立一次短连接存在的缺点:
- 三次握手延迟:每次 HTTP 请求增加 1.5 RTT 的时间开销;
- TCP 慢启动:新连接需要逐步提升传输速率,原因在于连接刚刚建立时,客户端和服务端需要相互告知当前可用的滑动窗口大小,初始时滑动窗口采用指数增长的形式不断扩大;
- 资源浪费:高并发时服务器需要维护大量连接。
自 HTTP/1.1 开始引入了连接复用机制,即 HTTP 请求会复用同一个 TCP 连接并发送多个请求。
连接复用的实现方式
HTTP/1.1 的 Keep-Alive
机制
- 客户端请求头携带
Connection: keep-alive
(HTTP/1.1 默认开启); - 服务端响应头携带
Connection: keep-alive
,表示同意复用; - 连接空闲时,不会立即关闭,而是等待后续请求。
示例
GET /page1.html HTTP/1.1
Host: example.com
Connection: keep-alive # 显式声明(可选)HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: text/html
连接真正关闭时的所需条件
- 达到
Keep-Alive: max
的请求数; - 超过
Keep-Alive: timeout
空闲时间; - 显式发送
Connection: close
。
HTTP/2 多路复用
HTTP/2 在传输时使用二进制协议传输数据,这一点已经和初代 HTTP 采用纯文本进行数据传输有了很大的区别。针对连接复用,HTTP/2 进一步引入了多路复用机制,具体来说:
- 在单个 TCP 连接上并行交错多个请求/响应(二进制分帧)「比如客户端同时发送请求 A 和 B,服务器无需按序返回」;
- 彻底解决了 HTTP/1.1 的队头阻塞问题。
HTTP/1.1 的队头阻塞问题
队头阻塞问题指的是,客户端和服务端采用 HTTP/1.1 协议进行通信时,如果请求 1 的响应延迟,那么会阻塞后续请求,即使后续的请求 2 已经准备好。
为什么在 HTTP/1.1 会出现队头阻塞问题?本质原因在于需要复用已经建立的 TCP 连接。需要先明确一点,一个{源 IP, 源 Port, 目标 IP, 目标 Port}
四元组唯一标识一条 TCP 连接,因此如果客户端与服务端通过相同的四元组意图建立一个新的 TCP 连接,连接请求将会被拒绝。此时如果客户端改变一个端口(通过随机分配的方式),就可以建立一个新的 TCP 连接(服务端不需要改变端口,比如 HTTP 服务一直在 80 端口监听)。
由于 HTTP/1.1 采用多路复用,所以如果客户端有新的请求,会复用之前的 TCP 连接,而不是新建一个 TCP 连接,因此如果之前的请求延迟没有得到恢复,新的请求需要在队列中等待,之前的请求得到响应之后新的请求才会发送。