Nginx 动态发现方案与实践

作者 : 开心源码 本文共4715个字,预计阅读时间需要12分钟 发布时间: 2022-05-12 共178人阅读

Nginx 动态发现方案与实践

一、背景

很多公司都有做动态调度系统,有些是基于 mesos+docker,有些采用了 google 的 K8s,或者者是自研的系统,这些系统有一个显著的特征就是服务实例的ip会频繁更换。这种容器化的部署方式和传统的服务部署形式不一样,原有的服务都是部署在某些物理机或者者云主机上,这些物理机或者者云主机的 ip 地址不会轻易更换,这样我们配置 nginx 做流量转发的时候即可以直接写ip。但是切换到这些容器化的系统后,服务的实例重启频繁,每一次重启后实例的 ip 就会发生变化,这样我们再用手动配置、变更后台 ip 的形式来做 nginx 的流量转发就基本上不可行了。这时我们需要想办法让发布后的实例ip自动升级到 nginx 的配置中去,并且能够让其自动生效。本板块正是基于前面的应用场景,用于处理后台实例 ip 频繁变化,无法将升级实时同步至 nginx 的配置中的问题。

二、板块架构

前期通过调研发现,有些公司采用了 etcd/consul+nginx 第三方板块(nginx-upsync-module)的方式来实现nginx零重启升级upstream的操作。我们内部并没有采用 etcd 或者者 consul 来存储后台实例配置,而是广泛采用了zk服务来保存后台的配置。大部分业务都会将实例ip注册到 zk 中去,所以我们的nginx需要从zk中拉取后台实例ip和端口。我们公司内部也有同学开发了 nginx 连接 zk 的板块,但是该板块是通过每个worker 进程去连接zk,一个 nginx 可能有多个甚至几十个 worker 进程,会造成 zk 的连接数突增,给 zk集群带来很大的压力。后续通过调研发现了 dyups 这个板块,而后通过自己编码实现连接zk,从 zk 中拉取配置,再通过 dyups 板块的接口升级到 upstream 的共享内存,也可以实现零重启升级 nginx 的upstream列表。同时通过自己编码实现和 zk 交互的逻辑,也可以控制在 zk 不可用时执行的逻辑。

在我们的板块有用到 dyups 这个 nginx 板块,dyups 板块是一个能够直接升级正在运行的 nginx 的 upstream 列表而不需要重新 reload nginx 配置的板块。这个板块通过开放一个接口,而后外部通过这个接口发起 post 或者者 get 请求,直接升级或者者获取对应 upstream 的后台列表。更加详细的用法可以浏览网址

https://github.com/yzprofile/ngx_http_dyups_module查看这个板块的 github 详情。但是因为 dyups 板块只能修改 nginx 的共享内存,不能持久化当前的upstream 配置到文件中,所以我们的板块另外一个核心的工作就是持久化 upstream 配置到配置文件中。

三、板块功能

本板块结合了我们公司常见业务的应用场景、日常使用中碰到的问题以及 dyups 的不足之处,主要实现了如下几个功能:

1)获取注册到zk中后台列表,并对获取到的列表数据格式化,保存到相应的 nginx 配置文件中,进行持久化

2)将保存到文件的后台服务器列表通过dyups板块的接口写入到 nginx upstream 板块的共享内存中,动态升级 upstream 里面的后台列表

3)当 zk 故障时,本板块将不再升级 nginx 的共享内存和本地 nginx 配置文件,使 nginx 的 upstream 配置保持在 zk 故障前的状态

4)支持读取多个 zk 集群的多个 zk 节点配置

四、板块工作流程

Nginx 动态发现方案与实践

五、板块的使用

基础依赖:

支持 dyups 板块的 nginx

python 2.6/2.7

1、clone 板块代码到 nginx 机器上

这里我们将板块代码放到/home/work 目录下

cd /home/work 
git clone http://v9.git.n.xiaomi.com/liuliqiu/nginx-upstream-reloader.git

2、执行板块源码目录中依赖安装脚本(nginx-upstream-reloader/install_venv.sh),这个脚本主要用于安装virtualvenv环境和依赖的第三方板块

cd nginx-upstream-reloader 
bash install_venv.sh

3、修改 nginx-upstream-reloader 板块配置文件

venv 环境安装完成后,修改 nginx-upstream-reloader/conf 目录下的 upstream_zk_nodes.conf 配置文件,这个配置文件用于定义后台实例所在的目的 zk 集群和 zk 节点以及对应 nginx upstream 的名字,具体的修改方法分为如下两种情况:

1)多个后台服务注册在一个zk集群,按照如下配置

