现代发布技术的原理和实践

一、前言

根据2017年的DevOps发展报告,高效能组织和低效能组织在软件交付的效率上有数量级上的差异。技术组织的软件交付能力是一种综合能力,涉及众多环节,其中发布是尤为重要的环节。

作为技术人员,大家可能听说过“滚动发布”和“蓝绿发布”等术语,但是很多人并不清楚这些术语背后的原理。本文试图总结当前主流的发布策略,每个的优劣,适用性,让开发人员特别是架构师对现代发布技术有一个更为清晰全面的认识,让大家能够根据自己的企业上下文,对发布策略做出正确的选型和实践。

二、单服务器组发布

先解释下单服务器组的概念,早先我们机器资源比较紧张,不像现在云计算和虚拟化(包括容器技术)这么发达,所以应用机器基本是预先静态分配好的(一般由运维负责分配),原来应用A住在这n台机器上,那么下次升级发布的应用A也住在这n台机器上,所以称为单服务器组发布方式。

2.1 蛮力发布

如下图所示,这种发布方式比较简单粗暴,有点像我们传统的软件升级方式,主要靠手工完成,先将老版本V1全部下掉,再将新版本发到机器上去。这种方式会引入服务中断(停机),在开发测试环境是可行的,但对于生产环境发布,其会直接影响用户的使用体验,这种方式一般是不建议的。

reckless before

发布前

reckless after

发布后

优势和适用场合

优势:

  • 简单成本低

不足:

  • 服务中断用户受影响,出了问题回退也慢

适用场合:

  • 开发测试环境
  • 非关键应用(用户影响面小)
  • 初创公司什么都缺,找夜深人静用户访问量小的时间干

流量模式

reckless traffic model

蛮力发布会引入服务中断时间,图片来自附录7.1

2.2 金丝雀发布(单服务器组)

在蛮力发布基础上的一种简单改进发布方式,目前仍然是不少成长型技术组织的主流发布方式。单服务器组下的金丝雀发布的简化步骤如下图所示:

canary one group before

发布前

canary one group first

先发一台金丝雀

canary one group after

全部发完

实践要点

  1. 金丝雀发布一般先发1台,或者一个小比例,例如2%的服务器,主要做流量验证用,也称为金丝雀(Canary)测试(国内常称灰度测试)。以前旷工开矿下矿洞前,先会放一只金丝雀进去探是否有有毒气体,看金丝雀能否活下来,金丝雀发布由此得名。简单的金丝雀测试一般通过手工测试验证,复杂的金丝雀测试需要比较完善的监控基础设施配合,通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回退的依据。
  2. 如果金丝测试通过,则把剩余的V1版本全部升级为V2版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败。

canary

金丝雀

优势和适用场合

优势:

  • 用户体验影响小,金丝雀发布过程出现问题只影响少量用户

不足:

  • 发布自动化程度不够,发布期间可引发服务中断

适用场合:

  • 对新版本功能或性能缺乏足够信心
  • 用户体验要求较高的网站业务场景
  • 缺乏足够的自动化发布工具研发能力

流量模式

canary one group traffic

少量金丝雀先接受流量,再全量发布,图片来自附录7.1

2.3 滚动式发布(单服务器组)

在金丝雀发布基础上的进一步优化改进,是一种自动化程度较高的发布方式,用户体验比较平滑,是目前成熟型技术组织所采用的主流发布方式。单服务器组下的滚动发布的简化步骤如下图所示:

rolling update one group before

发布前

rolling update one group first

发布中,先发一台金丝雀

rolling update one group middle

发布中,再发若干台

rolling update one group after

直到全部发完

实践要点

  1. 滚动式发布一般先发1台,或者一个小比例,如2%服务器,主要做流量验证用,类似金丝雀(Canary)测试。
  2. 滚动式发布需要比较复杂的发布工具和智能LB,支持平滑的版本替换和流量拉入拉出。
  3. 每次发布时,先将老版本V1流量从LB上摘除,然后清除老版本,发新版本V2,再将LB流量接入新版本。这样可以尽量保证用户体验不受影响。
  4. 一次滚动式发布一般由若干个发布批次组成,每批的数量一般是可以配置的(可以通过发布模板定义)。例如第一批1台(金丝雀),第二批10%,第三批50%,第四批100%。每个批次之间留观察间隔,通过手工验证或监控反馈确保没有问题再发下一批次,所以总体上滚动式发布过程是比较缓慢的(其中金丝雀的时间一般会比后续批次更长,比如金丝雀10分钟,后续间隔2分钟)。
  5. 回退是发布的逆过程,将新版本流量从LB上摘除,清除新版本,发老版本,再将LB流量接入老版本。和发布过程一样,回退过程一般也比较慢的。
  6. 滚动式发布国外术语通常叫Rolling Update Deployment。

