Skip to content

Commit

Permalink
add doc file
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaokai-wang committed Jan 28, 2016
1 parent 7907736 commit babd1d2
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 0 deletions.
Empty file added doc/FAQ.md
Empty file.
167 changes: 167 additions & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
nginx-upsync-module
====

目录
=================

* [模块背景](#模块背景)
* [方案设计](#方案设计)
* [业界方式](#业界方式)
* [开发方案设计](#开发方案设计)
* [http_api方案](#http_api方案)
* [upsync方案](#upsync方案)
* [方案实现](#方案实现)
* [列表更新方式](#列表更新方式)
* [高可用性](#高可用性)
* [兼容性](#兼容性)
* [性能测试](#性能测试)
* [应用案例](#应用案例)

模块背景
======

针对模块的开发背景,以微博的业务场景为例,每年的元旦、春晚、红包飞会带来巨大的流量挑战,这些业务场景的主要特点是:瞬间峰值高,互动时间短。基本上一次峰值事件,互动时间都会3小时以内,而明星突发新闻事件,红包飞这种业务,经常会遇到高达多倍的瞬间峰值。传统的应对手段,主要是提前申请足够的设备,保证冗余。

这么做除了成本高外,对系统进行水平扩容时,耗费的时间久,而且扩容缩容流程繁琐。对于明星的突发事件,流量突增几倍的情况下,进行扩容缩容的繁琐操作便会更加突出,而且这个时候对nginx 进行reload 是有一定危险的,之前的操作表明,在流量比较高时进行nginx 的reload 会出现服务的抖动,造成部分请求耗时增长20%-50%。

为了节约成本以及随着云服务的兴起,平台采用了混合云的部署方式,对资源进行弹性调度。对于第三方公有云服务,比如阿里云按照小时计费,所以需要按需部署,为了避免在弹性调度时,对服务造成不必要的抖动,以及自动化扩容缩容操作,开发了nginx-upsync-module,实现nginx 无损的扩容缩容。

方案设计
========

方案介绍了当前业界已经存在的,分析了其相应的优缺点,并自己设计实现了两个方案,并综合对比选择了upsync方式。

业界方式
-----------

实现nginx层的弹性扩容、缩容,当前业界已存在的、不需二次开发的有基于consul的consul-template和tengine提供的基于dns的服务发现。

```
两种方式的分析对比:
| |dns|consul-template|
|实时性|差|中|
|容错性|强|强|
|一致性|强|强|
|复杂性|易|繁|
```

tengine团队开发了自己的模块,该模块可以动态的解析upstream conf下的域名。这种方式操作简单,只要修改dns下挂载的server列表便可;缺点是现在的第一版负载均衡策略待完善;另一点默认解析一次的时间是30s,若配置的时间过短,可能对dns server形成压力;再一点是基于dns的服务,下面不能挂过多的server,否则会发生截断。

consul-template与consul作为一个组合,consul作为db,consul-template部署于nginx server上,consul-template定时向consul发起请求,发现value值有变化,便会更新本地的nginx相关配置文件,发起reload命令。但是在流量比较重的情况下,发起reload会对性能造成影响。reload的同时会引发新的work进程的创建,在一段时间内新旧work进程会同时存在,并且旧的work进程会频繁的遍历connection链表,查看是否请求已经处理结束,若结束便退出进程;另reload也会造成nginx与client和backend的长链接关闭,新的work进程需要创建新的链接。

reload造成的性能影响:
![consul-template-qps](https://github.com/weibocom/nginx-upsync-module/doc/images/consul-template-reload-qps.png)
在27s的时候进行的reload,nginx的请求处理能力会下降(注:nginx对于握手成功的请求不会丢失)。
![consul-template-cost](https://github.com/weibocom/nginx-upsync-module/doc/images/consul-template-reload-cost.png)
同时发现reload的同时耗时会发生波动,甚至有50%+的耗时增加。

基于上述的原因,设计并实现了另外两套方案,避免对nginx进行reload。

开发方案设计
-----------

* http_api方案

此方案提供nginx http api,添加/删除server时,通过调用api向nginx发出请求,操作简单、便利。架构图如下:
![http-api architecture](https://github.com/weibocom/nginx-upsync-module/doc/images/nginx-http-api-arch.png)
http api除了操作简单、方便,而且实时性好;缺点是分布式一致性难于保证,如果某一条注册失败,便会造成服务配置的不一致,容错复杂;另一个就是如果扩容nginx服务器,需要重新注册server(可参考nginx-upconf-module,正在完善)。

* upsync方案

upsync方式引入了第三方组件,作为nginx的upstream server配置的db,架构图如下:
![upsync architecture](https://github.com/weibocom/nginx-upsync-module/doc/images/nginx-upsync-arch.png)
所有的后端server列表存于consul,便于nginx横向扩展,实时拉取,容错性更好,而且可以结合db的KV服务,提高实时性。

通过上面的综合对比,选取upsync的方式,开发了nginx模块nginx-upsync-module。对于nginx配置db的选取,由于当前docker技术十分火热,选用了consul,另模块不强依赖于consul,可以横向的扩展支持etcd、zookeeper等。下面的实现基于consul进行介绍。

方案实现
======

基于upsync方式,开发了模块nginx-upsync-module,它的功能是拉取consul的后端server的列表,并更新nginx的路由信息。此模块不依赖于任何第三方模块。

列表更新方式
------------

consul 作为nginx的db,利用consul的KV服务,每个nginx work进程独立的去拉取各个upstream的配置,并更新各自的路由。流程图如下:
![upsync follow](https://github.com/weibocom/nginx-upsync-module/doc/images/list_update.bmp)

每个work进程定时的去consul拉取相应upstream的配置,定时的间隔可配;其中consul提供了time_wait机制,利用value的版本号,若consul发现对应upstream的值没有变化,便会hang住这个请求5分钟(默认),在这五分钟内对此upstream的任何操作,都会立刻返回给nginx,对相应路由进行更新。对于拉取的间隔可以结合场景的需要进行配置,基本可以实现所要求的实时性。upstream变更后,除了更新nginx的缓存路由信息,还会把本upstream的后端server列表dump到本地,保持本地server信息与consul的一致性。

除了注册/注销后端的server到consul,会更新到nginx的upstream路由信息外,对后端server属性的修改也会同步到nginx的upstream路由。当前本模块支持修改的属性有weight、max_fails、fail_timeout、down,修改server的权重可以动态的调整后端的流量,若想要临时移除server,可以把server的down属性置为1(当前down的属性暂不支持dump到本地的server列表内),流量便会停止打到该server,若要恢复流量,可重新把down置为0。

另外每个work进程各自拉取、更新各自的路由表,采用这种方式的原因:一是基于nginx的进程模型,彼此间数据独立、互不干扰;二是若采用共享内存,需要提前预分配,灵活性可能受限制,而且还需要读写锁,对性能可能存在潜在的影响;三是若采用共享内存,进程间协调去拉取配置,会增加它的复杂性,拉取的稳定性也会受到影响。基于这些原因,便采用了各自拉取的方式。

高可用性
------------

nginx的后端列表更新依赖于consul,但是不强依赖于它,表现在:一是即使中途consul意外挂了,也不会影响nginx的服务,nginx会沿用最后一次更新的服务列表继续提供服务;二是若consul重新启动提供服务,这个时候nginx会继续去consul探测,这个时候consul的后端服务列表发生了变化,也会及时的更新到nginx。

另一方面,work进程每次更新都会把后端列表dump到本地,目的是降低对consul的依赖性,即使在consul不可用之时,也可以reload nginx。nginx 启动流程图如下:
![start follow](https://github.com/weibocom/nginx-upsync-module/doc/images/start_fllow.bmp)

nginx启动时,master进程首先会解析本地的配置文件,解析完成功,接着进行一系列的初始化,之后便会开始work进程的初始化。work初始化时会去consul拉取配置,进行work进程upstream路由信息的更新,若拉取成功,便直接更新,若拉取失败,便会打开配置的dump后端列表的文件,提取之前dump下来的server信息,进行upstream路由的更新,之后便开始正常的提供服务。

每次去拉取consul都会设置连接超时,由于consul在无更新的情况下默认会hang五分钟,所以响应超时配置时间应大于五分钟。大于五分钟之后,consul依旧没有返回,便直接做超时处理。

兼容性
------------

整体上讲本模块只是更新后端的upstream路由信息,不嵌入其它模块,同时也不影响其它模块的功能,亦不会影响nginx-1.9.9的几种负载均衡算法:least_conn、hash_ip等。

除此之外,模块天然支持健康监测模块,若nginx编译时包含了监测模块,会同时调用健康监测模块的接口,时时更新健康监测模块的路由表。

性能测试
======

nginx-upsync-module模块,潜在的带来额外的性能开销,比如间隔性的向consul发送请求,由于间隔比较久,且每个请求相当于nginx的一个客户端请求,所以影响有限。基于此,在相同的硬件环境下,使用此模块和不使用此模块简单做了性能对比。

基本环境:

```
硬件环境:Intel(R) Xeon(R) CPU E5645 @ 2.40GHz 12 核
系统环境:centos6.5;
work进程数:8个;
压测工具:wrk;
压测命令:./wrk -t8 -c100 -d5m --timeout 3s http://$ip:8888/proxy_test
```

压测数据:
| |总请求|qps|
|nginx(official)|14802527|49521|
|nginx(upsync)|14789843|48916|

其中nginx(official)是官方nginx,不执行reload下的测试数据;nginx(upsync)是基于upsync模块,每隔10s钟向consul注册/注销一台机器的数据;从数据可以看出,通过upsync模块做扩缩容操作,对性能的影响有限,可以忽略不计。

应用案例
======

本模块首先应用于平台的remind业务,qps量约为7000+左右。下面是对本业务灰度的基本数据:

请求量变化:
| |0|1|2|3|4|5|6|7|8|9|10|11|12|
|reload|7723|7583|7833|7680|7809|7682|6924|7081|7207|7232|7486|7571|7465|
|upsync|7782|7705|7772|7810|7899|7978|7858|7934|7994|7731|7824|7648|7888|

![reload vs upsync](https://github.com/weibocom/nginx-upsync-module/doc/images/upsync-vs-reload-qps.png)

平均耗时变化:
| |0|1|2|3|4|5|6|7|8|9|10|11|12|
|reload|12.102|15.108|11.443|9.426|10.178|10.605|15.253|14.315|14.762|8.392|14.385|32.335|15.277|
|upsync|9.586|11.963|8.694|9.676|10.616|10.335|9.766|9.406|8.943|10.971|8.080|9.185|12.055|

![reload vs upsync](https://github.com/weibocom/nginx-upsync-module/doc/images/upsync-vs-reload-cost.png)

从数据可以得出,reload操作时造成nginx的请求处理能力下降约10%,nginx本身的耗时会增长50%+。若是频繁的扩容缩容,reload操作造成的开销会更加明显。

平台为了应对元旦期间的流量峰值,基于本平台的dcp系统,于元旦晚上批量部署阿里云实例,应用此模块进行了百余次的扩容、缩容操作,服务稳定,没有出现服务的波动。另本模块可以应用于对资源的弹性调度系统内,同时可以应用于临时流量突增的场景。

模块地址:https://github.com/weibocom/nginx-upsync-module,欢迎大家使用,任何问题欢迎随时交流。

```
参考附录:
[1] http://tengine.taobao.org/document_cn/http_upstream_dynamic_cn.html;
[2] https://www.hashicorp.com/blog/introducing-consul-template.html;
[3] https://www.nginx.com/blog/dynamic-reconfiguration-with-nginx-plus;
[4] https://github.com/alibaba/tengine/issues/595;
[5] https://github.com/xiaokai-wang/nginx-upconf-module;
```
Binary file added doc/images/.DS_Store
Binary file not shown.
Binary file added doc/images/consul-template-reload-cost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/consul-template-reload-qps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/list_update.bmp
Binary file not shown.
Binary file added doc/images/nginx-http-api-arch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/nginx-upsync-arch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/start_fllow.bmp
Binary file not shown.
Binary file added doc/images/upsync-vs-reload-cost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/upsync-vs-reload-qps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit babd1d2

Please sign in to comment.