upstream_zk_nodes.conf 
zk_servers: zk-hadoop-test01:11000,zk-hadoop-test02:11000
zk_nodes:
bonus-api: /web_services/com.miui.bonus.api.resin-web

zk_servers:后台服务注册的 zk 集群地址和端口

zk_nodes:upstream_name:后台服务注册的zk节点路径

当我们启动后,板块会拉取指定zk节点路径下的后台列表信息自动生成 upstream_name.upstream 文件,如上述配置,我们在指定的目录下(这个指定的目录可以在nginx-upstream-reloader/conf/main.conf配置文件的files_output_path选项控制,这里我们将该选项为/home/work/nginx/site-enable)/home/work/nginx/site-enable下会生成一个 bonus-api.upstream 文件,文件的内容会如下:

upstream bonus-api {
server ....;
server ....;
}

2)多个后台服务器注册在不同的 zk 集群

upstream_zk_nodes.conf 
- zk_servers: tjwqstaging.zk.hadoop.srv:11000
zk_nodes:
ocean-helloworld-upstream1: /ocean/services/job.ocean-helloworld-nginx-upstream_service.ocean-helloworld-nginx-upstream_cluster.staging_pdl.oceantest_owt.inf_cop.xiaomi
ocean-helloworld-upstream2: /ocean/services/job.ocean-helloworld-nginx-upstream_service.ocean-helloworld-nginx-upstream_cluster.staging_pdl.oceantest_owt.inf_cop.xiaomi
- zk_servers: tjwqstaging.zk.hadoop.srv:11000
zk_nodes:
ocean-helloworld-upstream3: /ocean/services/job.ocean-helloworld-nginx-upstream_service.ocean-helloworld-nginx-upstream_cluster.staging_pdl.oceantest_owt.inf_cop.xiaomi

zk_servers:后台服务注册的 zk 集群地址和端口

zk_nodes upstream_name:后台服务注册的zk节点路径

有同学跟我反馈为什么要用 yaml 格式的配置文件,而不用json格式的配置文件,json 对格式要求没有yaml 严格,但是 yaml 的配置文件看起层级直观多了。

当我们启动该板块后,板块会拉取指定zk节点路径下的后台列表信息自动生成 upstream_name.upstream文件,如上述配置,板块在/home/work/nginx/site-enable会生成一个 ocean-helloworld-upstream1.upstream、ocean-helloworld-upstream2.upstream、ocean-helloworld-upstream3.upstream三个文件,文件的内容会分别如下:

upstream ocean-helloworld-upstream1 {
server ...;
server ...;
}

upstream ocean-helloworld-upstream2 {
server ...;
server ...;
}

upstream ocean-helloworld-upstream3 {
server ...;
server ...;
}

4、修改 nginx 配置文件

前面已经配置了 nginx-upstream-reloader 板块连接zk节点获取后台配置后,自动生成 upstream 配置文件,所以我们需要在 nginx 中 include 这些 upstream 配置文件在 server 块中才可以使用这些 upstream。目前因为 dyups 板块的限制,需要将 upstream_name 设置为一个变量,而后在 proxy_pass指令中使用这个变量配置转发,具体可以参考下面的配置:

include /home/work/nginx/site-enable/ocean-helloword-upstream1.upstream; 
include /home/work/nginx/site-enable/ocean-helloword-upstream2.upstream;
include /home/work/nginx/site-enable/ocean-helloword-upstream3.upstream;

server {
listen 80;
location /helloworld1 {
set $ups1 ocean-helloword-upstream1;
proxy_pass http://$ups;
}
location /helloworld2 {
set $ups2 ocean-helloword-upstream2;
proxy_pass http://$ups2;
}
location /helloworld3 {
set $ups3 ocean-helloword-upstream3;
proxy_pass http://$ups3;
}
}

5、修改 nginx 配置文件,开启 dyups 接口

这里增加一个单独的 server,监听本地地址的14443端口

server{
listen 127.0.0.1:14443;
server_name _;
location / {
dyups_interface;
}
}

6、启动zk动态发现板块和 nginx

这里需要先执行 nginx-upstream-reloader/start.sh 文件,启动 nginx-upstream-reloader 板块,而后再启动nginx,由于当我们还没有启动 upstream-reloader 板块时,upstream 配置文件还未生成,但我们 nginx 配置文件中已经 include 这些 upstream 配置文件,这时启动 nginx 就会报错

bash nginx-upstream-reloader/start.sh 
/home/work/nginx/sbin/nginx #这里假设我们的nginx安装在/home/work/nginx/目录下

六、兼容性

目前该板块已经在 centos6 和 centos7 上测试通过,适用于容器和物理机。

以上为小米公司实践结果

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Nginx 动态发现方案与实践

发表回复