开发者学堂课程【应用发布新版本如何保障流量无损 :应用发布新版本如何保障业务流量无损(二)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1215/detail/18215
应用发布新版本如何保障业务流量无损
三、解决方案
如何在实际业务场景中去快速落地全链路灰度呢?目前,主要有两种这个解决方案,第一种是基于物理环境隔离,还有一种是基于容辑环境隔离,我们首先来看这个物理环境隔离,它顾名思义就是通过这个机器的方式来搭建真正意义上的这个流量隔离,这种方案是需要为我们要灰度的这个服务,然后搭建一套网络隔离,然后资源独立的环境,然后在其中去部署,要规度发布的这个服务,比如说图中,灰度环境1我们部署是 chart 这样的一个灰度版本,然后灰度环境2需要去同时灰度 chart 和 order 这个服务,所以灰度环境2里部署的是 chart 和 order 这个 V2版本,然后会看到不需要灰度的服务的话,在这个灰度环境中需要去部署对应的机械版本,这个方案,一般是用于企业的测试,跟预发开发这个环境的这个搭建,就我们可以针对构建一个大家供应的这样一个预发环境来做测试,但是他对于线上灰度发布引流这个场景来说是灵活性是不够的,并且我们的微服多版本存在,微服架构中比较常见的一个问题,如果我们每次都需要对这个业务场景采用堆积积的方式来维护这个多并发的回度测试的环境,那么它这个成本是非常高的,并且这个运维成本也是成指数级上上升的。
第二个方案是逻辑环境隔离,我们只需要部署服务的灰度版本,然后流量在调用链路上流转的时候,它会去判断下游服务,有没有对应的灰度环境的版本,没有它会去回退到这个经验版本,有它会去优先访问本次灰度环境的服务,效果图就是如图所示,蓝色的是这个正式环境流量可以看到它经过服务 ABCD,然后黄色的是灰度环境1的流量可以看到在整个调用链路上,它是按需然后才会流转到这个灰度环境中,非常方便对服务 B 服务 D 进行一个同时的灰度的小流量验证的场景,那么如何去实现这个基于逻辑环境隔离的一个方案呢,我认为需要解决以下几个问题,第一个就是链路上的这个各个组件跟这个服务,需要能够根据请求流量特征进行一个动态路由,这就是我们常说的这个标签路由,从网关开始它去访问下游的服务a的时候,它需要通过这个回头路由来将流量转发到对应的灰度环境,然后我们的这个后端的整个调链路上,每一个每一套的这个环节也需要微服务框架,具备这个标签路由的能力,确保这个流量能够转发到下游的服务的互动环境,另一个就是我们需要对服务下的所有节点进行分组,能够区分出版本,也就是节点打标就是我们的服务上游在掉下游的时候,我们需要去能够区分出来,比方说 a 调服务 B,那么它需要去区分出来这个服务B它有哪些这个版本,所以在我们的这个节点上报注册中心的时候需要带上这个环境标,这就是节点打标,第三个就是我们需要对流量进行一个灰度标识,以及或者是版本标识,这就是我们常说的流量染色,流量染色就是我们的这个流量,从网关进来之后,我们需要能够区分出来它这个流量所属的这个灰度环境,然后去动态的打上对应的这个标,这就是流量染色,那么当这个标传下来之后,怎么能保证这个在整个调用链路上,这个标被每一个环节的这个服务识别呢,就说我们怎么能将这个标从整个链路上一路传递下去呢,这就是需要依赖分布式链路集中,然后需要当请求到来跟请求出来的时候,需要做一些类似于切面这样的操作,然后去塞一些元素信息,比方说就是这个环境标,这就这就是说我们在实现,基于逻辑环境隔离的这个全面规度,我们是有代价的,不可避免的是需要我们为业务使用的网关以及互端的这个服务使用的开发框架进行一个改造,首先,需要支持这个通态路由,对于 speaker 和 double 这个开发框架,可以对出口流量实现一个自定义然后完成这个流量识别以及标签路由,同时我们也需要在框架中去嵌入这个分布式链动资金的技术来帮助我们进行会度标的一个传递,此外,可能会需要引入一个中心化的流量治理平台,然后方便各个业务就开发者可以快速的在治理平台上面去动态的构建,我们这个灰度环境,以及一些灰度环境的销毁。
第二个就是我们服务老版本在下线的过程中怎样保证无损,下线过程中出现流量有损的这个根本原因在于应用提供者节点在停止服务前的时候,他没有确保,所有的消费者已经收到了这个下线事件,另外的话,他已经无法确定就是消费端所有的带图请求,已经得到的处理之后再停止应用,所以新发布的应用,即使任何业务代码没有任何的问题的话,也会因为存在这个下线过程中时间滞后这样的一个问题,导致流量有损影响用户的体验,那么如何达到无损下线的效果呢?要解决以下两个问题,第一个就是服务提供者这个待下线的节点,他需要主动的从注册中心注销,注销之后需要去持续运行一段时间,然后再退出,第二个是服务提供者下线节点需要通过某种机制,然后主动的来通知我们的消费端,我已经快下线,这时候这个消费者,在访问这个待下线节点的时候,他就会将这个请求转移到其他的节点提供者上面。如图所示,就是希望就是能够这个服务提供者A他在下线的时候,他不是直接下线,而是通过主动向注册中心,告知自己要下线,有一个主动下线的这样一个操作,下线之后,他在持续运行一段时间,并且搭配使用的是主动通知机制,就是说对于消费者个正常调用,我们需要我们通过本次请求的响应中,然后告诉他,我这个节点快下线了,那么消费者a在下一次请求的时候,他会将请求转发到提供者 B 上面,那么如何实现这样的一个无损下线的能力呢?首先,开发者要深入的去熟悉各个微服务框架的内部实现,并且就是对于主动服务下线这块儿需要去自行实现,一个经过大规模生产时间的脚本来帮助我们在节点下线过程中执行一些前置的操作,第三个就是需要去实现这个主动通知机制,就刚刚我们提到的,可以在正常调用的响应中去塞入这个下线这个标识来告知这个消费者去做一个主动刷新的这样一个操作。
第二个就是正式上线,是怎么去做这个新版本这个无损上线,这个上线过程中出现流量有损的根本原因在于服务提供者需要经过一段时间资源预热,才能正常的接受大流量请求,并成功处理,同时在这个 K8S 场景下还需要配合这个K8S readiness 以及滚动发布这样的一个生命周期,才能确保应用发布过程中,不出现业务报错,一般的这个情况下的话,刚出刚发布的微服应用的实力跟其他的这个正常实力,它是一起平摊这个线上流量的,例如现在我有四个节点,那么上线了一个新的节点之后,那么这个新的节点处理流量就是1/5的流量直接打过来了,那么如果想要达到无损上线的效果呢,需要控制这个消费者调用服务端的时候流量是渐进式的递增的,需要去给这个新节点一个充足的预热时间,常规的做法会基于这样的一个线性,然后逐步的扩大我们节点的一个权重。可以看到,图中曲线是线性增长,然后在120秒之后,它的 QPS 已经稳定,说明在这个过程中,这个节点的权重是线性递增的,所以它的流量也是逐步上升的,我们来看一下这个开源它是如何实现小流量服务预热过程,它的原理是首先 provide a,在向注册中心注册的时候,它会去带上一个节点的一个启动时间以及自身的一个权重,以及一个预热时间,然后 consumer 去订阅这个服务节点的时候,它会去拉取到这个服务节点对应的这个预热时间,还有启动时间以及 weight,然后它会根据启动时间,预热时间以及设置的权重,然后根据当前的时间来计算这个实际的权重。Double 的话,它提供了这个方案是线性增长的,就是说它无法做到,刚开始慢,后面就是比较快速的这样的一个权重增长的过程,因为应用在预热的时候,它整个预热时间,前一段时间,它是一个比较慢的过程,但基本上到中间的时候,它已经预热差不多,这时候我们可以去快速的逐步加大我们的流量,不需要一个信心的这样一个增长过程。
有了无损上线上线之后,从这个应用视角来分析一下这个过程,如图首先是应用初始化,这种就是正常的一个这个类加载过程,并且可以看到有一个预建链的过程,就是可以去对我们应用依赖的一个 readiness 的数据库然后进行一个预建链,避免流量到来之后再去建链导致请求超时。然后服务注册,可以去做一些延迟注册这样的一个能力就是节点启动之后,可以在资源初始化之后,然后再去注册到这个注册中心上面,然后以确保我们这个节点初始完毕之后才被这个客户端感知到,第二个就是合理的去设计,这个 readiness 检查,这个 readiness 检查设计的比较好之后,那么节点可以在这个完全就绪之后才会被这个客户端感知到,下面就是这个小流量预热,就是刚刚我们前面提到的基于用户提供的预热时间以及权重和启动时间来做一个节点启动之后的时间差与预热时间的比重比来算流量的递增的关系,当预热之后,就可以确保,这个应用能够得到很平稳的一个预热过程,下面图示就是对比,就是线性预热跟高阶的模型对比图。
无侵入解决方案一
前面提到解决方案,都是一些依赖开发者对现有的这个架构进行一个进入式改造的方案,下面介绍无侵入的解决方案,我们可以看到上面我们去改造需要一定的这个开发成本跟这个维护成本,同时也会给这个业务发展带来一些不稳定因素,因为我们每次治理能力的发展,也会需要应用去进行升级,那应用其实本身它业务就是没有变的,但是底层的基础设施更新那么就会导致,因为应用业务也需要进行升级,目前我们结合阿里巴巴双11大促经验,总结出来,云产品对外输出的这些能力,方便用户可以通过低成本无侵入的方式来接入享受阿里巴巴沉淀多年的这个微服务能力,第一个方案就是原生网关加 MS 治理,提供一站式的微服务解决方案,可以看到就是针对我们刚才的场景,网关就是换成了我们这个原生网关,那么原生网关是什么呢?它是将这个流量网关,微服务网关和安全网关进行了一个三合一,然后我们支持了这个标准的 K8s ingress,并且我们兼容 Nginx ingress,它覆盖了这个90%的用户场景。并且我们针对于刚刚提到的全链路灰度,去衍生的支持标签路由以及这个流量染色和路由 fallback,方便用户可以快速的端到端的这个全面的规动,并且的话我们支持多种复发现,我们采用 agent 的方式,是通过自己码增强的方式,以无侵入的方式来增强用户使用的 double 微服务治理能力,前面提到的全程的规度依赖这个标签路由,流量染色,还有这个节点达标以及分布式链路之中,都是在这个 agent 的实现,并且这个 agent 已经在阿里巴巴内部进行了这个多年的打磨,已经得到了这个大规模的这个生产时间,用户可以非常放心的进行使用,这就是 MSE 治理,它提供了这个正式的这个解决方案,然后它无侵入增强主流 Spring cloud 和 Apache Dubbo 开源微服务框架,五年以内的版本都是支持。
无侵入解决方案二
第二个解决方案就是 EDAS,这个跟上面这个方案区别在于就是后端的这个微服务选择的产品不一样,上面我们提到这个 MSE 服务治理的话,它主要的是提供主要专注于微服务治理提供了一整套的解决方案,主要是卖的是服务能力,EDAS 它针对于这个微服务,它提供了一个 pass 平台,首先它内置了这个一站式的预治决方案,就是它内部使用的是 MSE 治理,另外它对于注册中心也进行了一个托管,也就是说在应用开发,应用部署,还有监控和运维,它都提供了一个全战式的一个解决方案,也就是说,在 MSE 服务这个方案中用户可能就是说,他对注册中心的话,他可以去按需的选择,对于监控报警,他可以去选择其他云产品然后这个应用发布也是需要自己管理发布,一个这个生命周期的过程,那么 EDAS 它提供了这样一个平台,在这个微服治理这个基础上,然后额外提供了这个服务治理,可观测,弹性伸缩以及应用管理这几个模块有一个托管。另外目前的 EDAS 就是通过这个 ingress 方式来无缝集成的这个原生网关,首先解释下 ingress,其实是 K8s ingress 这个时代,它去定义集群中服务对外暴露这个访问方式,通过这样一个标准,将定义与实现进行区分,所以说只要是用户使用了这个 ingress 那么它后期可以非常方便。
四、动手实践
有这样的一个业务架构,首先就是前面有一个原生网关,后端的调用链路有购物车 a,然后交易中心 B 以及订单中心C,然后客户端是通过这个浏览器或者 IOS 终端,然后调过来,注册中心是 NACOS,对于集群中的这个入口服务 a,是通过标准 ingress 对外定一个访问方式,现在希望就是我们能够使用这个全面的灰度的能力,构建一个灰度环境,方便我们对服务 a 和 C 对这个灰度版本进行一个验证。
前提条件就是我们需要有一个 ACK 的这样一个容器集群,
另外需要去装 ack-onepilot,
这个装完之后装到对应集群之后,需要在运维中心,K8s 集群列表里边对这个刚刚加入的集群按一个命名空间级别按需开启服务治理。
现在去部署 ABC 正式版本以及的这个灰度版本,可以去看一下你这个配置,
我们将这个文件在这个工作负载进行新创建,
然后后端应用已经部署好,已经对应了这个灰度版本,现在去部署这个原生网关,因为需要从网关来做一个端到端的全链路灰度,部署网关是用的是 MSC 原生网关,用户可以在应用市场下面找到 ack-mse-ingress-controller,
然后就是选择对应集群进行部署,这个我提前部署好,可以看一下,
这就是部署的,然后部署之后,需要去通过一个 MS 原生网关提供一个 CRD 来去动态的创建一个原生网关集群,通过这样一个简单配置,
规格是 2c4g,然后找到 Mseingressconfig 创建一个原生网关
网关已经部署好了,现在来看一下,这个微服务已经已经也部署好了,现在就是去构建这样一个正式环境的流量,因为这个调链是网关然服务 ABC,所以说对容器用户来说,他这个服务对外暴露,希望通过这个 ingress 资源,所以说这个实践是通过 ingress 资源来避免暴露,然后在网络服务,去创建入口服务 service,
创建好之后,通过 k8s ingress,然后将它对外暴露,这个就是 ingress,域名是 base.example.com,访问的服务是spring-cloud-a-base,path 是根路径,
如果端点出来之后
说明这个 ingress 资源已经被这个原生网关解析了,那么现在来测一下,正常情况下,它是它的访问路径都是ABC,下面就是测试结果。
现在希望进行一个全链路灰度,就是我们的服务 A 跟一个服务 C 需要一个同时的灰度发版,A 和 C 的灰度版本已经部署了,下一步需要找到全链路灰度,去创建这个对应的这个泳道,选择这个 ingress,然后选择我们本次全面灰度涉及到的应用,
然后创建第一个泳道,第一个泳道叫 gray,因为希望测试的是 gray 这个环境。选择 gray,可以看到 a c 自动创建出来了,在 gray 环境里只有a c,因为b没有版本,点击确认。
这个泳道创建成功的,然后需要去通过这个创建 ingress,然后将灰度内容给创建出来,这就是灰度环境内容,
首先是通过这个 nginx 来做灰度发布的,MAC 这个原生网关它是支持这个 nginx,非常方便用户从 nginx 迁移到原生网关,然后设置的条件是基于这个 x-user-id 来做这个灰度发布策略,然后当它100的时候来访问这个 a 的 gray 版本,并且在流量从网关出来的时候访问下一跳入口服务 a 的时候,做一个自动的流量染色,x-mse-tag 内置的一个标,意思是进行流量的标识。然后再创建
创建成功,刷新一下,
当这个端点出来之后表示节点已经解析,现在来测一下,对请求去加一个 x-uesr-id:100,它的正常应该是 A gray,然后B gray,然后是 C gray,看到是符合预期的,
这样就完成了这个全链路灰度的 demo 展示,用户其实可以去基于这个原生网关做一些更高级的场景。