今天,我们来聊一聊如何实现低风险发布。本篇是如何实现低风险发布的第一篇,主要探讨为什么要进行低风险发布和常见的低风险发布策略,后续文章包括如何实现灰度发布和蓝绿部署,以及实践中的一些要点,敬请期待。

为什么要进行低风险发布?

软件部署到生产环境是软件交付的最后一公里,只有将软件包部署到生产环境并对外发布,交付到最终用户手里,才能对用户真正创造价值。正是因为与最终用户息息相关,部署和发布至关重要,一旦出问题就会对最终用户产生影响,轻则影响公司产品的用户体验,重则让用户对产品失去信心,公司因此蒙受巨大损失。

我想请你回忆一下,你是否经历或者见过以下场景?某位研发或测试同学负责的某个功能特性全部发布上线到生产环境之后,运维或运营人员马上监测到发生了严重故障,产品的核心功能被影响了,也陆续收到了用户的投诉。在紧急拉起的会议里,已经坐满了相关部门的领导,责令相关人员马上定位并解决问题,种种迹象均表明可能就是刚才的发布上线引入了一个致命缺陷,才导致的严重故障,初步确认了问题,接下来是一阵解决方案的争论,运维人员提议应该马上回滚,开发和测试人员评估能否回滚、如何回滚或者尝试进行热修复,尝试了一系列方案后,问题终于修复了。你在想,如果故障没有影响到核心用户或者影响范围小一点就好了,这样就不会导致问题这么严重了,处理起来也能更从容,对公司和业务造成的负面影响更小甚至可以忽略不计。

据 Google SRE 统计,线上 70% 的故障都是由某种变更而触发的[1],可见变更是导致服务故障的主要原因。当然,这些变更不仅仅是狭义的上线新版本代码,也包含配置变更,数据变更,操作系统变更,网络变更,基础设施变更等方面。在互联网各大公司都在追逐尽快抢占市场先机的今天,新版本代码的发布无疑要求更多更频繁,也因此更大概率引发线上故障。

因此,我们需要一系列有效的策略来降低软件发布的风险,这些策略可能包括完善的测试环境验证、充足的上线前准备,然而,生产环境的数据和场景是极其复杂的,测试环境、预发布环境想穷尽生产环境的场景几乎是不可能达到的,因此在非生产环境如何验证也无法保证软件在生产环境发布后是安全的。

除了我们必须接受生产环境发布故障无法完全避免,我们也需要了解到现代软件工程实践中提倡的不是完美,而是保障一定的质量水平。在DevOps模式下,质量思想是要在保障一定的质量水平的前提下,尽量加快发布节奏,并通过低风险发布手段,以及线上测试和监控能力,尽早地发现问题,并以一种最简单的手段来快速恢复[2]。在Google的工程实践中,持续交付遵从这样一个核心的原则:随着时间的推移,小批量的变更会带来更高的质量,换句话说,更快更安全,这其中包含一个重要的发布理念,力求敏捷也接受没有一个软件二进制包是完美的,根据明确阈值的关键指标来决策是否进行特性发布[2]。

聊到这里,我想说的是,低风险的发布手段对于避免线上的严重事故很重要,也已经是软件工程领域公认的行之有效的保障软件产品线上稳定性的方法,对于每一家提供软件服务的公司都至关重要。

低风险发布策略

那么,常见的低风险发布手段有哪些呢?

在正式开始前,我们先介绍下部署和发布两个概念。部署和发布是两个不同的概念:

(1)部署:是一组技术实践,指的是通过技术手段将软件包应用到生产环境的过程。我们把一个代码包拷贝到服务器上运行,但并不把它暴露给用户,也就是并不给用户提供服务。这个阶段比较耗时,但因为还没有面向用户,所以风险很小。

(2)发布:指的是将软件功能正式生效,对用户可见和提供服务。是把部署好的服务暴露给用户的过程,也就是开始真正上线服务用户了。这个过程可以通过负载均衡的切换很快实现,但风险很大,一旦出现问题损失就会比较大。

