【万字长文】一文看懂持续部署按需发布!DevOps部署和发布方法大全 (下)

2022-06-24 10:00:00
赵卫David
转贴:
公众号
612
摘要:敏捷DevOps的一个主要目的是要达成持续的最短的周期进行价值交付,这就离不开快速的部署和发布。那么问题来了,部署和发布到底是一个概念还是不同的概念?有哪些常见的部署和发布策略?(下)

一、支持不同发布方式的技术实现

1.1 特性开关(Feature Toggle/Feature Flag)

利用代码中的特性开关(Feature Toggle/Flag/Switch)来控制发布逻辑,在生产环境中不用编写代码,不用发布新版本,在线上运行时,通过开关,打开或关闭特性。


一般不需要复杂的发布工具和智能负载均衡(Load Balancer)的配合,是一种相对比较低成本和简单的发布方式。


特性开关的原理如下图所示:
devops-Feature Toggle/Feature Flag
特性开关本质上就是一个“if … else …”的代码。而开关本身的配置可以是一个配置文件,或者是一个集中化的开关管理中心。


当开关关闭的时候,实际上体现的就是部署,将新版本部署到生产环境的时候,用户不可见,当打开开关的时候,功能对用户可见。所以特性开关很好的支持了将部署和发布解耦。


同时特性开关的各种应用方式可以很好的支持黑启动发布,金丝雀发布,灰度发布,A/B测试等。


如下图所示,特性开关对所有人有效。这是最简单的一种方式,与20年前的License许可证方式类似,例如:

  • ToC的例子,所有的用户使用同样的单体软件部署到PC上之后,根据用户的购买的License,打开和关闭某些特性。
  • ToB的例子,电信行业,例如华为和中兴卖给中国移动的设备,在部署到客户网路之中后,不用升级软件,只要购买了新的License,相应的特性就会被打开。
同时这种方式也可以支持持续集成的主干开发,所有开发人员在一个主干上开发代码,针对比较大的、周期长的、风险大的功能使用特性开关,可以保证主干出版本的时候,带上了部分未完成的代码,这些半成品代码通过开关关闭掉,发布给用户之后,半成品功能对用户不可见,也不会破坏已经完成的代码功能。
devops-Feature Toggle-Feature Flag2
如下图所示,特性开关对选定的用户群有效。
devops-Feature Toggle-Feature Flag3
如下图所示,特性开关可以增量的进行灰度发布,逐步扩大开关匹配的人员百分比。
devops-Feature Toggle-Feature Flag4
与特性开关所配对的不同范围的客群,需要结合其他手段识别和分流,例如不同的设备 id、user_id、pin、用户画像、地域、渠道(PC,微信,IOS,安卓等)、机房、网关、IP网段、Cookie、白名单等,可以支持金丝雀发布、灰度发布、A/B测试等。
还有一种情况是,在用户侧,用户可以自由选择使用开关,打开或关闭某个特性。

1.2 特性分支(Feature Branch)

为了对特性进行物理隔离,以及支持不同的发布方式,在版本控制系统中例如Git上,针对每个特性创建一个特性分支。无需采用特性开关,根据发布需要,对要发布的特性进行代码的合并和集成,这样可以创建多个集成不同特性的新版本,结合其他部署策略,这些新版本部署之后,根据需要使用不同分支版本进行灰度或者A/B测试等。


通常使用分支隔离不同版本代码,生产环境是老版本,新的发布使用特性分支对应的新版本;而使用不同特性分支同时发布不同的版本进行A/B测试也不少见。

1.3 抽象分支(Branch By Abstraction)

不采用特性分支方式来隔离大规模软件重构的代码,而是在不创建真实分支的情况下,通过设计手段,将大的架构/重构分解成多个架构切片,迭代增量的实现小的代码变更,逐步完成整体的架构。


增量上线的版本,在生产环境,部分功能业务逻辑运行在老代码上,部分功能运行在新版本上。


