You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置NGINX作为API网关从Zookeeper注册中心读取动态服务信息

NGINX 对接 Zookeeper 实现动态服务发现配置方案

原生NGINX不支持直接对接Zookeeper读取服务注册信息,你可以通过以下两种常用方案实现需求,两种方案都兼容你现有配置:

方案一:使用 OpenResty 实现无重启动态发现(推荐生产环境使用)

OpenResty是基于NGINX + LuaJIT的增强发行版,完全兼容原生NGINX的所有配置,你之前写的代理、upstream规则都可以直接复用,通过Lua扩展即可实现Zookeeper服务发现:

  • 第一步:安装OpenResty替换现有NGINX,安装时自带lua-resty-zk(Zookeeper客户端)、lua-resty-balancer(负载均衡)扩展库
  • 第二步:在nginx.conf的http块中添加Lua初始化逻辑,监听Zookeeper的服务注册节点:
http {
    # 你之前的原有配置全部保留
    include api_gateway.conf;
    
    # 初始化Zookeeper连接
    lua_shared_dict zk_services 10m; # 开辟10M内存缓存服务实例列表
    init_by_lua_block {
        local zk = require "resty.zk"
        local zc, err = zk:new({
            hosts = {"localhost:2181"}, -- 对应你的Zookeeper连接地址
            timeout = 10000
        })
        -- 监听Spring Cloud Zookeeper默认注册路径 /services/ 下的服务节点
        local function watch_service(service_name)
            local path = "/services/" .. service_name
            local children, err = zc:get_children(path, watch_service)
            if children then
                local instances = {}
                for _, node in ipairs(children) do
                    local data, err = zc:get(path .. "/" .. node)
                    if data then
                        local ins = require("cjson").decode(data)
                        table.insert(instances, ins.address .. ":" .. ins.port)
                    end
                end
                ngx.shared.zk_services:set(service_name, require("cjson").encode(instances))
            end
        end
        -- 监听你需要的两个服务
        watch_service("user_server")
        watch_service("email_server")
    }

    # 原有server块配置保留,只需要修改location的代理逻辑
    server {
        # 你原有监听端口、域名配置不变
        location /auth {
            set $service_name user_server;
            access_by_lua_block {
                local balancer = require "resty.balancer.least_conn"
                local ins = ngx.shared.zk_services:get(ngx.var.service_name)
                if ins then
                    local instances = require("cjson").decode(ins)
                    local ip_port, err = balancer:new(instances):find()
                    ngx.var.proxy_pass = "http://" .. ip_port
                end
            }
            # 你原有proxy_set_header配置全部保留
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location /email {
            # 同上述逻辑,service_name改为email_server即可
        }
    }
}

这个方案无需重启NGINX,Zookeeper节点变化会实时同步到本地缓存,性能损耗极低。

方案二:定时脚本同步配置(轻量方案,适合小项目使用)

无需替换现有NGINX,通过定时脚本拉取Zookeeper服务信息自动更新upstream配置,优雅重载NGINX即可:

  • 第一步:写同步脚本,以下为Python示例逻辑(需要安装kazoo库操作Zookeeper):
from kazoo.client import KazooClient
import json
import os

ZK_HOST = "localhost:2181"
CONFIG_PATH = "/etc/nginx/api_gateway.conf"
NGINX_TEST_CMD = "nginx -t"
NGINX_RELOAD_CMD = "nginx -s reload"

zk = KazooClient(hosts=ZK_HOST)
zk.start()

def generate_upstream():
    config_content = ""
    # 遍历所有服务
    services = zk.get_children("/services")
    for service in services:
        config_content += f"upstream {service} {{\n  least_conn;\n"
        nodes = zk.get_children(f"/services/{service}")
        for node in nodes:
            data, _ = zk.get(f"/services/{service}/{node}")
            ins = json.loads(data.decode())
            config_content += f"  server {ins['address']}:{ins['port']};\n"
        config_content += "}\n\n"
    return config_content

if __name__ == "__main__":
    new_config = generate_upstream()
    # 读取旧配置对比,有变化才更新
    try:
        with open(CONFIG_PATH, "r") as f:
            old_config = f.read()
    except:
        old_config = ""
    if new_config != old_config:
        with open(CONFIG_PATH, "w") as f:
            f.write(new_config)
        # 校验配置合法再重载
        if os.system(NGINX_TEST_CMD) == 0:
            os.system(NGINX_RELOAD_CMD)
zk.stop()
  • 第二步:配置crontab定时执行脚本,比如每10秒执行一次即可,配置更新后会自动优雅重载NGINX,不会丢失请求。

注意事项

  • Spring Cloud Zookeeper默认服务注册路径为/services/服务名,如果你们自定义了注册路径,对应修改上述方案中的读取路径即可
  • 方案二的执行频率不要低于5秒,避免频繁重载NGINX造成不必要的性能损耗
  • 两种方案都完全兼容你现有已经写好的代理请求头、负载均衡规则配置,不需要修改原有业务逻辑

内容的提问来源于stack exchange,提问作者Dang Nguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:09:02