优势和适用场合

优势:

  • 用户体验影响小,体验较平滑

不足:

  • 发布和回退时间比较缓慢
  • 发布工具比较复杂,LB需要平滑的流量摘除和拉入能力

适用场合:

  • 用户体验不能中断的网站业务场景
  • 有一定的复杂发布工具研发能力;

流量模式

rolling udpate one group traffic

滚动式发布,流量平滑过渡,图片来自附录7.1

三、双服务器组发布

随着云计算和虚拟化技术的成熟,特别是容器等轻量级虚拟化技术的引入,计算资源受限和申请缓慢问题已经逐步解决,可以做到弹性按需分配。为一次发布分配两组服务器,一组运行现有的V1老版本,一组运行待上线的V2新版本,再通过LB切换流量方式完成发布,这就是所谓的双服务器组发布方式。

3.1 蓝绿发布(双服务器组)

蓝绿发布仅适用于双服务器组发布,可以认为是对蛮力发布的一种简单优化发布方式。简化过程如下图所示:

blue green two groups before

发布前

blue green two groups after

发布后

实践要点

  1. V1版本称为蓝组,V2版本称为绿组,发布时通过LB一次性将流量从蓝组直接切换到绿组,不经过金丝雀和滚动发布,蓝绿发布由此得名;
  2. 出现问题回退也很直接,通过LB直接将流量切回蓝组。
  3. 发布初步成功后,蓝组机器一般不直接回收,而是留一个待观察期,视具体情况观察期的时间可长可短,观察期过后确认发布无问题,则可以回收蓝组机器。

优势和适用场合

优势:

  • 升级切换和回退速度非常快

不足:

  • 切换是全量的,如果V2版本有问题,则对用户体验有直接影响;
  • 需要两倍机器资源;

适用场合:

  • 对用户体验有一定容忍度的场景
  • 机器资源有富余或者可以按需分配(AWS云,或自建容器云)
  • 暂不具备复杂滚动发布工具研发能力;

流量模式

blue green two groups traffic

蓝绿发布一次完成流程切换,图片来自附录7.1

3.2 金丝雀发布(双服务器组)

对蓝绿部署的一种简单优化,发布时先从绿组拉入1台金丝雀,待金丝雀验证通过再发全量。对比蓝绿发布,该发布方式的优势是有一个生产流量的金丝雀验证过程,可以减轻V2可能有问题的风险和影响面。简化发布过程如下图所示:

canary two groups before

发布前

canary two groups middle

发布中,先发一台金丝雀

canary two groups after

全量发布

3.3 滚动式发布(双服务器组)

滚动式发布是对上面的蓝绿和金丝雀发布的进一步优化,按批次增量滚动发布,提供更平滑的用户体验。

rolling update two groups before

发布前

rolling update two groups first

发布中,先发一台金丝雀

rolling update two groups middle

发布中,再发若干台

rolling update two groups after

直到全部发完

实践要点

  1. 发布前先申请一批新服务器,数量一般和V1版本相同,将V2版本应用发布到新服务器上。例如如果在AWS云上,则可以直接调用API申请一批新VM,如果用容器云k8s,则可以直接启动一批新容器(使用V2版本容器镜像)。
  2. 一般会先通过LB拉入1台V2版本的机器,这台机器也相当于金丝雀,用于流量验证。
  3. 逐步按批次完成发布,每批只需要通过LB拉入V2版本,再拉出对应数量的V1版本。批次之间留有观察间隔,通过手工或监控反馈确保没有问题再继续发布。
  4. 发布有问题回退很快,直接通过LB将流量切回V1即可。
  5. 完成发布后,一般V1版本要保留观察以备万一,比如留1天,1天后没有问题则回收V1机器资源。

优势和适用场合

优势:

  • 用户体验影响小;
  • 升级切换和回退(rollback)速度比单服务器组滚动发布要快,LB切流量即可;

不足:

  • 需要两倍机器资源;
  • 发布工具比较复杂,LB需要流量切换能力

适用场合:

  • 用户体验不能中断的网站业务场景
  • 机器资源有富余或者可以按需分配(AWS云,或自建容器云)
  • 有一定的发布工具研发能力;

流量模式

rolling upodate two groups traffic

滚动式发布,流量平滑过渡,图片来自附录7.1

四、其它发布方式