简单来说,使用设计手段,例如设计模式、面向方面编程AOP(Aspect Object Programming)等,允许在代码层面存在两个版本的代码。

抽象分支通过如下几个步骤进行大规模增量式修改:

  • 在你想改变的那部分代码之上创建一个抽象层。
  • 对其余部分的代码进行重构,使其使用这个抽象层使用其之下的代码提供的功能。
  • 在新的实现代码里实现一些新的类,让其上的抽象层根据需要,选择性的导向旧代码或新增的类上。
  • 剔除原有的旧实现。
  • 清理,并重复前两步,如果需要,可同时交付你的软件。
  • 一旦旧实现完全被代替后,如果你愿意,可以移除那个抽象层。

devops-Branch By Abstraction

老马(Martin Fowler)指出,这些步骤也可以变化一下。“在最简单的情况下,你可以创建一个抽象层,然后重构,让所有的代码都调用它,然后再新写一个实现,最后切换一下就行了。但是,还可以将它分开做。比如,不创建整个抽象层,而只是创建将要修改的功能的一个子集,迁移这部分代码,然后再做下一部分(此时新旧代码共存)。

二、Facebook的案例

2.1 Facebook网站持续部署

Facebook网站2003-2017年的分支策略,采用主干开发(Trunk/Master),分支发布(Production/Release)。如下图所示意,每天2-3个小版本,每周一个大版本。


开发人员的分支代码每天都会提交代码到主干Master分支,可以说开发人员的特性分支是一个短生命周期的开发分支,可以忽略不计,视作主干开发分支发布。


Facebook网站采用一周的迭代周期,在一周之内频繁发布上线给用户。

同时Facebook使用了一个内部特性开关(Feature Toggles/Flags)系统Gatekeeper,可以在服务端打开和关闭某个特性。
devops-Facebook's case
仔细看一下分支策略,如下图所示,每周周一结束时发布一次大版本给用户(图中最左侧周一绿色五角星,版本293.7),在周一发布最新版本之后,周二将这个发布分支从production改名字为defunct分支,意味着是一个不再起作用的分支。


新版本是从主干Trunk上开一个分支,名为为latest,代表着最新的发布分支,包含着上周就绪但没有cherry pick摘取到上一个版本代码,即最新的代码代表着所有的代码,一部分代码已经在上个版本发布,一部分是未发布但是就绪完成的代码,然后在周二的时候,因为上一个版本发布分支的名字已经从production改为defunct, prodution名字被释放,就可以将latest分支重新命名为produciton。


总结下,这个发布分支从上周日到周一的时候叫做latest分支,周二到下周一的时候叫做production分支,无论如何改名字,都代表着发布分支,在下面的描述汇中我们统一称之为发布分支。


对于新版本,从周一到周日这个七天里,每天都会选取这个新版要发布的代码,就是下图中主干上字母C带红色框的图标,这个提交被摘选合并到发布分支上,就在发布分支上构成了一个最新发布(紫色五角星代表的版本)但是这个发布仅仅对Facebook员工可见,而最终用户不可见。


从周二开始,每天正式发布给用户1-2次(绿色的五角星,版本号294.0,294.1,294.2 …… 294.6),下周一结束时发布最后一个版本294.7。

devops-Facebook's case2
在2016年4月,如上图所示的主干开发,分支发布,达到了瓶颈,因为开发人员每天将就绪的代码提交到主干上可以达到1000+次提交,然后从主干上将代码合并到发布分支上,最多的时候一周需要合并一万次。一周的代码手工合并以及各种协调所需的人力耗费巨大,不可持续。
devops-Facebook's case3
Facebook从2016年4月到2017年四月开始建设主干开发主干发布的持续推送系统(push from master to production)。如上图所示,每天都有成百上千的小的增量的代码变化,几小时后被发布到100%的生产环境。首先最新变化的代码经过自动化测试之后,提交到Master分支,再被推送给Facebook员工(吃自己的狗粮)。如果进行了回归测试发现了问题就会产生推送阻塞(Push-blocking)告警。如果一切顺利就推送给2%的生产环境用户,直到最后推送给100%的生产环境用户。


