跳转至

Keep-Alive 使用场景

99% 的场景都该用 Keep-Alive,关键是配好超时时间和最大请求数


核心概念

  1. 高频请求 — 同一客户端短时间内多次请求同一服务器,Keep-Alive 省掉大量握手开销
  2. 高延迟网络 — 移动端/跨地域场景下,每次握手的延迟代价更高
  3. 资源受限 — 空闲连接太多时反而有害,需要缩短超时或关闭 Keep-Alive
  4. 安全隔离 — 某些敏感场景需要每次请求走独立连接

详解

建议启用 Keep-Alive 的场景

1. 高频请求同一服务器

graph LR
    A[前端页面] -->|请求 30 个资源| B[CDN/源站]
    C[微服务 A] -->|链式调用| D[微服务 B]
    D -->|继续调用| E[微服务 C]

最常见的场景。前端页面加载、微服务间调用、API 连续请求等,几乎没有任何理由关掉 Keep-Alive。

2. 移动端 / 高延迟网络

移动端网络延迟高,每次 TLS 握手可能要 100-300ms:

场景 无 Keep-Alive 有 Keep-Alive
30 次请求 × 150ms 握手 **4.5 秒**光握手 **150ms**只握手一次

省了 4 秒多,体感天差地别。

3. 短间隔批量请求

爬虫批量抓取、定时轮询、WebSocket 建立前的 HTTP 握手等,1000 个请求:

方案 每个请求耗时 总耗时
无 Keep-Alive 60ms(50ms 握手 + 10ms 传输) 60 秒
有 Keep-Alive 10ms(0ms 握手 + 10ms 传输) 10 秒

4. 内部服务间通信

微服务之间的 RPC 调用、数据库连接、Redis 连接等,连接池 + Keep-Alive 是标配。

不建议使用 Keep-Alive 的场景

1. 一次性 / 低频请求

偶尔请求一次,几分钟甚至几小时才来一次:

用户一天登录一次,查一次个人信息就不用了
每天凌晨跑一次定时任务,拉一次数据

Keep-Alive 连接空等着白白占内存。不过现代服务器默认超时 5-15 秒会自动释放,实际影响不大。

2. 连接数是瓶颈时

极端场景下,空闲连接太多反而有害:

10000 个空闲 Keep-Alive 连接 × 10KB = 100MB 内存
文件描述符吃掉 10000 个
新请求反而因为资源不够被拒绝

这时候应该**缩短超时时间**,而不是关掉 Keep-Alive:

keepalive_timeout 5;        # 空闲 5 秒就释放
keepalive_requests 1000;    # 单连接最多处理 1000 个请求就回收

3. 安全隔离

银行转账等敏感操作,每次操作用全新连接,确保上一次的上下文不会残留。多租户 SaaS 也要隔离,A 租户的连接不能被 B 租户复用。

4. 大文件传输

下载 2GB 文件,一个连接独占十几分钟。如果连接池只有 10 个,其他请求全部排队等这个下载完。

# 正确做法:下载用独立连接,业务用连接池
download_session = requests.Session()
download_session.headers['Connection'] = 'close'  # 下载完就关

api_session = requests.Session()  # 默认 Keep-Alive

决策参考

条件 Keep-Alive Connection: close
同一客户端高频请求 ✅
请求间隔 < Keep-Alive 超时 ✅
移动端 / 高延迟网络 ✅
微服务内部通信 ✅
偶尔请求一次 无所谓(让服务器默认超时就好)
单次大文件下载 ✅
连接数已达上限 缩短超时
安全隔离要求 ✅
公共 API 防滥用 缩短超时 + 限制次数

生产环境配置建议

Nginx

# 后端代理(微服务间)—— 激进复用
proxy_http_version 1.1;
proxy_set_header Connection "";
keepalive_timeout 60s;
keepalive_requests 1000;

# 面向公网 —— 适度保守
keepalive_timeout 10s;
keepalive_requests 100;

Java Tomcat

<Connector keepAliveTimeout="20000"
           maxKeepAliveRequests="200" />

常见陷阱

公共 API 忘记限制连接数

不限制 Keep-Alive 超时和最大请求数,一个恶意客户端可以长期霸占连接。应该设置 keepalive_timeout 和 keepalive_requests 上限。

大文件和小请求混用同一连接池

大文件传输独占连接时间过长,导致小请求排队。应该分离:大文件用独立连接(Connection: close),小请求用连接池复用。


练习题

如果你的 API 网关同时服务移动端和 Web 端,Keep-Alive 配置应该怎么考虑?
答案

移动端延迟高,Keep-Alive 收益大,超时可以设长一些(如 30 秒)。Web 端延迟低但并发高,超时可以短一些(如 10 秒)。可以按来源区分配置,或者取一个折中值(10-15 秒),配合 keepalive_requests 限制单连接最大请求数。

为什么说 Keep-Alive 的 '99% 场景都该用'?那 1% 是什么?
答案

那 1% 主要是:(1)安全隔离要求极高的场景(如金融交易),每次连接必须独立;(2)连接数是硬瓶颈的极端高并发场景;(3)超大文件传输会独占连接。除此之外,默认开启是正确选择。