深入剖析全链路灰度技术内幕(2)
发布时间:2021-12-16 点击数:990
03
1
物理环境隔离
逻辑环境隔离
接下来,会介绍解决上述问题需要用到的技术。
标签路由通过对服务下所有节点按照标签名和标签值不同进行分组,使得订阅该服务节点信息的服务消费端可以按需访问该服务的某个分组,即所有节点的一个子集。服务消费端可以使用服务提供者节点上的任何标签信息,根据所选标签的实际含义,消费端可以将标签路由应用到更多的业务场景中。
那么如何给服务节点添加不同的标签呢?在如今火热的云原生技术推动下,大多数业务都在积极进行容器化改造之旅。这里,我就以容器化的应用为例,介绍在使用 Kubernetes Service 作为服务发现和使用比较流行的 Nacos 注册中心这两种场景下如何对服务 Workload 进行节点打标。
请求链路上各个组件如何识别出不同的灰度流量?答案就是流量染色,为请求流量添加不同灰度标识来方便区分。我们可以在请求的源头上对流量进行染色,前端在发起请求时根据用户信息或者平台信息的不同对流量进行打标。如果前端无法做到,我们也可以在微服务网关上对匹配特定路由规则的请求动态添加流量标识。此外,流量在链路中流经灰度节点时,如果请求信息中不含有灰度标识,需要自动为其染色,接下来流量就可以在后续的流转过程中优先访问服务的灰度版本。
还有一个很重要的问题是如何保证灰度标识能够在链路中一直传递下去呢?如果在请求源头染色,那么请求经过网关时,网关作为代理会将请求原封不动的转发给入口服务,除非开发者在网关的路由策略中实施请求内容修改策略。接着,请求流量会从入口服务开始调用下一个微服务,会根据业务代码逻辑形成新的调用请求,那么我们如何将灰度标识添加到这个新的调用请求,从而可以在链路中传递下去呢?
从单体架构演进到分布式微服务架构,服务之间调用从同一个线程中方法调用变为从本地进程的服务调用远端进程中服务,并且远端服务可能以多副本形式部署,以至于一条请求流经的节点是不可预知的、不确定的,而且其中每一跳的调用都有可能因为网络故障或服务故障而出错。分布式链路追踪技术对大型分布式系统中请求调用链路进行详细记录,核心思想就是通过一个全局唯一的 traceid 和每一条的 spanid 来记录请求链路所经过的节点以及请求耗时,其中 traceid 是需要整个链路传递的。
上面我们详细介绍了实现全链路灰度所需要的几种技术,如果想为现有的业务接入全链路灰度能力,不可避免的需要为业务使用的开发框架 SDK 进行改造。首先,需要支持动态路由功能,对于 Spring Cloud、Dubbo 开发框架,可以对出口流量实现自定义 Filter,在该 Filter 中完成流量识别以及标签路由。同时需要借助分布式链路追踪技术完成流量标识链路传递以及流量自动染色。此外,需要引入一个中心化的流量治理平台,方便各个业务线的开发者定义自己的全链路灰度规则。基于 SDK 实现方式的图例如下:
基于 SDK 方式的弊端在于需要业务进行 SDK 版本升级,甚至会涉及到业务代码的变动。企业内部各个微服务虽然使用同一种开发框架,但很难保证框架版本是一致的,所以不得不为每一个版本维护一份全链路灰度的代码。业务代码与 SDK 代码紧耦合,SDK 版本迭代会触发业务不必要的发版变更,对业务的侵入性比较强。
下表是三种方式对比,从多个方面进行了对比。
3
流量入口:网关
在分布式应用中,作为流量入口的网关是不可或缺的。在全链路灰度场景中,就要求微服务网关具备丰富的流量治理能力,支持服务多版本路由,支持对特定路由规则上的请求进行动态打标。对于入口服务可见性问题,网关需要支持多种服务发现方式。安全性问题上,网关作为集群对外的入口可以对所有请求流量进行认证鉴权,保障业务系统不被非法流量入侵。
全链路灰度的解决方案
Cloud Native
如何在实际业务场景中去快速落地全链路灰度呢?目前,主要有两种解决思路,基于物理环境隔离和基于逻辑环境隔离。
1
物理环境隔离
物理环境隔离,顾名思义,通过增加机器的方式来搭建真正意义上的流量隔离。
这种方案需要为要灰度的服务搭建一套网络隔离、资源独立的环境,在其中部署服务的灰度版本。由于与正式环境隔离,正式环境中的其他服务无法访问到需要灰度的服务,所以需要在灰度环境中冗余部署这些线上服务,以便整个调用链路正常进行流量转发。此外,注册中心等一些其他依赖的中间件组件也需要冗余部署在灰度环境中,保证微服务之间的可见性问题,确保获取的节点 IP 地址只属于当前的网络环境。
逻辑环境隔离
- 链路上各个组件和服务能够根据请求流量特征进行动态路由
- 需要对服务下的所有节点进行分组,能够区分版本
- 需要对流量进行灰度标识、版本标识
- 需要识别出不同版本的灰度流量
接下来,会介绍解决上述问题需要用到的技术。
标签路由
标签路由通过对服务下所有节点按照标签名和标签值不同进行分组,使得订阅该服务节点信息的服务消费端可以按需访问该服务的某个分组,即所有节点的一个子集。服务消费端可以使用服务提供者节点上的任何标签信息,根据所选标签的实际含义,消费端可以将标签路由应用到更多的业务场景中。
节点打标
那么如何给服务节点添加不同的标签呢?在如今火热的云原生技术推动下,大多数业务都在积极进行容器化改造之旅。这里,我就以容器化的应用为例,介绍在使用 Kubernetes Service 作为服务发现和使用比较流行的 Nacos 注册中心这两种场景下如何对服务 Workload 进行节点打标。
在使用 Nacos 作为服务发现的业务系统中,一般是需要业务根据其使用的微服务框架来决定打标方式。如果 Java 应用使用的 Spring Cloud 微服务开发框架,我们可以为业务容器添加对应的环境变量来完成标签的添加操作。比如我们希望为节点添加版本灰度标,那么为业务容器添加`spring.cloud.nacos.discovery.metadata.version=gray`,这样框架向Nacos注册该节点时会为其添加一个标签`verison=gray`。
流量染色
请求链路上各个组件如何识别出不同的灰度流量?答案就是流量染色,为请求流量添加不同灰度标识来方便区分。我们可以在请求的源头上对流量进行染色,前端在发起请求时根据用户信息或者平台信息的不同对流量进行打标。如果前端无法做到,我们也可以在微服务网关上对匹配特定路由规则的请求动态添加流量标识。此外,流量在链路中流经灰度节点时,如果请求信息中不含有灰度标识,需要自动为其染色,接下来流量就可以在后续的流转过程中优先访问服务的灰度版本。
分布式链路追踪
还有一个很重要的问题是如何保证灰度标识能够在链路中一直传递下去呢?如果在请求源头染色,那么请求经过网关时,网关作为代理会将请求原封不动的转发给入口服务,除非开发者在网关的路由策略中实施请求内容修改策略。接着,请求流量会从入口服务开始调用下一个微服务,会根据业务代码逻辑形成新的调用请求,那么我们如何将灰度标识添加到这个新的调用请求,从而可以在链路中传递下去呢?
从单体架构演进到分布式微服务架构,服务之间调用从同一个线程中方法调用变为从本地进程的服务调用远端进程中服务,并且远端服务可能以多副本形式部署,以至于一条请求流经的节点是不可预知的、不确定的,而且其中每一跳的调用都有可能因为网络故障或服务故障而出错。分布式链路追踪技术对大型分布式系统中请求调用链路进行详细记录,核心思想就是通过一个全局唯一的 traceid 和每一条的 spanid 来记录请求链路所经过的节点以及请求耗时,其中 traceid 是需要整个链路传递的。
逻辑环境隔离——基于 SDK
上面我们详细介绍了实现全链路灰度所需要的几种技术,如果想为现有的业务接入全链路灰度能力,不可避免的需要为业务使用的开发框架 SDK 进行改造。首先,需要支持动态路由功能,对于 Spring Cloud、Dubbo 开发框架,可以对出口流量实现自定义 Filter,在该 Filter 中完成流量识别以及标签路由。同时需要借助分布式链路追踪技术完成流量标识链路传递以及流量自动染色。此外,需要引入一个中心化的流量治理平台,方便各个业务线的开发者定义自己的全链路灰度规则。基于 SDK 实现方式的图例如下:
逻辑环境隔离——基于 Java Agent
基于 SDK 方式的弊端在于需要业务进行 SDK 版本升级,甚至会涉及到业务代码的变动。企业内部各个微服务虽然使用同一种开发框架,但很难保证框架版本是一致的,所以不得不为每一个版本维护一份全链路灰度的代码。业务代码与 SDK 代码紧耦合,SDK 版本迭代会触发业务不必要的发版变更,对业务的侵入性比较强。
逻辑环境隔离——基于 Service Mesh
三种方式对比
下表是三种方式对比,从多个方面进行了对比。
-
如果您倾向于使用无侵入式的 Java Agent 的方式,但又担心自建带来的稳定性问题,您可以选择 MSE 微服务治理产品,该产品是阿里巴巴内部多年在微服务治理领域的沉淀的产出,经历了各种大促考验。
- 如果您倾向于使用语言无关、无侵入式的 Service Mesh 的方式,但又担心自建带来的稳定性问题,您可以选择阿里云 ASM 产品,相比开源 Istio,在功能性、稳定性和安全性都有很大的提升。
3
流量入口:网关
在分布式应用中,作为流量入口的网关是不可或缺的。在全链路灰度场景中,就要求微服务网关具备丰富的流量治理能力,支持服务多版本路由,支持对特定路由规则上的请求进行动态打标。对于入口服务可见性问题,网关需要支持多种服务发现方式。安全性问题上,网关作为集群对外的入口可以对所有请求流量进行认证鉴权,保障业务系统不被非法流量入侵。
上一篇:深入剖析全链路灰度技术内幕(3) 下一篇:深入剖析全链路灰度技术内幕(1)