nginx/HTTP upstream 配置解析

用动态数组收集上游服务器配置

nginx 解析 upstream 块时,用 ngx_array_t 连续保存服务器条目;每遇到一条 server 指令便追加一个元素。

release-1.26.3通信与流量核验 2026-10-08
相关概念

工程问题#

配置中的后端数量事先不确定,解析阶段需要持续追加,初始化负载均衡时又需要方便地遍历所有服务器。

实际实现#

ngx_array_push 检查已用数量与容量。若数组紧邻内存池尾部且有空间,就原地增加一个槽;否则分配双倍容量、复制旧元素并更新 elts。

处理流程#

  1. 创建服务器动态数组。
  2. 解析 server 指令并申请尾部槽位。
  3. 容量不足时原地扩展或复制到更大存储。
  4. 初始化条目,供后续上游初始化读取。

源码片段#

固定版本 · 原文摘录
src/core/ngx_array.crelease-1.26.3 · L74–L90
查看原文件
74            /* allocate a new array */7576            new = ngx_palloc(p, 2 * size);77            if (new == NULL) {78                return NULL;79            }8081            ngx_memcpy(new, a->elts, size);82            a->elts = new;83            a->nalloc *= 2;84        }85    }8687    elt = (u_char *) a->elts + a->size * a->nelts;88    a->nelts++;8990    return elt;
ngx_array_push

新存储按现有容量的两倍申请,复制旧数据并替换 elts,再以 size × nelts 计算追加槽位。这里保留容量 nalloc 与元素数量 nelts 的区别,也说明扩容会改变数组元素的存储地址。

片段是数组已满且无法原地扩展的分支,随后返回新元素槽位;原地扩展条件在上方。真实调用者位于 ngx_http_upstream_server。

收益与取舍#

工程分析

带来的收益

  • 连续布局便于按下标遍历。
  • 追加时自动管理容量,无需预先设定最终服务器数。

付出的代价

  • 扩容可能执行线性复制,并改变元素存储地址。
  • 扩容遗留的池内存通常随整个内存池释放。

可比较的选择

链表追加时无需整体搬迁,但逐项分配和指针遍历增加管理成本。

版本与适用范围#

对应配置解析阶段的服务器容器,不是请求分发算法。扩容不总是翻倍;持有元素指针的代码须注意 elts 搬迁。

参考来源#

源码、官方文档与原始论文
01
nginx 1.26.3:upstream 创建数组并追加 server

src/http/ngx_http_upstream.c · ngx_http_upstream; ngx_http_upstream_server

源码release-1.26.3
02
nginx 1.26.3:动态数组追加与扩容

src/core/ngx_array.c · ngx_array_push

源码release-1.26.3

相关实现与比较#

4 个相关案例
8 个匹配案例