跳转到内容
云栖回顾 | 2024 云栖大会微服务和网关相关演讲材料点此了解

3.2 微服务全链路灰度解决方案

什么是全链路灰度

单体架构下的服务发布

首先,我们先看一下在单体架构中,如何对应用中某个服务模块进行新版本发布。如下图,应用中的Cart服务模块有新版本迭代:
image.png第二节_3-2-1 第三章第二节第一张图.png

3-2-1 第三章第二节第一张图
由于Cart服务是应用的一部分,所以新版本上线时需要对整个应用进行编译、打包以及部署。服务级别发布问题变成了应用级别的发布问题,我们需要对应用的新版本而不是服务来实施有效的发布策略。

目前,业界已经有非常成熟的服务发布方案,例如蓝绿发布和灰度发布。蓝绿发布需要对服务的新版本进行冗余部署,一般新版本的机器规格和数量与旧版本保持一致,相当于该服务有两套完全相同的部署环境,只不过此时只有旧版本在对外提供服务,新版本作为热备。当服务进行版本升级时,我们只需将流量全部切换到新版本即可,旧版本作为热备。我们的例子使用蓝绿发布的示意图如下,流量切换基于四层代理的流量网关即可完成。
image.png
第二节_3-2-2 第三章第二节第二张图.png
3-2-2 第三章第二节第二张图
在蓝绿发布中,由于存在流量整体切换,所以需要按照原服务占用的机器规模为新版本克隆一套环境,相当于要求原来1倍的机器资源。灰度发布的核心思想是根据请求内容或者请求流量的比例将线上流量的一小部分转发至新版本,待灰度验证通过后,逐步调大新版本的请求流量,是一种循序渐进的发布方式。我们的例子使用灰度发布的示意图如下,基于内容或比例的流量控制需要借助于一个七层代理的微服务网关来完成。
image.png
第二节_3-2-3 第三章第二节第三张图.png
3-2-3 第三章第二节第三张图
其中,Traffic Routing是基于内容的灰度方式,比如请求中含有头部stag=gray的流量路由到应用v2版本;Traffic Shifting是基于比例的灰度方式,以无差别的方式对线上流量按比重进行分流。相比蓝绿发布,灰度发布在机器资源成本以及流量控制能力上更胜一筹,但缺点就是发布周期过长,对运维基础设施要求较高。

微服务架构下的服务发布

在分布式微服务架构中,应用中被拆分出来的子服务都是独立部署、运行和迭代的。单个服务新版本上线时,我们再也不需要对应用整体进行发版,只需关注每个微服务自身的发布流程即可,如下:
image.png
第二节_3-2-4 第三章第二节第四张图.png
3-2-4 第三章第二节第四张图
为了验证服务Cart的新版本,流量在整个调用链路上能够通过某种方式有选择的路由到Cart的灰度版本,这属于微服务治理领域中流量治理问题。常见的治理策略包括基于Provider和基于Consumer的方式。

  • 基于Provider的治理策略。配置Cart的流量流入规则,User路由到Cart时使用Cart的流量流入规则。
  • 基于Consumer的治理策略。配置User的流量流出规则, User路由到Cart时使用User的流量流出规则。

此外,使用这些治理策略时可以结合上面介绍的蓝绿发布和灰度发布方案来实施真正的服务级别的版本发布。

全链路灰度

继续考虑上面微服务体系中对服务Cart进行发布的场景,如果此时服务Order也需要发布新版本,由于本次新功能涉及到服务Cart和Order的共同变动,所以要求在灰度验证时能够使得灰度流量同时经过服务Cart和Order的灰度版本。如下图:
image.png
第二节_3-2-5 第三章第二节第五张图.png
3-2-5 第三章第二节第五张图

按照上一小节提出的两种治理策略,我们需要额外配置服务Order的治理规则,确保来自灰度环境的服务Cart的流量转发至服务Order的灰度版本。这样的做法看似符合正常的操作逻辑,但在真实业务场景中,业务的微服务规模和数量远超我们的例子,其中一条请求链路可能经过数十个微服务,新功能发布时也可能会涉及到多个微服务同时变更,并且业务的服务之间依赖错综复杂,频繁的服务发布、以及服务多版本并行开发导致流量治理规则日益膨胀,给整个系统的维护性和稳定性带来了不利因素。

对于以上的问题,开发者结合实际业务场景和生产实践经验,提出了一种端到端的灰度发布方案,即全链路灰度。全链路灰度治理策略主要专注于整个调用链,它不关心链路上经过具体哪些微服务,流量控制视角从服务转移至请求链路上,仅需要少量的治理规则即可构建出从网关到整个后端服务的多个流量隔离环境,有效保证了多个亲密关系的服务顺利安全发布以及服务多版本并行开发,进一步促进业务的快速发展。