经过统计,每个小版本平均包括92行新增或者修改的代码,每个开发人员每周推送到生产环境3.5个软件更新,总体结果是Facebook网站每天可以达到上千次的部署。每个开发人员对自己提交的代码负责,没有单独的测试团队,仅仅要求提交代码之前做代码的同行评审。


Facebook通过黑启动(Dark Launch)阶段,路由一部分真实用户访问后端服务,这时候Facebook的页面与聊天服务器建立连接,查询状态信息,并模拟消息发送,但是使用的是老用户页面,并没有修改界页面显示服务器端返回的消息,这样就可以在全面上线前进行压力测试,模拟新功能带来的影响。

2.2 Facebook移动端App持续部署

devops-Facebook's case4

2016年3月公开的报告显示,Facebook安卓App采用了一周的迭代,开发测试的周期是一周,而为了上线需要灰度和提交市场,还需要花费一周的时间,所以它的模式是1+1模式,而对于用户来说,每周都可以在应用市场上看到最新的版本。京东商城APP的模式是2+1模式,即开发测试周期是二周,再加上一周的灰度和提交市场时间,京东金融APP的模式将会在2021年对齐京东商城APP的2+1模式。


如上图所示,Facebook安卓APP的分支策略,采用了2017年4月以前的网站的主干开发,分支发布的模式,开发到部署过程如下:
  • 预推送测试(Pre-Push Testing):每个开发人员从主干Master上拉一个本地分支,在本地分支开发,在本地经过单元测试,静态代码扫描,以及部分集成测试之后,进行代码评审。
  • 推送中(On push):代码评审之后就启动合并到Master的推送请求,代码在真正的push到master分支之前,触发了自动化测试,包括:单元测试,黄金流程(被大量使用的功能以及核心流程)的冒烟测试,以及简单的新功能测试确保新构建没有问题(build test);所有的自动化测试通过后,本地分支代码就被允许自动合并到master分支,如果出现合并冲突,相关的开发人员就解决冲突。
  • 在主干和发布分支上持续测试:每隔几个小时,并行的在主干和发布分支上,持续的运行所有的自动化测试,包括:全面的的build test, 回归测试以及性能测试等。
一周的开发中,在主干上每天进行1次构建,产生1个α版本,通过Google Play Store发布给几万个外部用户。在第一周周日下午6点创建发布分支,在第二周的前三天对前一周的开发进行稳定化和收尾,采用cherry pick将缺陷修复从主干上合并到发布分支上,同时每天进行3次构建,最终推出一个β版本,并通过Google Play Store发布给3百万外部用户,第一天覆盖20%用户,第二天覆盖50%用户,第三天覆盖100%用户;然后周四周五是Soak“渗透”阶段 ,周四冻结代码,处理问题,提交市场上线。
Facebook Mobile App Continuous Deployment
Facebook的苹果App采用了和安卓App同样的模式,但是时间被拉长了,是一个2+2的模式,2周开发测试,2周的灰度和提交市场。
Facebook Mobile App Continuous Deployment-2
笔者经过研究Facebook IOS App 2019年的发版记录,如下图所示,基本上可以得出结论,现在IOS App也是一周一个版本,可以推测出IOS App是1周开发,1周灰度。至少从2019年来看,Facebook苹果和安卓的迭代和持续部署的模式都是一致的,都是1+1模式,1周开发测试,1周的灰度和提交市场。
Facebook使用了黑启动的部署策略,通过特性开关实现黑启动,Facebook的黑启动工具为Gatekeeper,如下图所示:
Facebook Mobile App Continuous Deployment-4