拿电商场景来说,0点开始要进行大促,需要先讲软件包提前部署到生产环境,此时已经完成了部署,但是对于用户来说大促的功能是不可见的,用户还不能参与到大促中,只有到了0点后,功能发正式对外,大促功能正式对外开放,此时才完成了大促功能的发布。

下面我们介绍下常见的降低发布风险的方法,主要包括滚动发布、蓝绿部署、灰度发布等,此外还有红黑部署、暗部署等。

滚动发布

首先,我们介绍下滚动发布,滚动发布是指在服务发布过程中,并不一下子启动所有新版本,而是先启动一台新版本,再停止一台老版本,然后再启动一台新版本,再停止一台老版本,直到服务实例全部更新完成,具体如下图所示。

image

滚动发布采用的是逐步部署新版本并替代旧版本,新版本部署后,负载均衡器会把流量直接指向新版本。这时候就会存在一个问题,如果新版本有问题,是不可用的,那么必须对已部署新版本的服务器进行回滚,不能快速把流量从新版本中摘除。如果服务部署的实例数过多,滚动发布到后面才发现故障,恢复往往较慢,因为服务也需要逐步回滚。如果每台或每组服务器回滚都需要几分钟,从开始到最终回滚完成,因服务实例较多,也往往需要耗费几十分钟甚至数小时不等,可能给用户带来长时间不好的体验。

滚动发布的优点在于实现简单,不需要依赖强大的技术基础设施就可以完成,只需要将新版本代码包拷贝到对应服务器上,之后停止旧版本、启动新版本即可。而且,滚动发布在某种程度上实现了相对安全的分批次服务部署,新版本启动后也不是直接接收全部流量,而是新版本服务数量与新旧版本总服务数量的占比,新版本部署一台后,可以观察生产环境无故障后,再进行后续部署和发布。、

蓝绿部署

下面介绍下蓝绿部署。蓝绿部署是指同时运行两个版本的应用,即蓝绿部署的时候,并不停止掉老版本,而是直接部署一套新版本,等新版本运行起来后,再将流量切换到新版本上。旧版本可以称为蓝色环境,而新版本则可称为绿色环境,两套环境可以使用各自单独的数据库,如下图所示。一旦生产流量从蓝色完全转移到绿色,蓝色就可以在回滚或退出生产的情况下保持待机,也可以更新成为下次部署的模板。

image

蓝绿部署的优点非常明显,在新版本刚部署到绿环境时,不会实际承接生产环境的流量,测试人员可以在绿环境充分测试验证新版本后,再把流量切换到新版本,这样就降低了服务发布到生产环境出故障的风险。还有一点,新版本在发布后出问题,也可以通过调整负载均衡器快速把流量切回蓝环境,这样能把问题影响降低到最小。

当前这是比较理想的情况,这里面有几个问题需要考虑,包括数据库的复制、切换过程中用户的事务操作如何保证等,这并不容易解决。幸运的是,我们可以采用同一套数据库也实施蓝绿部署,这样就能解决因数据复制、数据不一致等导致的问题,具体如下图所示。

image

使用一套数据库相比各自使用各自的数据库,就需要考虑数据库字段和数据更新时的兼容性了,这对于滚动发布也是必须要考虑的,因为一套数据库要同时支持两个版本的服务。

即便如何,蓝绿部署也存在一个明显的缺点,那就是占用资源多,因为有两套一模一样的环境,只有一套用于真正地提供线上服务,另一套则不会对外提供任何服务。

灰度发布

之后我们来介绍下灰度发布,灰度发布,又名金丝雀发布,是指在黑与白之间,能够平滑过渡的一种发布方式,通过让一小部分用户先使用新版本,以便提前发现软件存在的问题,从而避免用户受故障影响。简单地说,灰度发布就是把部署好的服务分批次、逐步暴露给越来越多的用户,直到最终完全上线。与蓝绿部署相比,灰度发布更加灵活,成本也更低,所以,在企业中也是一种更为普遍的低风险发布方式。

灰度发布之所以又名金丝雀发布,是因为金丝雀对瓦斯极其敏感,17 世纪时,英国矿井工人发现金丝雀对瓦斯这种气体十分敏感,因此为了保障自身的安全,每次下井工作时都会携带一只金丝雀,金丝雀会先于人察觉到有害气体,矿工察觉有危险,就会马上停止工作,回到地面。这就与灰色发布过程中,先发布给一部分用户来测试相似,因而得名。