上述都是偏传统的发布方式,能覆盖大部分应用发布场景。针对一些关键新功能的上线发布,或者一些特定的场景,还有一些特殊的发布方式。

4.1 功能开关发布

利用代码中的功能开关(Feature Flag/Toggle/Switch)来控制发布逻辑,一般不需要复杂的发布工具和智能LB配合,是一种相对比较低成本和简单的发布方式。这种方式也是支持现代DevOps理念,研发人员可以灵活定制和自助完成的发布方式。功能开关的原理如下图所示:

feature flag deployment

功能开关发布,图片来自附录7.2

实践要点

  1. 功能开关发布需要一个配置中心或者开关中心这样的服务支持,例如携程的Apollo配置中心附录7.3,或者开源的FF4J附录7.4,这些都支持开关发布,业界还有专门的功能开关SaaS服务,例如LaunchDarkly附录7.5。通过配置中心,运维或研发人员可以在运行期动态配置功能开关的值。当然,功能开关发布只是配置中心的一种使用场景,配置中心还能支持其它很多动态配置场景。
  2. 功能开关服务一般提供客户端SDK,方便开发人员集成。在运行期,客户端SDK会同步最新的开关值,技术实现有推方式(push),也有拉方式(pull),或者推拉结合方式。
  3. 新功能(V2 new feature)和老功能(V1 old feature)住在同一套代码中,新功能隐藏在开关后面,如果开关没有打开,则走老代码逻辑,如果开关打开,则走新代码逻辑。技术实现上可以理解为一个简单的if/else逻辑。
  4. 应用上线后,开关先不打开,然后运维或研发人员通过开关中心打开新功能,经过流量验证新功能没有问题,则发布完成;如果有问题,则随时可以通过开关中心切回老功能逻辑。

优势和适用场合

优势:

  • 升级切换和回退速度非常快
  • 相对于复杂的发布工具,实施比较简单,成本相对低廉
  • 研发能够灵活定制发布逻辑,支持DevOps自助发布

不足:

  • 切换是全量的,如果V2版本有问题,则对用户体验有直接影响;
  • 对代码有侵入,代码逻辑会变复杂,需要定期清理老版本逻辑,维护成本变高

适用场合:

  • 对用户体验有一定容忍度的场景
  • 已有配置中心或开关中心服务
  • 暂不具备研发复杂发布工具能力;

流量模式

feature flag traffic

通过功能开关一次完成流量切换,图片来自附录7.1

4.2 A/B测试

A/B测试附录7.10原来主要用于产品功能的比对测试,收集用户反馈和对比数据做产品功能设计的决策。实际上,A/B测试也可以作为一种新功能发布技术。下图展示基于LB实现的一种A/B测试发布。

a/b testing deployment

实践要点

  1. 上图中,原来PC端和手机端都访问老版本V1服务(也称A组或控制组),当V2新版本(也称B组或实验组)发布以后,为了验证V2的功能正确性,同时也为了避免V2有问题时影响所有用户,先通过LB将手机端的流量切换到V2版本,经过一段时间的A/B比对测试和观察(主要通过用户和监控反馈),确保V2正常,则通过LB将全部流量切换到V2。
  2. 基于LB方式实现A/B测试,LB需要能够通过某种条件做流量路由,例如通过client ip,设备类型,浏览器类型,甚至是定制的http header或查询字符串。
  3. 高级的A/B测试需要专门的平台支撑,wasabi附录7.6就是intuit开源的一个支持高级A/B测试的平台,这类平台可以细粒度到针对某类用户做A/B测试,例如针对某个地区的用户,某个年龄段的用户,公司内部用户等等。举了例子,假设一个关键业务的新功能上线,为了降低风险采用A/B测试,可以做到先只让公司内部员工能访问到新功能,待新功能验证过,再全量放开给外部用户使用。
  4. 功能开关和A/B测试有点相似,但功能开关一般是无状态和全量的,无法做到针对某类特定用户进行测试,而A/B测试一般是有状态的,能够跟踪事务和用户级别的状态,可以实现针对某类特定用户进行测试。

优势和适用场合

优势:

  • 用户体验影响小;
  • 可以使用生产流量测试;
  • 可以做到针对某类特定目标用户进行测试;

不足:

  • 搭建复杂度相对高,有一定技术门槛

适用场合:

  • 核心关键业务,比如涉及资金的
  • 具备一定的A/B测试平台研发能力

流量模式

a/b testing traffic

针对某类目标用户进行A/B测试,图片来自附录7.1

4.3 影子测试

对于一些涉及核心业务的遗留系统的升级改造,为了确保万无一失,有一种称为影子测试的大招,采用比较复杂的流量复制、回放和比对技术实现。下面是影子测试的一个样例架构图,