全链路灰度的解决方案

如何在实际业务场景中去快速落地全链路灰度呢?目前,主要有两种解决思路,基于物理环境隔离和基于逻辑环境隔离。

物理环境隔离

物理环境隔离,顾名思义,通过增加机器的方式来搭建真正意义上的流量隔离。
第二节_3-2-6 第三章第二节第六张图.png
这种方案需要为要灰度的服务搭建一套网络隔离、资源独立的环境,在其中部署服务的灰度版本。由于与正式环境隔离,正式环境中的其他服务无法访问到需要灰度的服务,所以需要在灰度环境中冗余部署这些线上服务,以便整个调用链路正常进行流量转发。此外,注册中心等一些其他依赖的中间件组件也需要冗余部署在灰度环境中,保证微服务之间的可见性问题,确保获取的节点IP地址只属于当前的网络环境。

这个方案一般用于企业的测试、预发开发环境的搭建,对于线上灰度发布引流的场景来说其灵活性不够。况且,微服务多版本的存在在微服务架构中是家常便饭,需要为这些业务场景采用堆机器的方式来维护多套灰度环境。如果您的应用数目过多的情况下,会造成运维、机器成本过大,成本和代价远超收益;如果应用数目很小,就两三个应用,这个方式还是很方便的,可以接受的。

逻辑环境隔离

另一种方案是构建逻辑上的环境隔离,我们只需部署服务的灰度版本,流量在调用链路上流转时,由流经的网关、各个中间件以及各个微服务来识别灰度流量,并动态转发至对应服务的灰度版本。如下图:
第二节_3-2-7 第三章第二节第七张图.png
上图可以很好展示这种方案的效果,我们用不同的颜色来表示不同版本的灰度流量,可以看出无论是微服务网关还是微服务本身都需要识别流量,根据治理规则做出动态决策。当服务版本发生变化时,这个调用链路的转发也会实时改变。相比于利用机器搭建的灰度环境,这种方案不仅可以节省大量的机器成本和运维人力,而且可以帮助开发者实时快速的对线上流量进行精细化的全链路控制。

那么全链路灰度具体是如何实现呢?通过上面的讨论,我们需要解决以下问题:

  1. 链路上各个组件和服务能够根据请求流量特征进行动态路由
  2. 需要对服务下的所有节点进行分组,能够区分版本
  3. 需要对流量进行灰度标识、版本标识
  4. 需要识别出不同版本的灰度流量

接下来,会介绍解决上述问题需要用到的技术。

标签路由

标签路由通过对服务下所有节点按照标签名和标签值不同进行分组,使得订阅该服务节点信息的服务消费端可以按需访问该服务的某个分组,即所有节点的一个子集。服务消费端可以使用服务提供者节点上的任何标签信息,根据所选标签的实际含义,消费端可以将标签路由应用到更多的业务场景中。
第二节_3-2-8 第三章第二节第八张图.png

节点打标

那么如何给服务节点添加不同的标签呢?在如今火热的云原生技术推动下,大多数业务都在积极进行容器化改造之旅。这里,我就以容器化的应用为例,介绍在使用Kubernetes Service作为服务发现和使用比较流行的Nacos注册中心这两种场景下如何对服务Workload进行节点打标。

在使用Kubernetes Service作为服务发现的业务系统中,服务提供者通过向ApiServer提交Service资源完成服务暴露,服务消费端监听与该Service资源下关联的Endpoint资源,从Endpoint资源中获取关联的业务Pod资源,读取上面的Labels数据并作为该节点的元数据信息。所以,我们只要在业务应用描述资源Deployment中的Pod模板中为节点添加标签即可。
第二节_3-2-9 第三章第二节第九张图.png
在使用Nacos作为服务发现的业务系统中,一般是需要业务根据其使用的微服务框架来决定打标方式。如果Java应用使用的Spring Cloud微服务开发框架,我们可以为业务容器添加对应的环境变量来完成标签的添加操作。比如我们希望为节点添加版本灰度标,那么为业务容器添加spring.cloud.nacos.discovery.metadata.version=gray,这样框架向Nacos注册该节点时会为其添加一个标签verison=gray
第二节_3-2-10 第三章第二节第十张图.png

流量染色

请求链路上各个组件如何识别出不同的灰度流量?答案就是流量染色,为请求流量添加不同灰度标识来方便区分。我们可以在请求的源头上对流量进行染色,前端在发起请求时根据用户信息或者平台信息的不同对流量进行打标。如果前端无法做到,我们也可以在微服务网关上对匹配特定路由规则的请求动态添加流量标识。此外,流量在链路中流经灰度节点时,如果请求信息中不含有灰度标识,需要自动为其染色,接下来流量就可以在后续的流转过程中优先访问服务的灰度版本。

