nginx反向代理缓冲区管理是以chain为单位、基于upstream生命周期的状态机调度机制,核心围绕buffer/bufs链表、busy/free链表及output_filter构建,实现数据分段、内存复用与异步边界控制。

要理解 Nginx 源码中反向代理缓冲区(Buffer)的管理逻辑,核心是抓住“数据流分段、内存复用、异步边界”这三个设计意图。它不是简单的读写缓冲,而是一套围绕 upstream 请求/响应生命周期构建的、带状态机的缓冲调度机制。
从 ngx_http_upstream_t 和缓冲区结构体入手
Nginx 反向代理的缓冲行为由 ngx_http_upstream_t 结构体统一控制,其中关键字段包括:
-
buffer:主接收缓冲区(
ngx_buf_t *),用于暂存 upstream 响应体;大小由proxy_buffer_size和proxy_buffers指令共同决定 -
bufs:缓冲区链表(
ngx_chain_t *),由多个ngx_buf_t组成,对应proxy_buffers配置的 buffer 数量和大小 -
busy 和 free:两个
ngx_chain_t *链表,分别管理已发送但尚未被下游确认释放的缓冲区、以及可复用的空闲缓冲区 -
output_filter:实际触发缓冲区向下写入的回调,最终调用
ngx_http_upstream_process_upstream
关注三个关键缓冲阶段的流转逻辑
缓冲区在 upstream 响应处理中经历三个典型阶段,每阶段对应不同内存操作策略:
-
接收阶段(upstream → buffer):在
ngx_http_upstream_process_header后,进入ngx_http_upstream_process_body;每次recv()到数据后,尝试填满当前buffer或复用free链表中的ngx_buf_t,填满即挂入bufs链表尾部 -
转发阶段(buffer → client):通过
ngx_http_upstream_send_response触发,将bufs中就绪的缓冲区组成 chain 交给ngx_http_output_filter;若下游 socket 写阻塞,则当前 chain 节点保留在busy链表,等待下次可写事件再重试 -
回收阶段(client 确认后):当
ngx_http_writer检测到busy中某缓冲区已完全写出且被下游 ACK,就将其移回free链表,供后续 upstream 响应复用
重点跟踪几个核心函数调用路径
不必通读全部文件,聚焦以下函数即可串起主线:
-
src/http/ngx_http_upstream.c中的ngx_http_upstream_init_request→ 初始化buffer和bufs链表 -
ngx_http_upstream_process_body→ 主循环读取 upstream body 并填充缓冲区 -
ngx_http_upstream_send_response→ 构建输出 chain 并调用ngx_http_output_filter -
src/http/ngx_http_write_filter_module.c中的ngx_http_write_filter→ 实际执行写入,并更新busy/free状态
注意配置与缓冲行为的映射关系
源码逻辑会因配置项产生显著差异,阅读时需同步对照:
-
proxy_buffering off:跳过bufs链表,直接使用单个buffer边收边转,busy/free机制退化为简单指针切换 -
proxy_buffer_size 4k:决定 header 缓冲区大小,影响buffer的初始分配,也参与 response header 解析边界判断 -
proxy_max_temp_file_size 1024m:当内存缓冲区满且开启磁盘缓存时,触发ngx_http_upstream_cache_temp_file将数据刷入临时文件,此时缓冲链表会混入 file buf 类型节点
不复杂但容易忽略的是:Nginx 的 buffer 管理始终以 chain 为单位调度,而非单个 buf;所有链表操作都保证无锁(依赖事件循环单线程),且每个 ngx_buf_t 的 pos/last 字段精确标记有效数据边界——这才是理解“为什么有时看到 buf 显示 empty 却仍挂在 busy 上”的关键。











