乐趣区

关于前端:一文读懂蓝绿发布AB-测试和金丝雀发布的优缺点

作者 | 扬少

背景

目前,业界曾经总结出了几种常见的服务公布策略来解决版本升级过程中带来的流量有损问题。本文首先会对这些广泛的公布策略进行简略的原理解析,最初联合阿里云的云原生网关对这些公布策略进行实际。

公布策略

被业界宽泛采纳的服务公布策略包含蓝绿公布、A/B 测试以及金丝雀公布。

1、蓝绿公布

蓝绿公布须要对服务的新版本进行冗余部署,个别新版本的机器规格和数量与旧版本保持一致,相当于该服务有两套完全相同的部署环境,只不过此时只有旧版本在对外提供服务,新版本作为热备。当服务进行版本升级时,咱们只需将流量全副切换到新版本即可,旧版本作为热备。因为冗余部署的缘故,所以不用放心新版本的资源不够。如果新版本上线后呈现重大的程序 BUG,那么咱们只需将流量全副切回至旧版本,大大缩短故障复原的工夫。待新版本实现 BUG 修复并重新部署之后,再将旧版本的流量切换到新版本。

蓝绿公布通过应用额定的机器资源来解决服务公布期间的不可用问题,当服务新版本呈现故障时,也能够疾速将流量切回旧版本。

如图,某服务旧版本为 v1,对新版本 v2 进行冗余部署。版本升级时,将现有流量全副切换为新版本 v2。

当新版本 v2 存在程序 BUG 或者产生故障时,能够疾速切回旧版本 v1。

蓝绿部署的长处:
1、部署构造简略,运维不便;
2、服务降级过程操作简略,周期短。

蓝绿部署的毛病:
1、资源冗余,须要部署两套生产环境;
2、新版本故障影响范畴大。

2、A/B 测试

相比于蓝绿公布的流量切换形式,A/B 测试基于用户申请的元信息将流量路由到新版本,这是一种基于申请内容匹配的灰度公布策略。只有匹配特定规定的申请才会被引流到新版本,常见的做法包含基于 Http Header 和 Cookie。基于 Http Header 形式的例子,例如 User-Agent 的值为 Android 的申请(来自安卓零碎的申请)能够拜访新版本,其余零碎依然拜访旧版本。基于 Cookie 形式的例子,Cookie 中通常蕴含具备业务语义的用户信息,例如普通用户能够拜访新版本,VIP 用户依然拜访旧版本。

如图,某服务以后版本为 v1,当初新版本 v2 要上线。心愿安卓用户能够尝鲜新性能,其余零碎用户放弃不变。

通过在监控平台察看旧版本与新版本的成功率、RT 比照,当新版本整体服务预期后,即可将所有申请切换到新版本 v2,最初为了节俭资源,能够逐渐下线到旧版本 v1。

A/B 测试的长处:
1、能够对特定的申请或者用户提供服务新版本,新版本故障影响范畴小;
2、须要构建齐备的监控平台,用于比照不同版本之间申请状态的差别。

A/B 测试的毛病:
1、依然存在资源冗余,因为无奈精确评估申请容量;
2、公布周期长。

3、金丝雀公布

在蓝绿公布中,因为存在流量整体切换,所以须要依照原服务占用的机器规模为新版本克隆一套环境,相当于要求原来 1 倍的机器资源。在 A/B 测试中,只有可能预估中匹配特定规定的申请规模,咱们能够按需为新版本调配额定的机器资源。相比于前两种公布策略,金丝雀公布的思维则是将大量的申请引流到新版本上,因而部署新版本服务只需极小数的机器。验证新版本合乎预期后,逐渐调整流量权重比例,使得流量缓缓从老版本迁徙至新版本,期间能够依据设置的流量比例,对新版本服务进行扩容,同时对老版本服务进行缩容,使得底层资源失去最大化利用。

如图,某服务以后版本为 v1,当初新版本 v2 要上线。为确保流量在服务降级过程中安稳无损,采纳金丝雀公布计划,逐渐将流量从老版本迁徙至新版本。

