服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

一分钟精华速览

全链路灰度发布是指在微服务体系架构中,应用的新、旧版本间平滑过渡的一种发布方式。由于微服务之间依赖关系错综复杂,一次发布可能会涉及多个服务升级,所以在发布前进行小规模的生产环境验证,让新版本的应用实例来承接、处理限定规模或范围的业务流量,能最大限度控制发布上线风险,保证业务连续性。本文详细解读微盟全链路灰度平台实践难点、解决思路及使用场景,还原其服务百万商家客户的全过程。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

作者介绍

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

微盟基础架构团队技术专家——戴明智 TakinTalks 社区专家团成员,SpringFramework、Apache Skywalking 社区 Contributor,个人博客阅读量 100w+。2019 年入职微盟,基础架构团队技术专家,参与并负责微盟全链路灰度平台的建设,经历了整个全链路灰度平台从 0 到 1 的全过程。

温馨提醒:本文约 6000 字,预计花费 12 分钟阅读。

「TakinTalks稳定性社区」公众号后台回复 “交流” 进入读者交流群;回复“0412”获取课件资料;

背景

随着微盟业务的高速发展,商家系统的迭代频率和质量要求也在变高。在多环境推出之前,业务研发团队进行产品并行迭代开发时,发布系统存在两个非常显著的问题——

1)只有一套标准的 QA 测试环境,多版本并行测试困难。

即当两个版本涉及到同一个应用,则第二个版本就会因为环境占用,而无法开始测试。这样就严重影响了测试和发布计划。

2)微盟业务线众多且存在相互依赖,发布过程中出现问题时需要回滚,灵活度和掌控力需进一步提升。

微盟业务线众多且存在相互依赖,而微盟所有应用均采用微服务模式。以上导致微盟一次发布迭代涉及的应用数众多,需要上下游人力协调进行发布,且发布过程中出现问题时需要挨个回滚。灵活度和掌控力需进一步提升。微盟最终选择引入全链路灰度发布来解决以上发布问题。当然,在近两年的实践和落地中,我们也遇到了不少挑战。我将详细分享微盟全链路灰度在落地过程中的一些难点和解决思路。

一、什么是全链路灰度?

1.1 全链路灰度

微服务全链路灰度是单体架构下灰度发布的衍生物,它的实施成本及复杂度更高。在单体架构下,一次迭代只会涉及到一个服务。但在微服务架构下,则需要链路上的多个服务同时进入灰度环境。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

如图所示,单体架构下灰度发布只涉及服务 A,则只需要对服务 A 进行灰度。而微服务架构下,一个用户请求链路上会涉及多个服务,此时则需要服务 A 和服务 C 同时进入灰度环境。因此,微服务架构下的灰度发布也被称之为“全链路灰度”。

1.2 全链路灰度有哪些挑战

全链路灰度我认为需要克服以下问题。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

1)资源隔离:要做独立的灰度环境,而这个独立的灰度环境会涉及到很多资源,包括 K8S 资源、消息队列、注册中心等,如何对这些资源制定合适的隔离方案?

2)流量标签传递:我们要保证灰度流量在整个灰度环境里流转,那么灰度流量标签如何做到全链路的传递?

3)多组件支持:全链路灰度会涉及到大量组件和应用,尤其微盟的组件多、每个组件的版本多、框架也很多,且没有统一标准。如何用一个合理的方式支持这些组件快速接入?

4)数据一致性:不管什么样的灰度方案,都需要确保业务数据一致性,以及灰度策略一致性。这些数据一致性如何得到保证?

二、如何应对全链路灰度的挑战?

2.1 挑战 1:资源如何隔离

2.1.1 资源隔离需要关注的指标

资源隔离要考虑很多方面,包括稳定性、实施复杂度、成本和性能。

稳定性是做隔离的一个重要指标,灰度须对生产环境的影响越小越好。且实施灰度方案时,不能影响生产调用的性能。复杂度高代表着其维护成本高,也越容易出错,因此复杂度是越低越好。成本方面亦然。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

2.1.2 K8S 资源隔离

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

一般会有三种方案,独立集群部署、同一集群标签区分、同一集群 node 隔离。

1)独立集群部署,不推荐。因为独立集群部署相当于再部署了一套环境,尽管稳定性可能会高一些,但它的复杂度很高,成本也很高。除此之外还要解决跨集群访问的问题。整体性价比不高。

2)同一套物理集群,通过标签区分容器里的资源。它的稳定性相对来说会低一点,但是整体比较简单,成本也低,性能也没有影响。导致其稳定性低的原因,是灰度的所有 POD 和生产的所有 POD 共享同一套物理集群,当灰度和生产同时拉起时,就会导致 Node 的 CPU 和内存都飙高,从而影响生产。我们曾经就出现过,所有灰度同时拉起时,被调度到了同一台物理机上,影响到了那台 Node 机器上的生产环境的应用。

