Nginx 不支持 upstream 嵌套,因其作用域限定于 http 级且内部仅允许 server 等指令;可通过两级 proxy_pass 链式转发实现两层轮询:第一层 upstream 转发至中间节点,再由其 proxy_pass 至第二层 upstream。

Nginx 本身不支持原生的“两层 upstream 嵌套”(比如在 upstream 内再定义另一个 upstream 并直接引用),upstream 块不能嵌套定义,也不能在 upstream 内引用其他 upstream 名称作为服务器。但你可以通过“逻辑分层 + 多级 proxy_pass”方式,模拟出两层轮询负载均衡的效果:第一层调度到若干“中间节点”,每个中间节点再转发到第二层真实服务集群。
为什么 upstream 不支持直接嵌套?
Nginx 的 upstream 是一个独立的配置块,作用域为 http 级别,其内部只允许 server、zone、keepalive 等指令,不允许出现另一个 upstream 块或变量引用 upstream 名称。以下写法是非法的:
upstream layer1 {
server 10.0.1.10:80;
upstream layer2 { # ❌ 不允许嵌套 upstream
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
}
实现两层轮询的可行方案:两级 proxy_pass 链式转发
核心思路:用两个独立的 upstream 块分别定义“第一层网关组”和“第二层服务组”,再通过 location 中的 proxy_pass 指向第一层;第一层 Nginx 实例(或同一台 Nginx 的不同 server 块)收到请求后,再 proxy_pass 到第二层 upstream。这样就形成「Client → 第一层 upstream(轮询)→ 第二层 upstream(轮询)」的两级调度链。
若所有逻辑部署在同一台 Nginx 上,可通过 localhost + 不同端口 或 named location 实现内部跳转。
✅ 推荐做法(单机双 upstream + 内部跳转):
- 定义
upstream backend_servers:第二层真实服务(如应用实例) - 定义
upstream gateway_nodes:第一层逻辑网关(可仅为本地不同端口或命名 location) - 用
location /直接 proxy_pass 到第一层 upstream - 用
location @layer2(或监听本地端口)承接第一层转发,并 proxy_pass 到第二层 upstream
✅ 正确配置示例(单机模拟两层轮询):
http {
upstream backend_servers {
least_conn; # 或 round_robin(默认)
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
<pre class="brush:php;toolbar:false;">upstream gateway_nodes {
# 这里不是真实服务器,而是指向本机内部命名 location
server 127.0.0.1:8000; # 可选:用端口区分,或全走 named location
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://gateway_nodes;
proxy_set_header Host $host;
}
}
# 模拟“第一层网关”的 server 块(监听内部端口)
server {
listen 127.0.0.1:8000;
location / {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}}
更实用的生产场景:物理分离的两层 Nginx
实际部署中,两层通常由不同机器/集群承担:
- Layer 1(接入层):公网 Nginx 集群,轮询分发到多个私有网关节点
- Layer 2(应用层):每个网关节点上运行 Nginx,再轮询其后端的若干 App Server
此时配置完全解耦:
▶ Layer 1 Nginx:upstream gateways { server 10.10.1.10; server 10.10.1.11; },proxy_pass http://gateways
▶ Layer 2(每台 gateway):upstream apps { server 172.16.0.100:3000; server 172.16.0.101:3000; },proxy_pass http://apps
这种结构天然支持独立扩缩容、健康检查、权重调整,且符合 Nginx 设计范式。
替代技巧:用 map + split_clients 实现“逻辑分层”(非真正嵌套)
如果只是想按规则把流量先分组、再组内轮询,可用 map 和 split_clients 配合多个 upstream:
- 用
split_clients "$request_id" $backend_group将请求哈希分到 group_a / group_b - 再用
map $backend_group $upstream_name映射到对应 upstream 名(仅限变量名,不能动态解析) - ⚠️ 注意:Nginx 不支持变量作为
proxy_pass的 upstream 名(除非用商业版或 OpenResty 的 lua-resty-upstream)
所以纯开源 Nginx 中,该方式仅适合静态分组,无法实现“组内再轮询”的动态效果,实用性有限。
不复杂但容易忽略:真正的两层轮询靠的是架构分层,而不是配置嵌套。用好 upstream + proxy_pass 链路,比强行“嵌套”更稳定、更易维护。