金丝雀公布的长处:
1、按比例将流量无差别地导向新版本,新版本故障影响范畴小;
2、公布期间逐渐对新版本扩容,同时对老版本缩容,资源利用率高。

金丝雀公布的毛病:
1、流量无差别地导向新版本,可能会影响重要用户的体验;
2、公布周期长。

实际

接下来,咱们会基于阿里云的容器运维平台 ACK 以及 MSE 云原生网关对以上介绍的三种公布策略进行实际。这里咱们采纳最简略的业务架构来展现,即一个云原生网关、一个后端服务(响应中返回以后版本信息)和注册核心。注册核心决定了业务架构中服务发现形式,咱们会别离以 K8s 容器服务和 Nacos 两种服务发现机制来实际不同的公布策略。

1、前提条件

• 创立了阿里云容器运维平台 ACK
• 创立了 MSE 云原生网关
• 创立了 MSE 注册核心 Nacos(服务发现形式为 Nacos 时须要)

2、服务发现形式:K8s 容器服务

在这个例子中,咱们应用 K8s 原生的服务发现形式,即通过申明式 Service API 资源将后端服务注册到 CoreDNS。例子中的后端服务提供一个查问以后版本的接口 /version,并且以后版本为 v1。云原生网关深度集成 ACK,能够实时动静地从 ACK 集群中获取服务信息,不便通过云原生网关将该后端服务裸露给内部用户。

业务架构如下图:

1、部署
将以下资源(Service 和 Deployment)利用到 ACK 集群,实现后端服务的部署和公布,以后利用版本为 v1。

apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  ports:
  - port: 8080
    protocol: TCP
  selector:
    app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: httpbin
      version: v1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
      - image: specialyang/spring-cloud-httpbin-k8s:v1
        imagePullPolicy: Always
        name: spring-cloud-httpbin-k8s
        ports:
        - containerPort: 8080

在云原生网关的服务治理 -> 起源治理中,增加指标 ACK 集群。

在服务治理中导入要裸露给云原生网关的服务 httpbin。

在 httpbin 服务的策略配置中增加服务版本 v1,留神须要抉择对应的标签来筛选出 v1 版本的节点,因为目前咱们只部署了 v1 版本,所以 v1 版本的节点数占总实例数 100%。

在路由治理中为该服务创立一条路由规定,从而将服务裸露给内部用户。httpbin 服务裸露的 api 的 path 为 /version,申请转发至服务 httpbin 的 v1 版本。

执行以下脚本测试申请的响应后果。

for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1

2、蓝绿部署
蓝绿部署须要依照服务以后版本所占用的资源情况为服务新版本申请同样的资源规格,部署结束之后将流量整体切换到服务新版本。

利用 K8s 的申明式 API 资源部署 httpbin 服务的新版本 v2,正本数同样是 3。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: httpbin
      version: v2
  template:
    metadata:
      labels:
        app: httpbin
        version: v2
    spec:
      containers:
      - image: specialyang/spring-cloud-httpbin-k8s:v2
        imagePullPolicy: Always
        name: spring-cloud-httpbin-k8s
        ports:
        - containerPort: 8080

在 httpbin 服务的策略配置中增加服务版本 v2,留神须要抉择对应的标签来筛选出 v2 版本的节点,集群中当初 v1 和 v2 版本的节点数统一,所以各占 50%。

当初,咱们开始利用蓝绿公布的思维将流量从 v1 整体切换至 v2,仅须要之前批改下面创立的路由规定中指标服务即可。

执行以下脚本测试申请的响应后果。

for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
version: v2
version: v2
version: v2
version: v2
version: v2
version: v2
version: v2
version: v2
version: v2
version: v2

当初咱们发现拜访 api 资源 /version 的申请的流量曾经全副从 v1 切换至 v2。

