在一篇文章Lossyflowproblem中阅读蓝绿发布、A/B测试和金丝雀发布的优缺点。本文将首先分析这些常见的发布策略的简单原理,最后结合阿里云的云原生网关来实践这些发布策略。发布策略业界广泛采用的服务发布策略包括蓝绿发布、A/B测试和金丝雀发布。1.蓝绿发布蓝绿发布需要对新版本服务进行冗余部署。一般情况下,新版本的机器规格和数量与旧版本一致,即服务有两个相同的部署环境,但此时只有旧版本对外提供服务,新版本作为热备。当服务版本升级时,我们只需要将所有流量切换到新版本,旧版本作为双机热备。由于冗余部署,无需担心新版本资源耗尽。如果新版本上线后出现严重的程序bug,我们只需要将所有流量切换回旧版本即可,大大缩短了恢复时间。新版本完成BUG修复并重新部署后,旧版本的流量切换到新版本。蓝绿发布通过使用额外的机器资源解决服务发布时的不可用问题。当新版本服务出现故障时,也可以快速将流量切换回旧版本。如图所示,某服务旧版本为v1,冗余部署新版本v2。版本升级时,所有现有流量将切换到新版本v2。当新版本v2出现程序错误或故障时,可以快速切换回旧版本v1。蓝绿部署的优势:1、部署结构简单,运维方便;2、服务升级流程操作简单,周期短。蓝绿部署的缺点:1、资源冗余需要部署两套生产环境;2、新版本故障影响较大。2.A/B测试相对于蓝绿发布的流量切换方式,A/B测试是根据用户请求的元信息将流量路由到新版本。这是一种基于请求内容匹配的灰度发布策略。只有符合特定规则的请求才会被转移到新版本,常见的做法包括基于HttpHeader和Cookie。基于HttpHeader方法的例子,比如User-Agent的值为Android,则请求(Android系统的请求)可以访问新版本,而其他系统仍然访问旧版本。以cookie方法为例,cookie中通常包含有业务语义的用户信息,比如普通用户可以访问新版本,VIP用户仍然访问旧版本。如图,某服务当前版本为v1,现在新版本v2上线。希望安卓用户可以试用新功能,其他系统用户不变。通过在监控平台上观察新旧版本的成功率和RT对比,当新版本整体服务预期时,可以将所有请求切换到新版本v2。最后,为了节省资源,可以逐步下线到老版本v1。A/B测试的优点:1、可以为特定的请求或用户提供新版本的服务,新版本失败的影响小;2.需要搭建完整的监控平台,比较不同版本之间请求状态的差异。A/B测试的缺点:1、仍然存在资源冗余,因为无法准确评估请求容量;2、发布周期长。3.蓝绿发布中发布金丝雀。由于流量的整体切换,需要根据原服务占用的机器规模,为新版本克隆一个环境,相当于需要原先两倍的机器资源。在A/B测试中,只要我们能够预估匹配特定规则的请求大小,就可以按需为新版本分配额外的机器资源。与前两种发布策略相比,金丝雀发布的思路是将少量请求导流到新版本,因此部署新版本服务只需要极少量的机器。在验证新版本符合预期后,逐步调整流量权重比例,让流量慢慢从旧版本迁移到新版本。在此期间,可以按照设定的流量比例扩容新版服务,缩容旧版服务。底层资源最大化。如图,某服务当前版本为v1,现在新版本v2上线。为保证服务升级过程中流量稳定无损,采用金丝雀发布方案,逐步将流量从旧版本迁移到新版本。金丝雀发布的优点:1、流量按比例导向新版本,新版本故障范围小;2.发布期间,新版本逐渐扩容,老版本同时缩减,资源利用率高。金丝雀发布的缺点:1、流量被无差别地导向新版本,可能影响重要用户的体验;2、发布周期长。实践接下来我们将基于阿里云的容器运维平台ACK和MSE云原生网关来实践上述三种发布策略。这里我们用最简单的业务架构来展示,即一个云原生网关、一个后端服务(在响应中返回当前版本信息)和一个注册中心。注册中心决定了业务架构中的服务发现方式。我们将使用K8s容器服务和Nacos两种服务发现机制来实践不同的发布策略。1.前提?创建阿里云容器运维平台ACK?创建MSE云原生网关?创建MSE注册中心Nacos(服务发现方式为Nacos时需要)2.服务发现方式:本例中为K8s容器服务,我们使用K8s原生的服务发现方式,即通过声明式ServiceAPI资源向CoreDNS注册后端服务。示例中的后端服务提供了一个接口/version来查询当前版本,当前版本为v1。云原生网关深度集成ACK,可以实时从ACK集群中动态获取服务信息,方便后端服务通过云原生网关暴露给外部用户。业务架构如下:1.Deployment将以下资源(Service和Deployment)应用到ACK集群中,完成后端服务的部署和发布。当前应用程序版本为v1。apiVersion:v1kind:Servicemetadata:name:httpbinspec:ports:-port:8080protocol:TCPselector:app:httpbin---apiVersion:apps/v1kind:Deploymentmetadata:name:httpbin-v1spec:replicas:3选择器:matchLabels:app:httpbin版本:v1模板:元数据:标签:app:httpbin版本:v1规范:容器:-图像:specialyang/spring-cloud-httpbin-k8s:v1imagePullPolicy:始终名称:spring-cloud-httpbin-k8s端口:-containerPort:8080在云原生网关的服务管理->源管理中,添加目标ACK集群。在服务管理中导入要暴露给云原生网关的服务httpbin。将服务版本v1添加到httpbin服务的策略配置中。注意需要选择对应的label来过滤掉v1版本的节点。因为我们目前只部署了v1版本,所以v1版本的节点数占实例总数的100%。在路由管理中为该服务创建路由规则,从而将服务暴露给外部用户。httpbin服务暴露的API路径为/version,请求转发到httpbin服务的v1版本。执行以下脚本测试请求的响应结果。对于我在{1..10}中;卷曲“${GATEWAY_EXTERNAL_IP}/version”;回声“”;doneversion:v1version:v1version:v1version:v1version:v1version:v1version:v1version:v1version:v1version:v12,蓝绿部署蓝绿部署需要根据占用的资源为新版本服务申请相同的资源规范根据服务的当前版本。部署完成后,流量会整体切换到新版本的服务上。使用K8s声明式API资源部署httpbin服务的新版本v2,副本数也是3。apiVersion:apps/v1kind:Deploymentmetadata:name:httpbin-v2spec:replicas:3选择器:matchLabels:app:httpbinversion:v2template:metadata:labels:app:httpbinversion:v2spec:containers:-image:specialyang/spring-cloud-httpbin-k8s:v2imagePullPolicy:Alwaysname:spring-cloud-httpbin-k8sports:-containerPort:8080在httpbin服务的策略配置中添加服务版本v2。注意需要选择对应的label过滤掉v2版本的节点,v1和v2版本集群的节点数量是一样的,所以各占50%。现在,我们开始使用蓝绿发布的思路,将流量从v1整体切换到v2。我们只需要修改上面创建的路由规则中的目标服务即可。执行以下脚本测试请求的响应结果。对于我在{1..10}中;卷曲“${GATEWAY_EXTERNAL_IP}/version”;回声“”;doneversion:v2version:v2version:v2version:v2version:v2version:v2version:v2version:v2version:v2version:v2现在我们发现访问api资源/版本请求的流量已经全部从v1切换到v2了。3.A/B测试A/B测试根据用户请求的元信息将流量路由到新版本。也就是说,可以根据请求内容动态更新。路由。比如我们希望User-Agent的值是Android请求(来自Android系统的请求)可以访问新版本,其他系统仍然访问旧版本。我们仍然使用上面实践中部署的httpbin的v1和v2部署。另外需要创建两条路由规则:?匹配路径为/version的请求访问服务版本v1?匹配路径为/version的请求访问服务版本v2,User-Agent头中包含Android请求访问服务版本v2注意,相对于版本路由规则,版本-v2路由规则需要增加请求头匹配规则。使用以下脚本测试A/B测试的效果。//useragent不包含androidcurl${GATEWAY_EXTERNAL_IP}/versionversion:v1//useragent包含androidcurl-H"User-Agent:Mozilla/5.0(Linux;Android4.0.3)"${GATEWAY_EXTERNAL_IP}/versionversion:v2它可以看出,当前请求会根据来源的操作系统来划分流量。4.金丝雀发布金丝雀发布允许少量流量导流到新版本的服务。验证通过后,逐渐增加流量,直到切流完成。在此期间可以扩充新版本,缩减旧版本。操作以最大限度地利用资源。在金丝雀发布策略中,新版本服务的初始部署副本数不需要与原来一致。只需要时刻保持资源满足灰度流量即可,所以我们将新版本的副本数调整为1,可以在服务版本中看到每个版本当前节点数的比例服务策略中的模块。清除其他发布策略遗留的路由规则后,我们新建一条路由规则,根据目标服务中的权重,将流量转发到新旧版本。其中,目标服务需要配置两个目的地,即httpbin的v1和v2版本,并设置相应的流量比例。使用以下脚本测试金丝雀发布效果。对于我在{1..10}中;卷曲“${GATEWAY_EXTERNAL_IP}/version”;回声“”;doneversion:v1version:v1version:v1version:v1version:v1version:v2version:v1version:v2version:v1version:v1在上面的测试结果中可以发现,10个请求中,有2个访问的是新版本v2,其流量比例确实达到预期的8:2。在实际业务场景中,新版本验证通过后,可以继续增加访问新版本的流量权重。期间注意根据需要扩容新版本,缩容旧版本。3、服务发现方式:Nacos注册中心的Kubernetes平台为容器化应用带来了动态的灵活性,加快了应用的交付过程,提高了底层资源的利用率。但在服务发现能力方面,与其他主流注册中心Nacos、Consul等相比,在功能完整性和易用性方面略有不足。因此,即使大部分业务应用已经迁移到Kubernetes运维平台,仍然选择为业务保留原有的注册中心。针对这个业务场景,我们再举例说明如何使用Nacos注册中心对服务进行蓝绿发布、A/B测试和金丝雀发布。示例中的后端服务提供了一个接口/version来查询当前版本,当前版本为v1。云原生网关与MSENacos注册中心深度集成,可实时动态获取Nacos实例的服务信息,方便通过云原生网关将后端服务暴露给外部用户。业务架构如下:1.Deployment将以下资源(Deployment)应用到ACK集群,完成后端服务的部署,并将服务发布到Nacos注册中心。当前应用程序版本为v1。需要注意以下几点:1.yaml资源中的变量${NACOS_SERVER_ADDRESS}需要替换成你的MSENacos地址。如果和网关在同一个VPC,那么内网域名就可以了;否则,您需要配置公共域名。2、在K8sService服务发现中,Pod中的Labels信息可以看作是节点的元数据信息。在Nacos注册中心中,节点的元数据信息取决于服务注册时携带的信息。在SpringCloud框架中,通过环境变量spring.cloud.nacos.discovery.metadata.xxx,以非侵入方式为节点添加元数据信息。在这个例子中,我们使用version作为版本标签来区分不同版本的节点。因此需要在业务容器中添加环境变量spring.cloud.nacos.discovery.metadata.version=v1。apiVersion:apps/v1kind:Deploymentmetadata:name:httpbin-v1spec:replicas:3选择器:matchLabels:app:httpbintemplate:metadata:labels:app:httpbinspec:containers:-image:specialyang/spring-cloud-httpbin-nacos:v1imagePullPolicy:始终名称:spring-cloud-httpbin-nacos端口:-容器端口:8080env:-名称:spring.cloud.nacos.discovery.server-addr值:${NACOS_SERVER_ADDRESS}-名称:spring.cloud.nacos。discovery.metadata.versionvalue:v1在云原生网关的服务管理->源码管理中添加目标MSENacos注册中心集群。在服务管理中导入要暴露给云原生网关的服务httpbin,注意服务源选择MSENacos注册中心。和K8sService服务发现例子一样,在policy配置中添加服务版本v1,tag名称和tag值可以选择我们在注册httpbin服务时添加的元数据信息version=v1。然后配置路由,将匹配/version路径的请求转发到httpbin服务的v1版本。执行以下脚本测试请求的响应结果。对于我在{1..10}中;卷曲“${GATEWAY_EXTERNAL_IP}/version”;回声“”;doneversion:v1version:v1version:v1version:v1version:v1version:v1version:v1version:v1version:v1version:v12,蓝绿部署其发布策略如下图所示:部署httpbin服务的新版本v2。注意注册中心和上面一致。同时在业务容器中添加环境变量spring.cloud.nacos.discovery.metadata.version=v2。业务应用启动时,会向指定的Nacos注册服务,同时携带用户自定义的元数据信息。云原生网关可以使用这些元数据信息来区分不同版本的节点。apiVersion:apps/v1kind:Deploymentmetadata:name:httpbin-v2spec:replicas:3选择器:matchLabels:app:httpbintemplate:metadata:labels:app:httpbinspec:containers:-image:specialyang/spring-cloud-httpbin-nacos:v2imagePullPolicy:始终名称:spring-cloud-httpbin-nacos端口:-容器端口:8080env:-名称:spring.cloud.nacos.discovery.server-addr值:${NACOS_SERVER_ADDRESS}-名称:spring.cloud.nacos。discovery.metadata.versionvalue:v2与K8sService示例中的蓝绿发布操作相同,在httpbin服务的policy配置中添加服务版本v2,然后修改目标服务httpbin中的v1版本路由规则到v2版本,发布成功后查看请求结果是否都是version:v2。3、A/B测试的发布策略如下图所示:我们还是用前面的例子,User-Agent的值为Androidrequests(来自Android系统的请求)canbeaccessthenewversion,其他系统仍然访问旧版本。涉及的路由规则的操作和验证方式与K8sService示例一致。4.金丝雀发布的发布策略如下图所示:同样,涉及的路由规则的操作和验证方式与K8sService示例一致。小结本文对常见的发布策略进行了简单的介绍和分析,并图文并茂地对每种发布策略进行了详细的讨论。总结如下:?蓝绿发布:简单理解就是流量切换。新版本服务的冗余部署。?A/B测试:简单理解就是根据请求内容(header、cookie)将请求流量路由到不同版本的服务。?金丝雀发布:是一种基于流量比例的发布策略。部署一个或一小批新版本服务,将少量(比如1%)的请求分流到新版本,逐渐增加流量比例,直到所有用户流量都切换到新版本为止。云原生网关托管作为您的流量入口,提供丰富的流量管理能力,支持K8sService、Nacos、Eurake、ECS、域名等多种服务发现方式,支持统一模型的服务版本以及灰度发布能力。在上面的实践中可以发现,两种服务发现方式只是元数据信息的位置不同,但是路由规则中的服务版本管理和灰度发布模型是一致的,可以轻松学会发现针对不同的服务该模式下的服务采用灰度发布方式,保证版本平滑无损升级。最后,对微服务领域感兴趣的同学可以加入用户群,在钉钉搜索群号34754806进行交流和答疑。