分布式链路追踪

还有一个很重要的问题是如何保证灰度标识能够在链路中一直传递下去呢?如果在请求源头染色,那么请求经过网关时,网关作为代理会将请求原封不动的转发给入口服务,除非开发者在网关的路由策略中实施请求内容修改策略。接着,请求流量会从入口服务开始调用下一个微服务,会根据业务代码逻辑形成新的调用请求,那么我们如何将灰度标识添加到这个新的调用请求,从而可以在链路中传递下去呢?

从单体架构演进到分布式微服务架构,服务之间调用从同一个线程中方法调用变为从本地进程的服务调用远端进程中服务,并且远端服务可能以多副本形式部署,以至于一条请求流经的节点是不可预知的、不确定的,而且其中每一跳的调用都有可能因为网络故障或服务故障而出错。分布式链路追踪技术对大型分布式系统中请求调用链路进行详细记录,核心思想就是通过一个全局唯一的traceid和每一条的spanid来记录请求链路所经过的节点以及请求耗时,其中traceid是需要整个链路传递的。

借助于分布式链路追踪思想,我们也可以传递一些自定义信息,比如灰度标识。业界常见的分布式链路追踪产品都支持链路传递用户自定义的数据,其数据处理流程如下图所示:
第二节_3-2-11 第三章第二节第十一张图.png
3-2-11 第三章第二节第十一张图

逻辑环境隔离

首先,需要支持动态路由功能,对于Spring Cloud、Dubbo开发框架,可以对出口流量实现自定义Filter,在该Filter中完成流量识别以及标签路由。同时需要借助分布式链路追踪技术完成流量标识链路传递以及流量自动染色。此外,需要引入一个中心化的流量治理平台,方便各个业务线的开发者定义自己的全链路灰度规则。如下图所示:

第二节_3-2-12 第三章第二节第十二张图.png
3-2-12 第三章第二节第十二张图

实现全链路灰度的能力,无论是成本还是技术复杂度都是比较高的,以及后期的维护、扩展都是非常大的成本。

当然您可以选择阿里云MSE服务治理产品,该产品就是一款基于Java Agent实现的无侵入式企业生产级服务治理产品,您不需要修改任何一行业务代码,即可拥有不限于全链路灰度的治理能力,并且支持近5年内所有的Spring Boot、Spring Cloud和Dubbo。

MSE 微服务治理全链路灰度

全链路灰度作为MSE服务治理专业版中的拳头功能,具备以下六大特点

  • 可通过定制规则引入精细化流量

除了简单地按照比例进行流量引入外,我们还支持 Spring Cloud与 Dubbo 流量按规则引入,Spring Cloud流量可根据请求的cookie、header、param参数或随机百分比引入流量,Dubbo流量可按照服务、方法、参数来引入
image.png

image.png

  • 全链路隔离流量泳道
  1. 通过设置流量规则对所需流量进行’染色’,‘染色’流量会路由到灰度机器。
    2) 灰度流量携带灰度标往下游传递,形成灰度专属环境流量泳道,无灰度环境应用会默认选择未打标的基线环境。
  • 端到端的稳定基线环境

未打标的应用属于基线稳定版本的应用,即稳定的线上环境。当我们将发布对应的灰度版本代码,然后可以配置规则定向引入特定的线上流量,控制灰度代码的风险。

  • 流量一键动态切流

流量规则定制后,可根据需求进行一键停启,增删改查,实时生效。灰度引流更便捷。

  • 低成本接入,基于Java Agent技术实现无需修改一行业务代码

MSE 微服务治理能力基于Java Agent字节码增强的技术实现,无缝支持市面上近5年的所有Spring Cloud 和 Dubbo 的版本,用户不用改一行代码就可以使用,不需要改变业务的现有架构,随时可上可下,没有绑定。只需开启MSE微服务治理专业版,在线配置,实时生效。

  • 具备无损上下线能力,使得发布更加丝滑

应用开启 MSE 微服务治理后就具备无损上下线能力,大流量下的发布、回滚、扩容、缩容等场景,均能保证流量无损。

RPC流量的全链路灰度方案

基于消息队列RocketMQ的全链路灰度方案

详细可以了解MSE服务治理的帮助文档 《基于消息队列RocketMQ版实现全链路灰度》
架构图_4-2-23 第四章第二节第二十三张图.jpg

3-2-15 第三章第二节第十五张图
技术方案如下:
第二节_3-2-16 第三章第二节第十六张图.png
3-2-16 第三章第二节第十六张图

MSE 服务治理以无侵入的方式提供了全链路灰度、离群实例摘除、金丝雀发布、微服务治理流量可观测等核心能力,以更经济的方式、更高效的路径帮助我们的系统在云上快速构建起完整微服务治理体系