转载-Nginx动态更新upstream实现

原文出处: Nginx动态发现方案与实践

1. 背景

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

2. 模块架构

前期通过调研发现,有些公司采用了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配置到配置文件中。

3. 核心功能

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

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

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

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

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

4. 模块工作流

image

5. 模块使用

基础依赖:

支持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{
    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/目录下

7. 兼容性

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

参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容