基于Nginx dyups模块的站点动态上下线

2017-09-11 16:39:43

简介

今天主要讨论一下,对于分布式服务,站点如何平滑的上下线问题。 

分布式服务

在分布式服务下,我们会用nginx做负载均衡, 业务站点访问某服务站点的时候, 统一走nginx, 然后nginx根据一定的轮询策略,将请求路由到后端一台指定的服务器上。 

 

这样的架构是没有问题的, 但是我们这里考虑几个问题, 

1. 网站上下线问题:我们网站平时更新站点的时候是直接覆盖文件,然后重启, 那这样会造成一些请求中断,如果是非核心逻辑那还好, 如果是核心逻辑,那请求中断,会影响一些数据一致性,比如资金, 交易,订单等。  

 2. 动态加减机器,比如某个站点访问量大,要新增机器,那就需要修改nginx的配置,然后reload, 这样会中断连接。 虽然reload很快,但是还是会有一瞬间的请求中断。 

 

对于第一个问题,我们可以在请求量少的时候去更新, 但是这种在一些服务稳定的公司可用, 对于互联网企业,可能2-3天就一个版本, 而且需要立刻上线, 如果每次都要等到凌晨4点去更新, 可能整个的开发节奏都被带慢了。 

对于第二个问题, 对于可以预见的流量,比如大促来临,可以提前3天放在请求量少的时候更新。 

 

最近几年,随着SOA的普及和微服务的出现,特别是dubbo的出现,服务治理的概念被提出来。 服务治理是一个很宏大的概念,包括服务注册,服务自动发现,服务路由,服务依赖,集群容错,服务降级,服务监测,服务审批等,当然不是每个服务中心都必须实现这些东西, 公司可以根据自己的实际需求来定制实现。 

基于Nginx dyups模块的动态上下线

基于以上这些情况, 我计划实现一个工具,这个工具首先解决站点上下线和动态扩容问题,也就是说在不需要重启nginx的情况下,并且在保证请求不丢失的情况下来更新站点。 同时带有部分服务治理功能。 

 

 

服务上线

1. 在一个新服务上线的时候,一般会提前申请几台机器, 运维会在nginx上新增server,并新增server对应的upstream ,正常情况下upstream应该配置是后端服务器的IP,但是这里不配置(如果允许,甚至这一步都可以省略)。 

2. 服务部署好并启动,在启动的时候,向注册中心注册自身的服务信息,包括IP和端口。 

3. 注册中心收到请求后,会对服务进行健康检测,确保提供的服务没有问题,则将服务状态标示为预上线状态。 

4. 在后台管理中心,就可以将预上线的服务设置为上线,服务管理中心会调用nginx的上线接口,将服务IP新增或者更新到upstream中,服务就可以提供访问。   

 

服务更新

假如我们现在有一个服务需要更新,则执行以下步骤:

1. 在后台管理中心,将一个服务设为下线,此时服务中心会调用nginx的下线接口,将指定服务器的IP设置为下线。 

2. 在等待1分钟后,确保没有新连接连过来,则可以开始更新服务站点。

3. 更新完毕后,再手动设为上线,此时服务中心会调用nginx的上线接口,将指定服务器的IP设置为上线。当然对于成熟的服务,这些都可以自动化,有些公司会有一些自动化发布工具, 与自动化发布工具集成,可以一键下线,更新并上线。 

 

服务运行期间

在服务运行过程中,会有一个健康检测的服务对所有提供服务的站点进行健康检测,一旦检测到有问题,就执行下线逻辑。 直到问题被解决,最后执行上线流程。 

 

动态加减机器

在服务运行过程中,可能因为某些原因,服务请求飙高(前提是这些请求都是合法的),超过了当前集群的承载能力,当系统检测到这些情况后,可以动态扩充机器,比如现在流行的docker,在启动容器的时候,同时启动应用,应用在启动的时候,将自身信息注册给注册中心,注册中心再将这些信息同步到nginx,应用就可以提供访问,整体上就可以实现弹性计算。 

 

