
背景
先來回憶一下,
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
,直接使用nacos 對應語言的 SDK ,擷取執行個體清單生成agent
,并且使用upstream
監聽服務變化Naocs SDK
reload
nacos-nginx-template 使用
nacos-nginx-template以上的第二種思路實作以Agent的形式讓Nginx實作對Nacos的服務發現。
-
下載下傳二進制包
點選此處下載下傳:
最新穩定版-
配置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" |
-
啟動,即可使用
sh bin/startup.sh
核心代碼
- 擷取
配置的資訊,支援多個config.toml
,調用Nacos Api 拉取執行個體清單upstream
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");