八、总结

主干开发TBD(Trunk-Based Development)先锋保罗·哈曼特(Paul Hammant)将分支模型映射到发布频率,如下图所示,并且可以看到,特性开关作为一个必不可少的技术,可以很好的支持更频繁的发布。
devops-Trunk-Based Development

Jez Humble在《精益企业》中引用保罗·哈曼特(Paul Hammant)的部署加速度(Deployment g-forces),每天发布100次采用的是黑启动,蓝绿部署和金丝雀发布,如下图所下,图中将黑启动翻译成了灰度发布。

devops-Deployment g-forces

以上各种部署、发布以及支撑技术,对比总结如下:

分类
方式 简要描述 特点 优势 不足 适用场合
部署 蓝绿部署
1.也称为红黑部署,不停绿环境的老版本,部署新版本到蓝环境
2.测试蓝环境确认OK后将流量切到新版本,然后老版本同时也升级到新版本
3.如果没有使用其他发布技术,部署即发布
1.使用负载均衡(Load Balancer)
2.一次性切换版本,立即生效
1.升级切换和回退速度非常快
2.零停机时间
1.切换是全量的,如果 V2 版本有问题,则对用户体验有直接影响
2.需要两倍机器资源
3.如果两个版本共享数据,需具备向后兼容
1.对用户体验有一定容忍度的场景
2.机器资源有富余或者可以按需分配(容器云)
3.对服务连续性要求优先级是最高的
4.每个新版本每次部署都采用这个策略
滚动部署
1.一般是取出一个或者多个服务器停止服务,执行更新,并重新将其投入使用。周而复始,直到集群中所有的实例都更新成新版本
2.如果没有使用其他发布技术,部署即发布
1.相对于蓝绿部署,更加节约资源——它不需要运行两个集群、两倍的实例数。
2.使用负载均衡
3.经过多个批次的部署后,才最终部署完成
1.部署期间用户体验影响小,体验较平滑
2.零停机时间
1.部署和回滚时间相对缓慢,因为是分批次滚动操作
2.部署工具比较复杂,负载均衡需要平滑的流量摘除和拉入能力
3.由于两个版本同时存在,需要向后兼容
1.对用户体验和性能要求比较高,需要先行验证
2.对服务连续性要求非常高
3.要部署的机器或实例非常多
4.每个新版本每次部署都采用这个策略
黑启动
1.本意:针对新功能或者特定主要版本,首先是用户无感知的部署,进行性能等测试
2.扩展:然后可以开放部分客群流量,逐步扩大用户感知范围
1.先部署成功(结合其他部署方式)
2.再打开特性开关,逐步发布到更大范围的客群
1.用户无感知或者感知小
2.在暗模式下,可以提前发现大规模的性能问题
3.根据条件向部分用户发布,比较灵活去做验证或实验
1.为了真正的黑启动,让用户无感知,需要技术和工具手段
2.为了扩展,逐步扩大放量,需要其他的基础设施支持,投入较大
1.针对新功能或者特定主要版本,并不是每个版本都需要这个策略
2.验证重大算法、架构重构或者重大业务等
发布 金丝雀发布 1.也叫金丝雀测试,先发布一台或者小比例服务器或实例,经过流量验证后,再发布给所有用户,目的是线上验证,减少缺陷带来的影响
2.滚动部署的一个特例
3.黑启动的一种实现方式
1.对比滚动部署,先部署少量金丝雀机器或实例
2.少量金丝雀先接受流量
3.再全量发布
1.能够测试实时生产流量
2.用户体验影响小,发布过程出现问题缺陷等只影响少量用户
3.快速回滚
4.零停机时间
1.发布速度慢,因为需要监控金丝雀一段时间
2.需要对监控和可观测性投入
3.需要向后兼容
1.对新版本功能或性能缺乏足够信心
2.用户体验要求较高
3.降低全量发布的风险
4.网站式服务端发布应用比较广泛
灰度发布 1.增强性质的滚动部署和金丝雀发布,黑启动的一种实现方式
2.逐步发布开放流量给更大范围的客群,目的是利用客群流量提前发现缺陷
1.可以结合使用负载均衡的滚动部署和金丝雀发布
2.可以使用特性开关,结合其他技术,对不同范围客群打开特性开关
1.具备金丝雀发布特点
2.在保证基本功能和性能在金丝雀发布被验证之后,再逐步加大放量进一步验证
3.随着客群范围的逐步扩大,问题和缺陷可以得到及时发现和修复
1.发布速度慢,因为刻意的逐步放量有个时间过程
2.需要对监控和可观测性投入
3.需要向后兼容
1.对新版本质量、功能、性能缺乏足够信心
2.用户体验要求较高
3.降低全量发布的风险
4.移动端APP应用比较广泛
A/B测试 1.针对两个功能A和B,随机选定两组类似的客群,进行对比试验,目的是验证假设,探索业务
2.黑启动的一种实现方式
1.测试功能表现和效果如何,例如可用性、受欢迎程度、可见性、转化率、业务指标等等
2.通常应用在前端页面上
3.也可以应用在后台不同策略的对比上
1.快速实验能力
2.用户体验影响小
3.可以使用生产流量测试
4.可以做到针对某类特定目标用户进行测试
1.设置和搭建复杂度相对较高,有技术门槛
2.由于采样偏差问题导致结果偏差
1.用来业务探索
2.有两个或多个方案要进行对比,验证假设
支撑技术 特性开关 通过开关控制新版本和老版本功能,打开开关走新版本代码逻辑,关闭开不按走老版本代码逻辑
1.支持简单的特性开和关
2.结合其他的分流技术,例如不同的用户画像、地域、IP网段、机房等,可以支持A/B测试,灰度发布,金丝雀发布
3.如果具备特性开关技术,可以不使用特性分支,来支持主干开发
1.针对不同条件,打开关闭开特性,非常灵活
2.升级和回滚非常快
3.零停机时间
1.简单的特性开关是全量切换,有可能打开开关给所有用户带来大量影响
2.复杂特性开关要结合各种分流技术
3.功能开关需要一个配置中心或者开关中心
1.需要精细化精准化运营测试
2.支持灰度发布
3.支持A/B测试
特性分支 根据选择的不同特性的分支,产生不同的版本
1.物理上是两个版本,各自有二进制包
2.需要结合不同的部署方式进行部署
1.与不同部署方式优势之处一样
2.结合滚动部署,金丝雀发布,支持有限的A/B测试
1.与不同部署方式不足之处一样
2.需要维护多个分支和版本
1.没有特性开关工具或研发能力
2.简单的版本管理
3.简单的部署管理
抽象分支 不使用特性分支,还能达到创建分支进行重构的同样效果,迭代发布增量的重构 1.没有使用多个分形分支
2.对新代码使用设计手段达成分支效果
1.持续发布
2.业务功能交付与重构交付并行
3逐步验证架构的方向和正确性
1.成本比一次性完成高
2.整个重构完成时间周期可能会较长
3.技术手段可能较难
1.需要较大的架构改动和重构
2.架构风险较大
3.同时还要支持交付业务功能