3、A/ B 测试
A/B 测试基于用户申请的元信息将流量路由到新版本,换句话说,就是能够依据申请内容来动静路由。举个例子,咱们心愿 User-Agent 的值为 Android 的申请(来自安卓零碎的申请)能够拜访新版本,其余零碎依然拜访旧版本。

咱们依然利用下面实际中部署的 httpbin 的 v1,v2 的 deployment。此外,须要创立两条路由规定:
• 匹配 path 为 /version 的申请拜访服务版本 v1
• 匹配 path 为 /version,且 User-Agent 头部含有 Android 的申请拜访服务版本 v2

留神相比 version 路由规定,version-v2 的路由规定中须要减少申请头匹配规定。

通过以下脚本测试 A/B test 的成果。

// user agent 中不含有 android
curl ${GATEWAY_EXTERNAL_IP}/version
version: v1
// user agent 中含有 android
curl -H "User-Agent: Mozilla/5.0 (Linux; Android 4.0.3)" ${GATEWAY_EXTERNAL_IP}/version
version: v2

能够看出,以后申请会依照起源的操作系统对流量进行分流。

4、金丝雀公布
金丝雀公布容许引流一小部分流量到服务新版本,待验证通过后,逐渐调大流量,直至切流结束,期间可随同着新版本的扩容,旧版本的缩容操作,达到资源利用率最大化。

在金丝雀公布策略中,服务新版本的正本初始部署数无需与原始保持一致。仅需放弃资源始终满足灰度流量,所以咱们将新版本的正本数调为 1,能够在服务策略中服务版本模块看到以后各版本节点数的占比状况。

革除掉其余公布策略遗留的路由规定,咱们新创建一条路由规定,在指标服务中依照权重将流量转发至新旧版本。

其中,指标服务须要配置两个目的地,httpbin 的 v1 和 v2 版本,并设置对应的流量比。

通过以下脚本测试金丝雀公布的成果。

for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
version: v1
version: v1
version: v1
version: v1
version: v1
version: v2
version: v1
version: v2
version: v1
version: v1

在以上测试后果中,能够发现 10 个申请中,有 2 个是拜访的新版本 v2,其流量比的确合乎冀望的 8:2。

在实在业务场景中,新版本验证结束后,就能够持续调大拜访新版本的流量权重,期间留神对新版本扩容,按需对旧版本缩容。

3、服务发现形式:Nacos 注册核心

Kubernetes 平台为容器化利用带来了动静弹性,放慢了利用交付过程,进步了底层资源的利用率,但在服务发现能力上,相比其余支流注册核心 Nacos、Consul 等,其性能完整性、可用性上略显有余。因而,即便大部分业务利用曾经迁徙至 Kubernetes 运维平台,但依然抉择为业务保留了原始的注册核心。

针对这种业务场景,咱们额定举例当应用 Nacos 注册核心时,如何为服务进行蓝绿公布、A/B 测试和金丝雀公布。例子中的后端服务提供一个查问以后版本的接口 /version,并且以后版本为 v1。云原生网关深度集成 MSE Nacos 注册核心,能够实时动静地从 Nacos 实例中获取服务信息,不便通过云原生网关将该后端服务裸露给内部用户。

业务架构如下图:

1、部署
将以下资源(Deployment)利用到 ACK 集群,实现后端服务的部署,并将服务公布到 Nacos 注册核心,以后利用版本为 v1。须要留神以下几点:

1、该 yaml 资源中变量 ${NACOS_SERVER_ADDRESS}须要替换为你的 MSE Nacos 地址,如果和网关在一个 VPC,那么内网域名即可;否则,你须要配置公网域名。

2、在 K8s Service 服务发现中,Pod 中 Labels 信息可看做是节点的元数据信息。而在 Nacos 注册核心中,节点的元数据信息取决于服务注册时携带的信息。在 Spring Cloud 框架中,通过环境变量 spring.cloud.nacos.discovery.metadata.xxx 无侵入式为节点增加元数据信息,在该例子中,咱们以 version 作为版本标用来辨别不同版本的节点。因而,须要为业务容器增加环境变量

