什么是 HTTP 长连接(Keep-Alive)?
HTTP 长连接(HTTP Persistent Connection),通常被称为 HTTP Keep-Alive,是一种允许在单个 TCP 连接上发送和接收多个 HTTP 请求/响应的机制。
简单来说,它的核心思想是:“一次建立,多次复用”。
以下是关于 HTTP 长连接的详细解析:
1. 为什么需要长连接?(背景与短连接的痛点)
在早期的 HTTP/1.0 时代,默认使用的是短连接。其流程如下:
- 客户端发起 TCP 连接(三次握手)。
- 客户端发送 HTTP 请求。
- 服务端返回 HTTP 响应。
- 断开 TCP 连接(四次挥手)。
短连接的问题:
如果一个网页包含很多资源(HTML, CSS, JS, 图片等),每加载一个资源都要重新建立和断开一次 TCP 连接。
- 耗时: TCP 三次握手和四次挥手需要时间,增加了网络延迟(RTT)。
- 耗资源: 频繁创建和销毁 socket 会消耗服务器的 CPU 和内存资源。
- 慢启动: TCP 连接建立初期有“慢启动”机制,速度较慢,频繁新建连接无法利用 TCP 的全速传输能力。
2. 长连接(Keep-Alive)的工作原理
Keep-Alive 旨在解决上述问题。开启长连接后,流程变为:
- 客户端发起 TCP 连接(三次握手)。
- 客户端发送请求 A。
- 服务端返回响应 A。
- 保持连接不断开。
- 客户端继续在该连接上发送请求 B。
- 服务端返回响应 B。
- ...(重复多次)...
- 直到达到超时时间或最大请求数,连接才关闭。
形象的比喻:
- 短连接: 你给客服打电话,问一个问题,挂断;再拨打,问第二个问题,挂断。
- 长连接: 你给客服打电话,问一个问题,别挂,接着问第二个问题,直到问完才挂断。
3. 如何开启与关闭
- HTTP/1.0: 默认是关闭的。如果需要开启,客户端必须在请求头中显式添加:plaintext
Connection: keep-alive - HTTP/1.1 及以后: 默认开启。除非显式在请求头中声明关闭:plaintext
Connection: close
4. 关键参数(Keep-Alive Header)
虽然 HTTP/1.1 默认开启,但服务器可以通过响应头告知客户端保持连接的策略。常见的参数包括:
timeout: 连接空闲多久后自动关闭(单位:秒)。max: 在连接关闭前,最多允许发送多少个请求。
例如:Keep-Alive: timeout=5, max=100 表示连接空闲 5 秒或者处理了 100 个请求后就会关闭。
5. 优缺点分析
优点:
- 降低延迟: 减少了 TCP 握手的次数,后续请求响应更快。
- 节省 CPU: 减少了操作系统频繁建立和销毁 TCP 连接的开销。
- 网络拥塞控制优化: 避免了每次请求都经历 TCP 的慢启动阶段,连接“热”起来后传输速度更快。
缺点:
- 服务器资源占用: 如果连接一直保持打开但没有数据传输(空闲状态),会占用服务器的内存和连接数(File Descriptors)。对于高并发服务器,过多的空闲连接可能导致新连接无法进入。
- 解决方案: 合理设置
Keep-Alive Timeout时间(如 Nginx 中通常设为 65s 或更短)。
- 解决方案: 合理设置
- 队头阻塞(Head-of-Line Blocking): 在 HTTP/1.1 中,虽然连接复用了,但请求是串行的。如果请求 A 处理很慢,请求 B 必须等待 A 完成才能发送/接收。
- 解决方案: HTTP/2 引入了多路复用(Multiplexing)解决了这个问题。
6. 容易混淆的概念:TCP Keepalive vs HTTP Keep-Alive
虽然名字很像,但它们是不同层面的东西:
- HTTP Keep-Alive (应用层): 为了复用连接,发送多个 HTTP 请求,避免频繁开关连接。
- TCP Keepalive (传输层): 是一种心跳检测机制。当连接长时间没有数据传输时,TCP 层发送空数据包来探测对方是否还在线,用于检测死连接(如网线被拔掉)。
总结
| 特性 | 短连接 (Short Connection) | 长连接 (Keep-Alive) |
|---|---|---|
| 连接生命周期 | 1 个请求 | 多个请求 |
| TCP 握手开销 | 高(每次请求都要) | 低(仅第一次需要) |
| 服务器压力 | CPU 压力大(频繁建连) | 内存压力大(维持连接) |
| 适用场景 | 极低频次的请求 | 网页加载(含多图/JS/CSS)、API 频繁调用 |
| HTTP 版本 | HTTP/1.0 默认 | HTTP/1.1 默认 |
右滑查看面试常问