shadow testing

实践要点

  1. 目标实现老的legacy服务迁移升级到新的experimental服务。
  2. 测试开始前,需要在测试环境部署一份legacy服务和experimental服务,同时将生产数据库复制两份到测试环境。同时需要将生产请求日志收集起来,一般可以通过kafka队列收集,然后通过类似goreplay附录7.8这样的工具,消费kafka里头的请求日志,复制回放,将请求分发到legacy服务和experimental服务,收到响应后进行比对,如果所有响应比对成功,则可以认为legacy服务和experimental服务在功能逻辑上是等价的;如果有响应比对失败,则认为两者在功能逻辑上不等价,需要修复experimental并重新进行影子测试,直到全部比对成功。根据系统复杂度和关键性不同,比对测试时间短的可能需要几周,长的可达半年之久。
  3. 影子测试因为旁路在独立测试环境中进行,可以对生产流量完全无影响。
  4. 影子测试一般适用于遗留系统的等价重构迁移,例如.net转java,或者sqlserver数据库升级为mysql数据库,且外部依赖不能太多,否则需要开发很多mock,测试部署成本会很高,且比对测试更加复杂和不稳定。
  5. 当当网有一个比较成功的交易系统.net转java迁移项目附录7.9,采用了影子测试技术,值得参考借鉴。

优势和适用场合

优势:

  • 对生产用户体验完全无影响
  • 可以使用生产真实流量进行测试(复制比对)

不足:

  • 搭建复杂度很高,技术门槛高,数据库的导出复制是难点
  • 外部依赖不能太多,否则测试部署成本很高,且比对测试更加复杂和不稳定

适用场合:

  • 核心关键业务,比如涉及资金的
  • 具备一定影子测试平台研发能力,包括流量复制、数据库导出复制和分发比对系统。

流量模式

shadow testing traffic

影子测试对生产流量无影响,图片来自附录7.1

五、比较

下表对各种发布策略,从各个维度进行综合比较,供参考:

comparision

六、结论和建议

下面是对发布策略的一些选型建议,供不同阶段公司参考:

  1. 蛮力发布一般是不建议采用的,除非是开发测试环境,用户体验不敏感的非关键应用,或者是创业期什么都缺时候的无奈之举。
  2. 如果暂时还不具备研发较复杂的滚动发布工具和配套智能LB,则功能开关是一种不错的轻量级发布技术,投入相对较小的成本,可以让研发人员灵活定制发布逻辑。
  3. 金丝雀发布通过少量新版本服务器接收生产流量的方式去验证新版本,可以显著降低风险。金丝雀发布适用于大部分场景,一般成长型公司就可以采用。
  4. 对于达到一定业务体量的公司,考虑到用户体验对业务的关键性,则需要投入研发资源开发支持滚动式发布的工具和配套的智能LB,实现自动化和零停机的发布。滚动式发布一般和金丝雀发布配合,先发一台金丝雀去验证流量,再按批次增量发布。
  5. 随着轻量级虚拟化(例如容器)的普及,双服务器组发布方式具有更快的发布和回退速度,是值得投入的高级发布技术。蓝绿部署仅适用于双服务器组,滚动式发布既可以在单服务器组上实现,也可以在双服务器组上实现。
  6. 对于涉及关键核心业务的新功能上线,采用A/B测试,可以显著降低发布风险,A/B测试是唯一一种支持针对特定用户组进行生产测试的高级发布技术。当然A/B测试的投入不低,建议有一定研发能力的组织采用。
  7. 对于关键核心业务的迁移重构,为确保万无一失,最后的一个大招是影子测试,影子测试对生产流量和用户完全无影响。当然这个大招的投入成本和门槛都高,建议有足够业务体量和研发能力的组织投入。
  8. 上述的各种发布策略并不是非此即彼的,一个公司常常会综合采用多种发布技术作为互补,实现灵活的发布能力。例如主流的发布手段是金丝雀+滚动式发布,某些业务线可能根据业务场景需要采用功能开关发布,还有一些业务线则可能采用高级的A/B测试发布手段。

七、附录

  1. k8s deployment strategies
  2. Deploying new releases: Feature flags or rings?
  3. 携程Apollo配置中心
  4. Feature Flag for Java
  5. LaunchDarkly ~ Feature Flag as a Service
  6. Wasabi高级A/B测试平台
  7. 使用goreplay实现遗留系统升级
  8. Goreplay
  9. 9. 华丽蜕变 – 当当网交易系统重构
  10. A/B Testing
0%