spring.cloud.nacos.discovery.metadata.version=v1。apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      containers:
      - image: specialyang/spring-cloud-httpbin-nacos:v1
        imagePullPolicy: Always
        name: spring-cloud-httpbin-nacos
        ports:
        - containerPort: 8080
        env:
        - name: spring.cloud.nacos.discovery.server-addr
          value: ${NACOS_SERVER_ADDRESS}
        - name: spring.cloud.nacos.discovery.metadata.version
          value: v1

在云原生网关的服务治理 -> 起源治理中,增加指标 MSE Nacos 注册核心集群。

在服务治理中导入要裸露给云原生网关的服务 httpbin,留神服务起源抉择 MSE Nacos 注册核心。

与 K8s Service 服务发现的例子一样,在策略配置中增加服务版本 v1,标签名和标签值能够抉择为咱们在 httpbin 服务注册时增加的元数据信息 version=v1。之后配置路由匹配 path 为 /version 的申请转发至 httpbin 服务的 v1 版本。

执行以下脚本测试申请的响应后果。

for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1
version: v1

2、蓝绿部署

其公布策略如下图所示:

部署 httpbin 服务的新版本 v2,留神注册核心与下面保持一致,同时为业务容器减少环境变量 spring.cloud.nacos.discovery.metadata.version=v2,业务利用启动时会向指定 Nacos 注册服务,同时携带上用户自定义的元数据信息。云原生网关能够利用这些元数据信息来对节点辨别不同的版本。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v2
spec:
  replicas: 3
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      containers:
      - image: specialyang/spring-cloud-httpbin-nacos:v2
        imagePullPolicy: Always
        name: spring-cloud-httpbin-nacos
        ports:
        - containerPort: 8080
        env:
        - name: spring.cloud.nacos.discovery.server-addr
          value: ${NACOS_SERVER_ADDRESS}
        - name: spring.cloud.nacos.discovery.metadata.version
          value: v2

与 K8s Service 的例子中蓝绿公布操作一样,在 httpbin 服务的策略配置中增加服务版本 v2,而后将路由规定中的指标服务 httpbin 的 v1 版本批改为 v2 版本,公布胜利之后,查看申请后果全副为 version: v2。

3、A/B 测试
其公布策略如下图所示:

咱们同样用之前的例子,User-Agent 的值为 Android 的申请(来自安卓零碎的申请)能够拜访新版本,其余零碎依然拜访旧版本。波及的路由规定的操作、与验证形式与 K8s Service 的例子统一。

4、金丝雀公布
其公布策略如下图所示:

同样,波及的路由规定的操作、与验证形式与 K8s Service 的例子统一。

总结

本文对常见的公布策略进行了简略介绍和原理解析,并以图文并茂的形式对每个公布策略进行了具体探讨,总结如下:

• 蓝绿公布:简略了解就是流量切换,根据热备的思维,冗余部署服务新版本。
• A/B 测试:简略了解就是依据申请内容(header、cookie)将申请流量路由到服务的不同版本。
• 金丝雀公布:是一种基于流量比例的公布策略,部署一个或者一小批新版本的服务,将大量(比方 1%)的申请引流到新版本,逐渐调大流量比重,直到所有用户流量都被切换新版本为止。

云原生网关以托管的形式来作为您的流量入口,提供了丰盛的流量治理能力,反对多种服务发现形式,如 K8s Service、Nacos、Eurake、ECS 和域名,并以对立的模型反对了服务版本以及灰度公布能力。在下面的实际中,能够发现两种服务发现形式仅仅是元数据信息所处的地位不同,但服务版本治理以及路由规定中的灰度公布模型都是统一的,您能够轻松学会为不同服务发现形式的服务进行灰度公布,确保版本升级过程中平滑无损。

最初,对微服务畛域感兴趣的同学,能够钉钉搜寻群号 34754806 退出用户群交换、答疑。

退出移动版