3)同一套物理集群,Node 做隔离。即在同一套 K8S 集群里,Node 机器通过标签、POD 亲和性等机制,来保证灰度的 POD 优先调度到灰度的机器上,稳定性也因此得到提升。因为独立出来的 Node 机器,需要设置冗余机器,所以其成本是居于方案一和方案二之间。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

以上是 K8S 资源隔离后的一张架构图。从这里可以看到 Ingress、Service、POD 都是通过灰度的标签,做了逻辑上的隔离。至于 Node 上是否要做隔离,可以根据具体的情况而定。我个人推荐 Node 做隔离,灰度的规模足够大是需要隔离的。虽然会冗余 20%~25%的 Node 机器,但是它带来的稳定性收益是很高的。

2.1.3 注册中⼼隔离

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

注册中心的隔离主要考虑 RPC 的调用,即要保证 RPC 调用的稳定性,以及能够区分 RPC 的流量。

注册中心的隔离方式也有两种,独立集群部署和不区分集群。

1)独立集群部署。如果注册中心用的是 ZK,就单独为灰度去部署一套 ZK。这样它的稳定性会高一些,但复杂度也会相应较高。因为需要同时监听两套注册中心上的服务提供方,还需要识别注册中心是灰度的还是生产的,再去做调用,导致它的成本也会比较高。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

(独立集群模式,生产环境和灰度环境分开注册)2)不区分集群。稳定性相对会低一些。因为如果使用同一套集群,那么在做灰度的过程中,到某一阶段时,作业中心的负载会比较高。比如,如果用 ZK,那么因为多了一些灰度的生产者和消费者,就会导致 Z-node 数量上升,节点激增,CPU 也会上涨。此时就很可能会影响到生产上正常的服务订阅和注册。当然,若不区分集群,则复杂度和成本会比较低。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

(使用同一集群模式,用标签区分实例)微盟使用了单一集群的方案,为了避免 ZK 负载过高,对 ZK 做了扩容。

2.1.4 消息队列隔离

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

全链路灰度涉及到核心三个调用,正常的 Http 调用,还有 RPC 和消息,所以消息的隔离也很重要。

消息队列的隔离也有两种方式。第一种是 Topic 级别的隔离。第二种是不隔离,消费方自行过滤。

1)Topic 级别的隔离:也可以认为是一种物理上的隔离。因为每一个 Topic 对应的就是物理的 Partition,不会因为生产环境的延迟导致灰度环境的延迟,而灰度环境也不会影响到生产环境,所以它的稳定性会比较高。为什么复杂度也会比较高?因为对一个 Topic 进行灰度,需要生产方把消息同时生产到两个 Topic,消费方也需要同时消费两个 Topic 中的消息,这样就比较复杂。

同时,一个 Topic 的生产方会有多个,当一个生产方需要灰度时,其他不必要做灰度的生产方,也必须把自己的消息同时发布到灰度环境中去,这样就会对其他生产方带来额外的负担。而新建一个 Topic 就意味着要多占一些分区,所以其成本也相应会比较高。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

2)不做 Topic 级别的隔离:只在消息生产时携带灰度标签,消费方在消费时,根据消息里的标签自行过滤,消费方只消费其对应环境的消息。比如,当生产环境的消费方拉到一条灰度消息时,直接不处理然后回应 ZK 就结束。同理,当灰度环境的消费方拉到生产消息,也不做处理。这样不会带来额外的物理成本,所以成本也相对较低,性能不会受影响。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

基于稳定性及监控考虑,微盟目前采用了独立 Topic 的方案。

2.2 挑战 2:流量标签如何传递

之前我们介绍过微盟在分布式链路的场景下,整个链路的 Trace ID 传递(支撑百万商户、千亿级调用:微盟如何通过链路设计降本 40%?)。流量标签的传递基本上可以借鉴这套流程。

全链路灰度主要传递的场景有两个,一个是跨线程,一个是跨进程。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

跨线程的传递:可以借助阿里开源的 TTL 完成传递。也可以借助 Skywalking 提供的 SDK 对线程进行封装,这样也可以完成。

跨进程的传递:跨进程的传递主要是找到流量标签传递用的载体。Http 的请求可以通过 Header 设定一个固定的 Key 来传递流量标签。RPC 可以通 Double 本身提供的 RPC Contest 来传递。而消息的传递,可以通过在消息中添加 Attachment,或者设计一个完整的消息协议,在消息的 Header 中添加流量标签,以此来完成流量标签的传递。

2.3 挑战 3:如何快速支持多组件

