在 Nginx 上启用 HTTP/2 之后,单个 TCP 连接可以同时承载多个请求流,这大幅降低了连接建立开销,但也带来一个新的问题:每个 HTTP/2 连接需要维护独立的内存池来存放帧数据、流状态和压缩上下文。这个内存池的大小,也就是我们常说的连接池大小,直接决定了单连接在高并发流下是否会频繁扩容、是否会产生内存碎片,以及单个 worker 进程能稳定承载多少连接。很多配置文档会提到 http2_pool_size 这个参数,但在 Nginx 官方稳定版的 ngx_http_v2_module 中并没有该指令。实际它通常是对 HTTP/2 连接内存池的一种概括性描述,真正控制连接池占用的是 http2_max_concurrent_streams、http2_chunk_size、http2_body_preread_size 等指令的协同作用。下面先从连接池的内存模型说起。

HTTP/2 连接池的内存模型
Nginx 采用多进程模型,每个 worker 进程独立处理连接。HTTP/2 连接建立后,worker 会为之创建独立的连接结构体,并初始化一个内存池。这个池不是一次性固定分配的,而是按需增长:先分配小块,不够时再向操作系统申请大块。所有帧头、流控制窗口、HPACK 解码表、请求体预读缓冲等都从这个池里取。如果连接空闲,池会保持在某个基础水位;如果并发流很多,池会快速膨胀。http2_pool_size 的设想就是给这个池设一个初始容量,减少运行期分配,避免高并发时频繁向系统要内存。
与 HTTP/1.x 相比,差异更加明显。HTTP/1.x 每个请求一个连接,请求结束后连接关闭,内存池随之释放;而 HTTP/2 连接是长连接,多个流交错使用同一连接,池不能随时释放,因此初始大小和增长上限对内存稳定性影响很大。如果初始池过小,第一个帧就会触发扩容,带来额外延迟;如果初始池过大,1000 个空闲连接就可能占用几个 GB 内存,直接拖垮整个节点。
以默认配置为例,Nginx 内存池页面大小通常为 4KB,一个 HTTP/2 连接的基础占用大概在 10KB 到 20KB 左右,包含连接结构体、HPACK 动态表等。但当并发流数量增加到 100 个以上时,单连接占用可能增长到 1MB 甚至更多。因此,所谓连接池大小的调优,本质上就是控制单连接在空闲和满载两种状态下的内存水位。
影响连接池大小的关键配置指令
官方 ngx_http_v2_module 并没有直接暴露 http2_pool_size,实际控制连接池大小的是一组协同工作的指令。首先是 http2_max_concurrent_streams,它限制单个 HTTP/2 连接上同时活跃的流数量,默认 128。每个流都需要独立的接收缓冲、发送缓冲和状态结构,所以该值直接线性影响连接池内存需求。其次是 http2_chunk_size,默认 8192 字节,决定每次读写操作分配的最小缓冲块大小。再次是 http2_body_preread_size,默认 65536 字节,控制请求体预读缓冲。此外,http2_max_header_size 和 http2_max_field_size 限制 HPACK 解码后的头部总大小和单个字段大小,防止异常头部撑爆内存池。
下面给出一段常见的 Nginx 配置示例,展示这些指令是如何组合使用的:
http {
server {
listen 443 ssl http2;
server_name ipipp.com;
http2_max_concurrent_streams 128;
http2_chunk_size 8k;
http2_body_preread_size 64k;
http2_max_header_size 16k;
http2_max_field_size 4k;
}
}
根据上述配置可以做一个粗略的内存估算。假设 http2_max_concurrent_streams 设置为 256,http2_chunk_size 设置为 16k,每个流至少需要一个发送缓冲和一个接收缓冲,理论单流需要 32k,256 个流就是 8MB。再加上请求体预读 64k 和 HPACK 动态表,单连接内存可能超过 8MB。如果 worker 进程同时保持 2000 个活跃连接,理论上需要 16GB 内存,这显然不合理。因此连接池调优绝不是越大越好,而是要根据实际业务负载精确控制。
还需要注意,http2_max_requests 默认值为 1000,它限制单个 HTTP/2 连接上最多允许的请求总数。达到该值后连接会被关闭,强制客户端重新建立连接。这个机制可以防止长连接内存池无限增长,是控制连接池总占用的重要防线。生产环境中不建议将该值调得过大或直接关闭。
调优实战与监控
调优不能凭感觉,必须先从监控数据出发。通过 nginx -T 2>&1 | grep http2 可以查看当前生效的 HTTP/2 指令;用 ss -s 统计 TCP 连接总数;用 ps -o rss= -p <worker_pid> 观察单个 worker 进程的内存占用。当出现 worker_connections are not enough 报错,或者客户端频繁收到 HTTP/2 流重置帧时,就需要检查连接池是否达到了瓶颈。
不同业务场景需要不同的参数组合。高并发短连接 API 场景下,单连接的并发流数量不需要太高,http2_max_concurrent_streams 保持在 64 到 128 即可,http2_chunk_size 使用默认 8k,这样可以降低单连接的内存占用,提高 worker 进程的总连接容量。大文件下载或流媒体场景则需要更大的 http2_chunk_size,可以调整到 16k 甚至 32k,以提升单流吞吐,但应把 http2_max_concurrent_streams 限制在 32 到 64,避免每个连接的内存池过度膨胀。
压测是验证调优效果的有效手段。使用 h2load 工具可以模拟不同连接数和并发流数量:
h2load -n 100000 -c 100 -m 10 https://ipipp.com/
其中 -c 指定并发连接数,-m 指定每个连接的并发流数。测试过程中观察请求延迟和 worker 内存增长曲线。如果内存随连接数线性上升且斜率过大,说明单连接池占用太高,应当降低 http2_max_concurrent_streams 或 http2_chunk_size。反之,如果内存增长平稳但延迟升高,说明连接池大小不足以支撑当前并发,需要适当放宽参数。
如果你的 Nginx 版本或第三方补丁确实提供了 http2_pool_size 指令,建议将初始池设置为 4k 或 8k,并搭配 http2_max_requests 限制单连接生命周期,强制重连释放内存池。同时,监控 /proc/<worker_pid>/status 中的 VmRSS 变化,确保调参后不会出现内存缓慢爬升不回收的情况。连接池大小并不是一个孤立参数,它必须与业务并发模型、机器内存容量和内核 TCP 参数协同配合,才能真正发挥 HTTP/2 多路复用的优势。
Nginxhttp2_pool_size连接池大小修改时间:2026-10-05 18:44:07