灰度发布将发布分成不同的阶段,每个阶段验证通过后,进入下一阶段,每个阶段逐步增加使用新版本的用户比例,再部署更多的节点,依次循环,最终完成所有节点的部署,将所有应用都升级到新版本,具体如下图所示。增加用户比例的方式也有很多,可以按照流量比例进行灰度,也可以针对不同类型的用户、地域、设备类型进行灰度。

image

灰度发布期间,在其上也可以进行A/B测试,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

灰度发布的优势在于,可以自由调控发布过程中新版本服务所承载的流量,从刚发布不接收流量,到最终完成替代旧版本均可以自由掌握,也可以按照用户、地域等更多因素调整流量比例,实现更稳健的发布。灰度发布的每个阶段都可以进行充分验证后再进行后续的发布,即使新版本有问题也可以把损失降到最低。相比蓝绿部署,灰度发布也不需要两套环境,节约了服务器资源,降低了成本。

红黑部署和暗部署

最后我们聊一下红黑发布和暗部署。

与蓝绿部署类似,红黑部署也是通过两个集群完成软件版本的升级。当前提供服务的所有机器都运行在红色集群中,当需要发布新版本的时候,具体流程是这样的:

(1)先申请一个黑色集群,在黑色集群上部署新版本的服务;

(2)等到黑色集群升级完成后,我们一次性地把负载均衡全部指向黑色集群;

(3)把红色集群从负载均衡列表中删除,并释放红色集群中所有机器。

这样就完成了一个版本的升级。这是Netflix采用的部署手段,Netflix的主要基础设施是在AWS上,所以它利用AWS的特性。与蓝绿部署相比,红黑部署只不过是充分利用了云计算的弹性伸缩优势,从而获得了两个收益:一是,简化了流程;二是,避免了在升级的过程中,由于只有一半的服务器提供服务,而可能导致的系统过载问题。至于这两种部署方式名字中的“蓝绿”“红黑”,只是为了方便讨论,给不同的集群取的名字而已,通过不同颜色表明它们会在系统升级时运行不同的版本。

A/B 测试不仅可以用灰度发布来实施,也可以用暗部署等技术手段。所谓暗部署,就是指功能或特性在正式发布之前,将其第一个版本部署到生产环境,以便在向最终用户提供该功能之前,团队可以对其进行测试。“暗”指的是用户无感知。比如后端先行的部署方式,把一个包含新功能的接口发布上线,这个时候,由于没有前端调用这个接口,用户并不会真实地调用到这个接口。当用户进行了某些操作后,系统会将用户的流量在后台复制一份并打到新部署的接口上,以验证接口的返回结果和性能是否符合预期。除了流量镜像的方式,我们也可以采用功能特性开关的方式,开关的起始状态为关闭,新版本部署验证完毕后再打开开关,真正把功能对外发布。

如何选择合适的发布策略?

现在你对主要的低风险发布方式应该都有了基本的了解,那么选择哪种部署方式最好呢?这必须结合目前公司的业务场景和相关要求,没有银弹,只有适合当前现状的才是最好的,包括服务特点、业务特定、技术架构等等各种因素。如果是初创团队,使用滚动发布,我想不会有什么大的问题。如果是对线上质量敏感,采用的微服务架构,可能使用灰度发布或蓝绿部署(发布)更合适,当然这两种发布策略也需要依赖一些微服务的基础设施,如服务网格、服务注册中心等。

想做好发布管理,也不止于选对发布策略就好,团队遵守同一套数据库变更规范,比如只对字段进行新增而不能删除和修改,这对于服务能否快速回滚至关重要。

下期我们就聊一下,如何实现灰度发布和蓝绿部署,探讨关于发布的更多优秀实践和要点。

参考:

[1] https://book.douban.com/subject/26875239/

[2] https://time.geekbang.org/column/intro/100036601?tab=catalog

[3] https://book.douban.com/subject/35838155/

[4] https://book.douban.com/subject/30419555/

[1] https://www.infoq.cn/article/weoxu*5pnc0xyrgo7k4j