我们需要对很多 SDK 做灰度能力的支持,而微盟的 SDK 特别多,且同一个 SDK 在不同的业务部门还有不同的版本,所以在全链路灰度时碰到了比较多的问题。以 Double 为例,Double 2.7 中提供了标签路由的功能,基于这个功能去做灰度调用会很简单,但是微盟只有部分业务组用了这个版本,大部分还停留在 2.6 的版本,此时,如何快速让这些组件都拥有灰度的能力就是一个很大的问题。

一般会有两种方案,一种是 SDK 开发封装,一种是 JavaAgent。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

1)SDK 开发封装:基于每一个组件不同的 SDK,不同的版本,去做一层封装,然后去提供灰度能力的支持。它的优点是开发比较简单,排查问题也比较方便。因为在本地就可以调试,研发可以自行排查问题。然而,因为微盟的组件实在太多,这意味着需要开发的 SDK 会特别多,且后期还要去维护升级每一个 SDK,推广速度也会很慢,因此并不适合微盟。

2)JavaAgent:这种方式的好处是无侵入,可以把所有的 SDK 的增强逻辑都维护在同一个 Java 中,推广也会比较容易。Agent 在微盟应用比较广泛,因此有一个专门的管理平台,在管理平台中可以对 Agent 做灰度推广,比如先推广到 200 个应用,然后逐步递增到 300 个、400 个等等,逐步覆盖到所有应用。这样的好处是维护方便,但相对于 SDK 的开发,Agent 的开发难度更高,且因为它难以调试,导致一旦灰度链路中 Agent 出问题,就必须我们协同业务组去定位和解决。同时,还会有很多隐藏问题,比如,两个或者多个 Agent 之间可能会触发相互干扰,此时定位会比较难,这也是其缺点之一。

2.4 挑战 4:如何克服数据一致性

数据一致性是灰度场景下所有人都会碰到的共性问题,而且是比较麻烦的问题。

2.4.1 什么是数据一致性

假设在灰度环境中,有服务 A 和服务 C 两个应用,当前执行的策略是“店铺 ID=a,b,c”。流量进入灰度环境,假设此时通过中心化的策略平台下发了一个新的策略,那么服务 A 和服务 C 之间可能会有延迟,即两个应用不一定能同时接到新下发的策略,且这个延时的值是不确定的。此时会导致两个服务执行两个不同的策略,服务 A 执行的策略还是“店铺 ID=a,b,c”,而服务 C 执行的策略变成了“店铺 ID=a,b”。假设此时有一股流量“店铺 ID=c”进来,此时流量会进入服务 A 的灰度环境,以及服务 C 的基准环境,这时流量就会出现问题。这个就是策略一致性问题。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

2.4.2 如何解决数据一致性问题

1)方案一:下发策略时添加生效时间戳,减少网络延迟带来的影响。

也就是,让服务 A 和服务 C 约定到达某个时间后同时生效。但是这种方式并不能保障强一致性,因为即使是统一的生效时间戳,不同机器上的时间也可能是不一致的。且会受到计时策略的影响,比如到期计时是每一毫秒判断一次,还是每秒判断一次。所以这种方案并不能保证数据的强一致性。

2)方案二:先下发策略,策略带有版本号,确认所有应用接收到策略后,通过入口应用启用指定版本的策略。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

如图所示,在做策略调整时,服务 A 和服务 C 会同时存在两个版本的策略。假设这个灰度环境的流量入口应用是服务 A,就可以通知服务 A 启用 V2 版本的流量,确保服务 A 这条链路上涉及到的应用都收到 V2 版本的策略,这样就能解决策略一致性问题。而业务数据一致性的问题,则需要业务部门自行解决,全链路灰度平台很难解决应用中业务数据的一致性,所以在这里不做展开。

三、全链路灰度在微盟的落地效果如何?

3.1 整体架构

基于对微盟业务的思考,我们做了业务关键字的能力,这里不在于技术的实现,而在于这个诉求本身如何满足。微盟全链路灰度平台的整体架构分为 4 部分,交互层、业务层、策略层和路由层。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

交互层主要就是 UI 界面,即产品入口。通过交互层可以进行创建环境、开始灰度、调整策略、灰度转正等等一系列的操作。所有的请求都会被业务层,也就是灰度调度平台接收到,然后在灰度调度平台中做一系列操作。最核心的就是灰度策略和灰度转正。所有的灰度策略都会被策略层处理,再按照特定的格式推送到路由层,最后由路由层去完成整个灰度流量的路由。

3.2 灰度生命周期

微盟设计了一个比较完整且复杂的灰度生命周期。如图所示。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