参考

  • 软件发布生命周期:https://en.wikipedia.org/wiki/Software_release_life_cycle
  • 持续部署:https://www.scaledagileframework.com/continuous-deployment/
  • 按需发布:https://www.scaledagileframework.com/release-on-demand
  • 亚马逊平均每11.6秒部署一次:https://www.youtube.com/watch?v=dxk8b9rSKOo
  • 《凤凰项目:一个IT运维的传奇故事》:https://item.jd.com/12708994.html
  • 《持续交付:发布可靠软件的系统方法》:https://item.jd.com/10843669.html
  • 《持续交付2.0:业务引领的DevOps精要》:https://item.jd.com/12512514.html
  • 《发布!设计与部署稳定的分布式系统 第2版》:https://item.jd.com/12627801.html
  • Facebook大规模快速发布:https://engineering.fb.com/2017/08/31/web/rapid-release-at-massive-scale/,https://www.jianshu.com/p/ef4e9aeac507
  • Facebook如何实现大规模快速发布:https://www.infoq.com/news/2017/09/facebook-release-scale/,https://www.zybuluo.com/sambodhi/note/893487
  • Facebook的移动端软件的持续部署:https://research.fb.com/wp-content/uploads/2017/01/paper_fse2016-003.pdf
  • Facebook移动发布流程:https://www.infoq.com/presentations/Facebook-Release-Process/
  • Facebook 的 DevOps 案例研究与相关工具:https://segmentfault.com/a/1190000019236151
  • 我们经常聊的金丝雀发布、滚动发布、蓝绿发布到底有什么差别?https://mp.weixin.qq.com/s/MS8wi5t7btxO18Q0rfat4g
  • 应用部署和测试战略:https://cloud.google.com/solutions/application-deployment-and-testing-strategies
  • 应用部署的六个战略:https://thenewstack.io/deployment-strategies/
  • 什么是蓝绿部署:https://digitalvarys.com/what-is-blue-green-deployment/
  • 为什么领先公司使用黑启动:https://launchdarkly.com/blog/why-leading-companies-dark-launch/
  • Facebook Chat:https://www.facebook.com/note.php?note_id=14218138919
  • Facebok黑启动:https://controlaltconstruct.blogspot.com/2019/01/facebook-dark-launching-technique.html
  • 黑启动:https://martinfowler.com/bliki/DarkLaunching.html
  • Kent Beck响应式设计:https://www.infoq.com/presentations/responsive-design/
  • 动物哨兵:https://en.wikipedia.org/wiki/Sentinel_species
  • 国内金丝雀:https://en.wikipedia.org/wiki/Domestic_canary
  • 金丝雀发布:https://martinfowler.com/bliki/CanaryRelease.html
  • 金丝雀测试:https://featureflags.io/canary-testing/
  • 蓝绿部署,A/B测试和金丝雀发布:https://blog.christianposta.com/deploy/blue-green-deployments-a-b-testing-and-canary-releases/
  • A/B测试:https://en.wikipedia.org/wiki/A/B_testing
  • A/B测试知识点总结:https://www.jianshu.com/p/c5832ad60575
  • A/B测试实践全总结:http://www.woshipm.com/pmd/699804.html
  • A/B测试:https://learn.growthhackers.com.cn/skills/ab/
  • 多变量测试与A/B测试:https://www.optimizely.com/optimization-glossary/multivariate-test-vs-ab-test/
  • 特性开关:https://martinfowler.com/articles/feature-toggles.html
  • 部署新版本:特性开关还是猪增量发布?:https://opensource.com/article/18/2/feature-flags-ring-deployment-model
  • 特性开关驱动开发:https://blog.launchdarkly.com/feature-flag-driven-development/
  • 探索如何在生产环境逐步地为部分或者全部用户启用特性:https://docs.microsoft.com/en-us/azure/devops/migrate/phase-features-with-feature-flags?view=azure-devops
  • 特性开关使用场景:https://featureflags.io/feature-flag-uses/
  • 利用抽象分支做增量式大规模软件改造:http://www.continuousdelivery.info/index.php/2013/01/04/branch_by_abstraction/
  • 老马的抽象分支:https://martinfowler.com/bliki/BranchByAbstraction.html
  • Facebook主干开发:https://paulhammant.com/2013/03/13/facebook-tbd-take-2/

DevOps文章
联系我们
联系人: 阿道
电话: 17762006160
地址: 青岛市黄岛区井冈山路157号中南金石国际广场A座3202室