天天看點

通過Nacos讓Nginx擁有服務發現能力

通過Nacos讓Nginx擁有服務發現能力

背景

先來回憶一下,

nginx

如何配置多個執行個體的負載均衡,配置如下:

upstream serverList {
    server 172.17.0.111:9999;
    server 172.17.0.110:9999;
}
 
server {
   location / {
       proxy_pass  http://serverList;
    }
}           

當我們的服務執行個體變化時,要手動修改

nginx.conf

然後

nginx -s reload

在微服務架構下,我們的服務均已經注冊到 注冊中心 例如(nacos/eureka),注冊中心已經維護所有服務執行個體的

IP:PORT

清單 ,為何不直接通過 nginx 來擷取注冊中心中的

IP:PORT

清單自動配置

upstream

和熱更新。

如上思路實作有如下:

  • 使用

    nginx-lua-module

    子產品編寫

    lua

    腳本, 調用注冊中心的

    Http API

    來擷取執行個體清單 配置

    upstream

    ,定時

    reload

    熱更新
  • JAVA/Golang

    編寫單獨的

    agent

    ,直接使用nacos 對應語言的 SDK ,擷取執行個體清單生成

    upstream

    ,并且使用

    Naocs SDK

    監聽服務變化

    reload

nacos-nginx-template 使用

nacos-nginx-template

以上的第二種思路實作以Agent的形式讓Nginx實作對Nacos的服務發現。

  1. 下載下傳二進制包

點選此處下載下傳:

最新穩定版
  1. 配置config.toml

配置檔案使用

TOML

進行配置

nginx_cmd = "/usr/sbin/nginx"
nacos_addr = "172.16.0.100:8848,172.16.0.101:8848,172.16.0.102:8848"
reload_interval = 1000

[discover_config1]
nginx_config = "/etc/nginx/nginx.conf"
nginx_upstream = "upsteam1"
nacos_service_name = "service1"

[discover_config2]
nginx_config = "/etc/nginx/nginx.conf"
nginx_upstream = "upsteam2"
nacos_service_name = "service2"           
參數 描述 例子
nginx_cmd nginx指令的全路徑 "/usr/sbin/nginx"
nacos_addr nacos的位址 "172.16.0.100:8848,172.16.0.101:8848,172.16.0.102:8848"
reload_interval nginx reload指令執行間隔時間(ms 預設值1000) 1000
nacos_service_name nacos服務名 "com.nacos.service.impl.NacosService"
nginx_config 需要修改nginx配置的路徑 "/etc/nginx/nginx.conf"
nginx_upstream nginx中upstream的名字 "nacos-service"
  1. 啟動,即可使用

sh bin/startup.sh           

核心代碼

  • 擷取

    config.toml

    配置的資訊,支援多個

    upstream

    ,調用Nacos Api 拉取執行個體清單
for (DiscoverConfigBO configBO : list) {
    namingService.subscribe(configBO.getServiceName(),
            event -> {
                List<Instance> instances = namingService
                        .getAllInstances(configBO.getServiceName());
                //更新nginx中的upstream
                refreshUpstream(instances, configBO.getUpstream(), configBO.getConfigPath());
            }
    );
}
           
  • 根據執行個體清單,拼湊

    upstream

private boolean refreshUpstream(List<Instance> instances, String nginxUpstream, String nginxConfigPath) {
        //擷取到upstream 名稱
        Pattern pattern = Pattern.compile(UPSTREAM_REG.replace(PLACEHOLDER, nginxUpstream));
        //擷取到配置檔案内容
        String conf =  FileUtl.readStr(nginxConfigPath);
        //拼接新的upstream
        String newUpstream = UPSTREAM_FOMAT.replace(PLACEHOLDER, nginxUpstream);
        StringBuffer servers = new StringBuffer();
        if (instances.size() > 0) {
            for (Instance instance : instances) {
                //不健康或不可用的跳過
                if (!instance.isHealthy() || !instance.isEnabled()) {
                    continue;
                }
                servers.append(formatSymbol + "    server " + instance.getIp() + ":" + instance.getPort() + ";\n");
            }
        }
        servers.append(formatSymbol);
        newUpstream = newUpstream.replace(PLACEHOLDER_SERVER, servers.toString());
        //替換原有的upstream
        conf = matcher.replaceAll(newUpstream);
        return true;
    }           

-Java 調用nginx reload

Runtime.getRuntime().exec("nginx  -s reload");