美文网首页
如何优雅发布

如何优雅发布

作者: ction | 来源:发表于2020-05-24 18:12 被阅读0次

    优雅发布的概念

    DevOps、敏捷作为CI/CD思想的延伸已经成为研发的基本共识和文化基础,今天谈到的优雅发布和和CD中的Deployment是同一个单词但是侧重点却不同,CI/CD的过程讲究的是如何将开发、测试和部署的过程串起来达到一气呵成的效果,所以有持续集成(CI)和持续部署(CD)的概念,也有Pipeline的概念,基于敏捷的研发理念迭代速度很快,在流水线上的每一个角色,甚至包括产品经理都像是在流水线旁等待任务一样,PRD一旦发布,这个流水线就开始运转了,争分夺秒地上线去抢夺用户和流量。尤其是上线前的Dev、QA和Staging阶段流水线的特性更是被严重依赖,优雅发布这个时候并不是重点,没有人会在乎短暂的停机,而且很多非生产环境都是单机的,无论如何都无法避免发布造成的服务停止。但是到了真正的上线阶段,特别是有了一定的用户群和流量的时候,拉新客和留老客的重要度就是同等重要的了。而面向C端用户的产品迭代又非常快,CI/CD的理念下,到了真正的发布的时候如果不能做到优雅发布即通常也称为不停机发布(Zero-Downtime-Deployment),用户的流失的锅就会由研发团队来背,进而转嫁给由运维来背(想象一下用户注册环节恰巧在流水线发布,一批用户注册失败了)。而由于概念的不清晰,研发团队经常被挑战的就是:不都已经敏捷研发了,流水线部署了嘛,怎么还不能随时上线?

    传统应用如何优雅发布

    开始主题之前让我们先看看传统意义上的“不停机发布”是如何进行的,首先看下图,这是一个最简单的典型的由负载均衡来代理,假设场景是我们要发布App2,从图中我们可以看到App2有3个节点,一般我们选择在非高峰时间段,2B应用通常在晚上就可以进行发布,2C应用可能会选择在凌晨2点左右。发布的步骤就是通过Pipeline逐步的对192.168.10.21 ~ 23进行逐个发布,这样的发布看似总有两个节点在提供服务,用户是没有感知的,但是细究之下有很多推敲之处:一般负载均衡的心跳检测都有一定的时间,从60S到180S不等,所以在进行具体一个节点发布的时候,由于心跳检测还没有来的及检测出来当前的节点已经不能提供服务了,而这种情况实际有两种细分场景:一个场景实际就是应用服务端口已经不提供服务了(tomcat的8080端口响应超时),所以一部分请求就被转发到当前节点,但是应用服务器不能响应,一般也就是超时响应,此时的表现就是用户在白屏等待直至超时。另外一个场景是尽管应用服务端口已经启动,但是启动应用是需要一定的时间的,在初始化过程中被转发过来的请求就没有办法响应了,而此时端口实际是work的,但是不能处理正常的业务,这种情况下用户得到的是立即响应的服务器错500错误,如果没有针对性的错误处理,这是一般就会报出来tomcat的500错误。因此这样的发布实际上有很长的一段错误发生率,是完全无法达到优雅发布的标准的。

    Figure-1-典型应用负载均衡

    那么这种情况下,我们该如何避免发布过程中的服务超时和服务器内部错误500的情况发生呢,简单一点的做法就是结合负载均衡的配置,但是这样的做法对运维有一定要求,而且要熟悉所有服务的upstream配置,下面让我们先看看如何操作。

    1、临时修改负载均衡的配置,将要发布的节点从upstream中摘除

    upstream app2_backends {

            server 192.168.10.21:8080;

            server 192.168.10.22:8080;

            server 192.168.10.23:8080;

    }

    2、重启Nginx

    nginx -s reload

    3、观察一下192.168.10.21的日志,看看是不是有新的流量打入(这里暂时不考虑定时任务等其他因素)

    4、在没有新流量打入,且原有流量处理完成的前提下进行正常发布

    5、确认192.168.10.21的服务正常启动后(日志或者/status都可以)

    6、修改负载均衡的配置,将192.168.10.21上线,192.168.10.22从upstream中摘除

    upstream app2_backends {   

        server 192.168.10.21:8080;       

        server 192.168.10.22:8080;       

        server 192.168.10.23:8080;

    }

    7、重启Nginx

    重复上述步骤直至将所有节点发布完毕,但是这样这样的发布实在太多繁琐,而且中间涉及大量的负载均衡的配置修改、反复重启、app应用日志的确认等,很难将发布下放至一线运维人员,所以很难推行。那么有没有更简单的操作呢?当然是有的,我们来回顾一下上述发布过程,中间涉及反复的配置修改和重启命令,都是重复性劳动,而且容易出错,主要就是每次修改了配置必须要重启Nginx,如果加载后不用重启了是不是就简化了很多步骤?嗯,所以动态加载就是答案,实现动态加载有如下两种方式:

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

    因为nginx-1.9.0以上支持zone的概念,而ngx_dynamic_upstream是需要zone的,所以可以使用ngx_dynamic_upstream(https://github.com/cubicdaiya/ngx_dynamic_upstream)来进行upstream中的某个ip进行上下线

    我们以ngx_dynamic_stream为例来看如何简化操作

    1、修改conf配置,这里注意看粗体的/dynamic部分,后面会用到

    upstream app2_backends {

        zone zone_for_app2_backends 1m;

        server 192.168.10.21:8080;           

        server 192.168.10.22:8080;         

        server 192.168.10.23:8080;

    }

    server {

            listen 80;

            location /dynamic {

            allow 127.0.0.1;

                deny all;

                    dynamic_upstream;

            }

            location / {

                proxy_pass http://app2_backends;

            }

    }

    2、下线192.168.10.21节点

    $ curl "http://127.0.0.1/dynamic?upstream=zone_for_app2_backends&server=192.168.10.21:8080&down="

    server 192.168.10.218080  down;

    server 192.168.10.228080 ;

    server 192.168.10.23:8080 ;

    $

    3、观察一下192.168.10.21的日志,看看是不是有新的流量打入

    4、在没有新流量打入,且原有流量处理完成的前提下进行正常发布192.168.10.21节点

    5、确认192.168.10.21的服务正常启动后(日志或者/status都可以)

    6、上线192.168.10.21节点

    $ curl "http://127.0.0.1/dynamic?upstream= zone_for_app2_backends &server= 192.168.10.21 :8080&up="

    server 192.168.10.21 8080  ;

    server 192.168.10.22 8080 ;

    server 192.168.10.23 :8080 ;

    $

    7、重复2-6步骤发布另外两个节点

    到这里为止,大家可以看到从概念上的“不停机发布”到真正的不停机发布,我们做了一个深入的实际的可参考案例,那么够不够优雅呢?这个我们暂时不表,后面我们再进一步阐述。我们接下来看一下面向微服务的优雅发布如何操作,又有哪些细节等我们来探究?

    微服务应用如何优雅发布

    进入这一章节,第一印象是啥?都微服务集群了,天然都支持不停机发布了!这是大量的解决方案提供商跟我说解决方案的时候的一个答案,好像这个问题就不应该问,潜台词是,你懂不懂微服务?实际真的是这样么?

    首先要声明的就是在微服务应用中负载均衡更加复杂,既涉及到客户端又涉及到服务端,在上述章节传统单体应用还主要以服务端的负载均衡为主,因此并没有对客户端负载均衡进行展开,而本章节我们就不赘述服务端的负载均衡,微服务的两大阵营Dubbo和Spring Cloud我们不会全部展开,今天仅以Spring Cloud为例进行简单剖析。

    我们知道通过Ribbon配置服务提供者地址后,Ribbon就可以基于某种负载均衡算法,自动帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。下图展示了Ribbon与注册中心(Eureka/Nacos均可)、微服务网关(Zuul/Spring Cloud Gateway)的负载均衡关系。稍加解释一下:

    S1线是从入口负载均衡到达微服务网关实例1(服务消费者),然后通过网关的Ribbon负载到服务2(服务提供者/服务消费者)实例1,再负载到服务1(服务提供者)实例2

    S2线是从入口负载均衡到达服务网关实例3(服务消费者),然后通过网关的Ribbon负载到服务1(服务提供者)实例3

    Figure-2-Ribbon在微服务系统中的负载均衡应用

    那么是不是通过这样的一个架构就可以说是能提供不停机发布了呢?答案是否定的。这个原理同上一章节中是一致的,就是说负载均衡算法都是有心跳时间的,换句话说,都是通过被动的检测服务提供方的状态来决定是否剔除不健康的节点,因此虽然在微服务中都提供了健康检查的接口,因为是被动的,所以总会有失效状态和失效时间。因为微服务的负载均衡既要考虑到服务端的负载又要考虑到客户端的负载,实际上,更需要提前摘除不健康节点。这里我们可以看下阿里云提供的EDAS服务是如何做的,具体参考无损下线 Spring Cloud 应用。那么我这里就简单通过一张图来解释一下,EDAS如何做的,如果没有EDAS我们又如何做?

    Figure-3-微服务优雅发布

    请大家注意这张图与上图的变化:

    1、运维发布的时候主动注销某一服务的实例(服务1的实例1)

    2、确认待发布的节点(服务1的实例1)下线之后进行真正的发布

    3、此时同样是上述的S1和S2两个请求,从注册中心中就无法查到待发布节点(服务1的实例1),将仅负载到剩余的两个实例上

    运行在EDAS上的微服务,通过主动监听事件,捕获到进程注销事件后,增加了一个prestop阶段,向注册中心推送注销服务实例的消息,主动下线,确认服务节点摘除之后再进行真正的注销。

    那么如果我们不跑在EDAS上要如何进行做呢?从原理上来讲,我们手工就可以做到,只是比较繁琐,下面由我来以Eureka为例进行拆解一下,大致做法如下:通过/eurekaUnregister或者/offline来通知注册中心下线,多解释一点,收到下线通知之后并不会马上通知所有的注册客户端,而是等到下一次心跳的时候再通知,这样处理的好处:首先不会增加注册中心的消息处理逻辑,其次是所有的服务调用都是在同一心跳的时候被通知不会因为立即通知下线而产生服务终端从而产生失败。

    补充一点,有一些操作是可以通过DELETE操作/eureka/apps/{application.name}/{instance.id}来主动从Eureka摘除节点,但是这样的做法无法从根本上将该节点摘除,下一次心跳续约后,Eureka因为检测到该节点处于online状态,会继续把该节点加入Eureka注册中心。

    Figure-4-主动通知注册中心下线

    如果不通过上述两种方式进行下线,还有一种更简单的,直接调用Eureka的Restful API即可。

    PUT /eureka/apps {application.name}/{instance.id} /status?value=OUT_OF_SERVICE

    总结

    本文通过简单的两个场景来阐述优雅发布在传统应用和微服务集群中如何做,从而真正减少由于版本更新迭代而带来的服务不可用时间,尤其是随着微服务集群的规模越来越大,如果不能提供这种不宕机发布服务,是很难协调出来一个窗口来进行更快的业务迭代,所以我们可以看到像BATJ这类型的业务你很难见到有停止服务的运营公告,但是在企业内部,甚至一些伪互联网公司的服务,提供的都是缩水的发布服务,而在用户和流量成本越来越高的时代,显然这是不可接受的。

    相关文章

      网友评论

          本文标题:如何优雅发布

          本文链接:https://www.haomeiwen.com/subject/udcwohtx.html