灰度发布
现在对于稳定性的要求越来越高,同时在维护的应用中有一个正在进行迁移,需要采取一些措施来实现平稳升级和迁移。采用灰度发布是一个可行的方案。

什么是灰度发布

百度百科上的解释是这样的

灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

从上面的解释,不难看出,灰度发布包括三个要点:

  1. 分别部署A,B两个版本
  2. 选择测试用户并逐渐切流
  3. 将测试用户切到B版本,不能影响到政策用户对A版本的使用

灰度发布主要的作用也显而易见:

  1. 降低发布带来的影响。即使在日常和预发环境进行充分测试,但也没人能保证线上一定是好的。测试环境和线上毕竟不是完全一样,测试也不可能覆盖所有地方
  2. 通过新老版本对比,验证新版本带来的效果。

    怎么做灰度发布

    在开始介绍灰度发布之前,先看一下没有灰度的发布流程是怎么样的:

    直接替换部署

    如果变更是兼容的:
    通常的发布方式是底层服务先进行发布,然后上层应用跟着进行发布。前端CDN比较特殊,会在web层之前进行非覆盖式发布(CDN 本质是一个OSS文件,每次发布CDN版本+1,并保留之前的版本)。web层带着最新的CDN版本在最后发布
    灰度发布 - 图1
    一般应用通常会引入配置服务器来管理一些配置项,可以实现不重新发布应用的情况下做一些变更。比如切换CDN版本号来实现前端发布
    灰度发布 - 图2

    滚动部署和蓝绿部署

    现在应用基本都会有多台机器和负载均衡。发布方式则会变成每次发布一部分机器,从负载均衡上去掉并更新,更新完成之后负载均衡重新接入这部分机器。这就是滚动部署。
    蓝绿部署也是类似。区别在于,先升级一部分,然后通过负载均衡把流量导入到新服务,最后升级另一部机器并重新接入负载均衡。
    灰度发布 - 图3

    不兼容变更

    上面讨论的都是兼容的变更,但有时候会需要做一些 breaking change ,这个时候就要前后端同时发布,否则会有一段时间服务不可用。如果是用最原始的部署方式,web层带着最新的前端代码(或CDN版本号)一起发布就好了。但是在有了配置服务器之后,虽然多数场景提供了便利,但对这种场景却不是很友好。前端发布通过配置服务器的方式独立于后端的发布,两次发布会有短暂的服务不可用的时间
    实现不兼容变更的平滑发布,常见做法是引入版本号,一部分机器升级到 v2 版本,/v1/api 和 /v2/api 共存。前端应用使用新版本 /v2/api 的接口。在发布完成之后视情况去掉 v1 版本相关的代码。

    灰度发布的分类

    结合上面灰度发布的定义和在不做灰度发布时的部署方式,对于怎么做灰度发布基本能想象它的脉络。核心就在于先升级部分机器并根据一定条件把部分用户引导到新服务。
    在介绍具体做法前,先整体的分一下类:从灰度的方式划分,可以分为物理灰度和逻辑灰度。从灰度的范围又可以分为功能级别灰度和应用级别灰度。

    从灰度方式划分

    物理灰度做法比较简单,其实就是根据机器维度进行灰度。和上文提到的直接部署一样,机器部署应用之后,流量均匀的打到新老版本上。好处是这种方式很简单,不需要做额外的事情。缺点上面也提到了,对于不兼容的变更不适用
    灰度发布 - 图4
    逻辑灰度相比物理灰度,变化的点只有把均匀的流量变成根据一定逻辑切换流量。
    灰度发布 - 图5
    逻辑灰度可以更精确的控制流量,如果出现问题,回滚也方便,流量切走就是了。对于有诉求要做更进一步的AB测试同学,更是必须要做的事。但这种方式在灰度结束之后,往往需要清除灰度相关的代码
    1. if(灰度条件成立){
    2. 灰度服务
    3. }else{
    4. 稳定服务
    5. }
    如果灰度的服务涉及到多个功能点,类似的if else就会多了起来。如果灰度的条件要处理一些用户信息,代码会更多(比如对某人群进行灰度,会额外增加人群判断的逻辑)。在结束之后删除这些代码并发布也是一件麻烦事,如果留到下次需求再去掉,人的惰性,不求有功但求无过的心理,维护人员调整等等原因都可能会增加项目维护的难度。为了缓解这个问题,可以把灰度的逻辑单独抽出来:
    灰度发布 - 图6
    这样一来,灰度结束的时候就只用删掉 if else 而没有灰度的逻辑。
    还有另一种更加棘手的情况。在灰度的过程中,有另一个 feature 需要发布的话怎么处理,是赶紧结束上一个的灰度,全量发布还是一起发上去同时灰度?feature 还好处理,如果出现了线上问题,急需 hotfix 呢。这些都是需要思考的问题

    从灰度范围划分

    功能级别的灰度很好理解,就是对单个功能进行灰度。和上面提到的方式一致。可能遇到的麻烦点也是可能存在多个功能同时需要灰度,并且灰度标签不一致。通过提取灰度条件SDK 的方式可以缓解
    应用级别的灰度服务端可以通过 v1,v2这种版本号标识即可。前端会相对特殊,因为前端是依赖于服务端的,虽然同时存在多个前端版本很容易(无非是多个CDN版本共存)。但出于同一次发布和同一次灰度关联,”今日事今日毕” 的原则,在发布流程上前端会多一个 betaVersion 版本,区别于正式的 version 版本。先发布 betaVersion,并切流验证,验证无误之后发布正式版本,切流完成。
    灰度发布 - 图7

    总结

    灰度的流程大概可以分为:
    制定灰度策略 -> 筛选用户 -> 部署系统 -> 观察灰度情况 -> 增大/降低灰度比例 -> 灰度结束 -> 删除灰度代码
    灰度发布有诸多好处,但也不是没有成本。但如果能够因地制宜的选择灰度发布的方式,可以充分享受灰度的好处而将成本降到最低