一个灰度环境在平台上从创建到结束,要经过以上几个流程。初始状态下,需要把这个灰度环境内涉及的所有应用加进来后去创建环境。确认准备工作完成后,可以开始灰度的操作,此时环境就会流转到灰度状态。在灰度状态下,可以做策略编辑,通过策略编辑去实现逐步放大流量的功能。对应文章片头提到的,在微盟 SaaS 业务中,头部商家的流量占了大部分,通过这种策略编辑就可以先让少量商家承接灰度版本,然后再逐步放大流量,等流量到一定比例后再逐步引入头部商家,这样就保证了发布是足够安全的。灰度状态下,在流量逐步划拨的过程中如果完全没有问题,那么就可以发起一次转正,把灰度版本完全转换成基准版本。如果验证有问题且不可修复的,也可以快速下线,把灰度占用的资源释放掉。

3.3 实践场景

3.3.1 实践场景 1:快速创建灰度环境

图中展示的是一个已创建完毕的环境。在创建环境过程中,只需要关注两点,一个是哪些应用需要参与到这次灰度中,另一个是灰度的策略是什么。录入这些信息后,即可开始灰度操作。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

3.3.2 实践场景 2:配置流量策略

配置流量策略目前已经支持比较复杂的流量策略。按条件灰度,包含 Http 的 Header、域名的 Host、Per-stream,以及域名中某些特定值的灰度,这些都已能实现。按比例灰度,对某一个应用控制固定比例(如 20%、30%)的流量进入灰度,这个目前也支持。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

在配置流量策略的过程中,有一个需要大家关注的问题。流量调整过程中,需要对底层所用的资源做扩容,其中很核心的是需要对 POD 做扩容,且 POD 扩容应该要发生在把流量调度到灰度环境之前。因此平台需要允许在每一次配置策略时,同步设置扩容比例,以此来保证它不会被突然的流量增长打崩。

3.3.3 实践场景 3:灰度推进到蓝绿状态

在微盟有一个强制要求,无论哪一次灰度,都必须在蓝绿状态做停留。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

蓝绿状态在平台上的体现,就是在策略编辑时,要进入全流量灰度的状态,也就是所有的流量都进入灰度的状态。之所以这么设计,是因为很多问题在 20%、50%甚至 80%流量状态下,是无法得到完全验证的。灰度必须要经历一次完整的流量高峰并验证没有问题,才可以认为是安全的。而至于停留多久,平台不做限制,由业务部门视业务情况自行决定。

3.3.4 实践场景 4:灰度转正,灰度发布完成

蓝绿状态验证完成后,此时可以发起灰度转正。前面我们提到了资源隔离,灰度转正的作用就是释放这部分隔离的资源,把灰度版本发布到生产环境中去。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

而此前,业务部门去执行一次大版本的发布,是需要考虑流量损失、服务编排等等一系列问题的。通过这个灰度转正流程,可以确保流量无损,也无需业务方考虑服务编排。灰度转正后才会把流量切回生产,以此来保证整个过程中对业务不造成影响。

3.3.5 实践场景 5:流量回切,灰度下线

在灰度的过程中可能会碰到一些异常的问题,如果问题比较严重,则可以利用流量回切能力,一键把流量快速切到生产环境。然后再选择灰度下线,或者在灰度环境下继续做验证和修复。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

3.4 落地效果

QA 测试环境从 1 套到 80+套,支持多部门并行测试。各业务团队可以快速在平台上隔离出一套独立的环境,来解决开篇提到的并行测试环境占用的问题。闲时会有 40+环境并行,忙时有高达 80+的环境同步运行。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

内部覆盖率超过 85%。目前应用基本完成接入灰度,覆盖率超过 85%。

发布效率大幅提升。使用灰度发布后,没有出现过因为发布导致线上流量受损。同时发布效率大幅提升,即使在大规模迭代的情况下,也没有出现过通宵发布。

四、未来规划

4.1 监控能力提升

目前微盟全链路灰度平台已经能完全区分灰度链路和生产链路,但其监控能力与公司现有的监控能力相比,还有一些短板,比如 POD 的监控、指标、告警等,接下来都要重点去加强。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

(微盟灰度平台链路监控页面)

4.2 开放能力

随着全链路灰度平台的推广,我们收到了越来越多的诉求,比如小程序发布平台、APP 管理平台、微盟特有生态系统盟链等等,也希望接入到灰度平台中来,以此来降低对商家造成的影响。

服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

因此我们需要去做扩展能力,来支撑这些诉求。目前我们已经提供了两套扩展机制,帮助外部生态系统接入平台,当然这部分工作也正在优化迭代中。(全文完)

Q&A

1、灰度环境是不是单独一套更好还是怎么样?

2、消息队列隔离,为什么没有考虑不同的消费组?

3、Redis 怎么进行灰度?4、怎么控制灰度的影响范围?

更多详细内容,欢迎点击“阅读全文”,观看完整版解答!

本文来自投稿,不代表TakinTalks稳定性技术交流平台立场,如若转载,请联系原作者。

(0)
上一篇 2023年4月20日 下午6:05
下一篇 2023年5月5日 上午8:30

相关推荐

发表评论

登录后才能评论