为什么不实现服务动态发现?

   这里可以看到图中已经有一个服务注册中心。 既然有了服务注册中心了, 那可以让业务站点连接服务注册中心来获取真实的服务IP,然后绕过nginx来连接服务,这里之所以没有这样做,是因为:

    1.  实现服务动态发现,这个需要和RPC框架配合,而且需要做服务的软负载,失败重连,限流等,整个项目设计就上升了一个复杂度, 考虑到有些项目还未使用RPC,并且不想对原有的项目有过多的侵入, 所以这里不做实现。 但是并不意味没有这些功能,服务的负载, 失败重连, 限流,其实这些功能在nginx中同样也有,可以直接使用,所以没有必要重新再开发。 

    2.  实现服务动态发现,获取到真实的服务IP,然后直连,这些一般是在流量特别大,nginx上出现短板的时候使用,但实际情况,一般很少会耗尽nginx的性能,即使有,也可以通过ngxin水平扩展来实现,所以这里依然使用nginx作为负载均衡。 

 

这里讲一下这个项目的关键点:

1. 服务的注册和健康检测这个没有技术难点,这里不做解释。

2. 关于操作nginx上下线,这里的确是一个难点,因为nginx本身并没有提供这些上下线API,需要openresty并配合一些第三方扩展来实现。 这里主要用到了两个扩展模块:ngx_http_dyups_module  lua-upstream-nginx-module

  ngx_http_dyups_module(https://github.com/yzprofile/ngx_http_dyups_module)提供了粗粒度的upstream管理方法,可以对整个upstream进行新增,删除。 

  lua-upstream-nginx-module(https://github.com/openresty/lua-upstream-nginx-module) ,则提供了细粒度的管理方式,可以对某一个服务IP进行管理,其中提供的set_peer_down方法,可以对upstream中的某个ip进行上下线。

3. 也可以使用ngx_dynamic_upstream(https://github.com/cubicdaiya/ngx_dynamic_upstream)

这些插件有一个共同点,那就是在不需要重启nginx的基础上, 动态修改nginx的配置。 


  • 2019-12-20 13:24:58

    瓦片地图生成使用以及原理

    我们都知道地球是圆的,电脑显示器是平的,要想让位于球面的形状显示在平面的显示器上就必然需要一个转换过程,这个过程就叫做投影(Projection)。在地球上我们通过经纬度来描述某个位置,而经过投影之后的地图也有自己的坐标系统,本篇文章就来详细介绍在百度地图API中涉及的各种坐标体系。

  • 2019-12-20 13:27:16

    腾讯地图谷歌和高德地图等自定义地图区别

    腾讯、百度、Google的地图投影均采用Web Mercator 投影坐标系;腾讯与Google的地图瓦片分辨率及切片范围是完全相同的,仅仅是命名规则稍有不同,这就使得同一位置和缩放级别的地图瓦片是完全可以重叠的;而百度地图每个缩放级别分辨率与前两者均不相同,而且地图瓦片的坐标原点做了一定的偏移,导致百度地图与前两者的瓦片是无法重叠的,这是因为百度在GCJ-02的基础上又进行了加密处理,形成了百度独有的BD-09坐标系。

  • 2019-12-22 08:06:48

    如何快速撤销上一次的commit

    在平时工作中使用git难免会提交一些错误的文件到git库里,这时候,撤销吧,怕把正确的文件删除了,不撤销重新改又很麻烦,下面,我就从提交的三个阶段,来讲解如何撤销错误的操作。

  • 2019-12-23 14:54:03

    RPC, REST ,GraphQL区别比较优劣

    其实在使用和学习的过程中,有很多文章都对比过它们的异同,但是大部分文章并没有从一个相对客观的角度来对比,更多是为了突显一个的优点而刻意指出另外一个的缺点。这让我想到一句话,脱离业务情景谈技术就是耍流氓。