先來回憶一下, 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
。git
在微服務架構下,咱們的服務均已經註冊到 註冊中心 例如(nacos/eureka),註冊中心已經維護全部服務實例的 IP:PORT
列表 ,爲什麼不直接經過 nginx 來獲取註冊中心中的IP:PORT
列表自動配置 upstream
和熱更新。如上思路實現有以下:
github
nginx-lua-module
模塊編寫 lua
腳本, 調用註冊中心的 Http API
來獲取實例列表 配置 upstream
,定時 reload
熱更新 JAVA/Golang
編寫單獨的agent
,直接使用nacos 對應語言的 SDK ,獲取實例列表生成 upstream
,而且使用 Naocs SDK
監聽服務變化 reload
nacos-nginx-template 以上的第二種思路實現以Agent的形式讓Nginx實現對Nacos的服務發現。架構
點擊此處下載:最新穩定版app
配置文件使用TOML進行配置負載均衡
nginx_cmd = "/usr/sbin/nginx" #nginx命令的全路徑
nacos_addr = "172.16.0.100:8848" #nacos 服務地址
reload_interval = 1000 # 刷新間隔
[discover_config1]
nginx_config = "/etc/nginx/nginx.conf" #nginx config 配置
nginx_upstream = "upsteam1" #upstream 名稱
nacos_service_name = "service1" #nacos 服務名稱
[discover_config2]
nginx_config = "/etc/nginx/nginx.conf"
nginx_upstream = "upsteam2"
nacos_service_name = "service2"複製代碼
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;
}複製代碼
Runtime.getRuntime().exec("nginx -s reload");複製代碼