Facebook 如何进行大规模持续交付

乔梁 | 2021-01-25

软件行业已经想出了多种方法来更快、更安全、更高质量地交付代码。其中许多工作集中在诸如持续集成、持续交付、敏捷开发、DevOps 和测试驱动开发等思想上。所有这些方法都有一个共同的目标:使开发人员能够以安全的、小的、增量的步骤将代码快速、正确地发布给使用它的人

在《持续交付 2.0 》一书中的第 7 章与第 12 章均提及了 Facebook 的一些做法。今天就用这篇文章,进一步系统介绍一下它的发展历程。

Facebook 公司的开发和部署流程已经发展起来,并形成了良好的生态,它由一系列快速迭代技术的部分组成,但却并没有严格遵循任何一个特定的部分。这种灵活、务实的方法,使我们能够快速成功地发布我们的 Web 和移动产品。

2017 年以前,我们每天使用简单的主干发布的分支策略,推送 Facebook 的 Web网站 三次。工程师将已经通过一系列自动化测试的代码变更,通过 cherry picks 的方式,将需要发布的内容从主分支推送到发布分支上,以便当日可以部署。一般来说,我们每天看到 500 到 700 次的Cherry Picks。另外,我们每周会拉出一个全新的发布分支,这个分支中内容包括那些当周还没有被Cherry Pick 到线上的所有变更。

这个系统很好地支撑了人员扩张,从2007年很少的工程师,发展到今天的数千工程师。另外,随着我们增加了更多的工程师,我们可以完成了更多的工作——代码交付的速度随着团队的规模而增长

但是,除了现有的工具和自动化系统之外,发布工程师还花费了一定的人力来推动每日和每周的部署(PUSH)工作。我们知道,随着团队的不断壮大,批量处理越来越大的代码块以供交付将不会继续扩展。

到 2016 年,我们看到,原来的主干开发模式( branch/cherry pick)已经达到极限。我们每天向主分支摄入1000多个diff,每周的推送量有时高达10000个diff。每周协调和交付如此大规模的发布所需的人工工作量是不可持续的。

2016 年 4 月,我们决定对 facebook.com 实行“准持续部署”机制上。在接下来的一年里,我们逐步推出了这个机制,首先是员工的 50% ,然后是生产环境流量的 0.1% ,再到 1% ,到 10% 。每一次扩大范围,都让我们能够验证我们自己的工具和流程是否能够处理因此所增加的推送频率,以及获得真实反馈信号的能力。我们的主要目标是:确保新系统让人们的体验更好——或者至少不会让它更糟

经过几乎整整一年的规划和开发,在 2017 年 4 月的三天时间里,我们让 Web 网站的 100% 生产服务器都能够运行直接从主干部署的代码(译注:参见《持续交付 2.0 》 第七章,第 112 页,图 7-16 Facebook 的代码部署进度可视化工具)。

规模化持续交付

一个真正的持续部署系统一旦启用,它就应该非常快速地将每一个单独的变更交付到生产环境中。然而,Facebook 的代码速度要求我们开发一个支撑系统,可以每隔几个小时推送几十到几百个代码变更。**在这种准连续交付模式中所做的更改通常是小的和增量的,很少会对实际用户体验产生明显的影响。**每个版本都会在几个小时内以分层的方式,部署到全量生产环境。一旦发现任何问题,我们可以立即停止继续部署。其步骤如下:

  1. 必须通过一系列内部的自动测试用例集的验证,才能将代码提交到主干上
  2. 再将其上的代码 diff 推给 Facebook 的内部员工使用
  3. 如果我们引入了一个回归问题,我们可以按下一个按钮,发出阻塞警报
  4. 还有一个紧急停止按钮,让我们阻止进一步扩大发布。
  5. 如果一切正常,我们将其推到生产环境的2%,然后再次收集质量信号,并监视警报,特别是对于我们的自动化测试或员工跟踪可能没有发现的边缘情况。
  6. 最后,我们推出了100%的生产,我们的 Flytrap 工具汇总用户报告,并提醒我们任何异常。

译注:Flytrap Database(捕蝇器) 是 Facebook 公司统一收集生产环境中的用户反馈数据的数据库。此数据库包含由(内部或外部)用户提交的问题报告。 用户可以通过应用程序上的“报告问题”组件提交问题,该组件可以通过下拉菜单或摇动设备获得。或者,他们可以填写一个帮助中心“联系表”上的一个 FB 网站。员工报告的问题也会自动输入到一个名为 Tasks database(任务数据库)中。而用户提交的问题并不会自动输入到 Tasks database 中,因为许多用户提交的是一些不重要的问题、对新功能的请求、各种改进建议,有时甚至只是垃圾信息。总的来说,Flytrap 数据库相当嘈杂。因此,只有当机器人能够识别足够多的用户报告的问题,超过给定的阈值时,用户汇报的问题才会自动输入到 Tasks database 中。

许多变更最初都隐藏在我们的 Gatekeeper 系统之后,它允许我们将新功能的发布和 web 代码的版本变更分离,帮助降低任何特定更新导致问题的风险。如果我们发现了一个问题,我们可以简单地关闭对应功能的开关,而不是回滚到以前的某个版本或向前提交修复。

这种准连续的发布周期有几个优点:

  • 它消除了热修复(Hotfix)的必要性。在原来使用那个一天推三次的系统时,如果有一个关键的变更必须发出,而不是在预定的推送时间内发出,就必须有人打电话请求通过热修复的手段下发。这种外带推送具有一定的破坏性,因为它通常需要一些人工操作,由于审批流程时间不可控,很可能它还会与下一个预定推送撞车。现在,有了新的发布系统,绝大多数需要热修复的东西都可以简单地提交给主干上,并在下一次版本发布中推送出去了。

  • 它可以为全球工程团队提供更好的支持。我们曾经试着安排每天三次的推送,以适应我们在世界各地的工程办公室。但是,即使这样,每周的推送也要求所有工程师在特定的日期和时间集中注意力,而在他们的时区内并不总是那么方便的。这个新的准持续发布系统意味着世界各地的所有工程师都可以在自己认为有必要的时候,开发并交付他们的代码。

  • 它提供了开发下一代工具、自动化和流程的强制功能,这些都是公司扩大规模所必需的。当我们接受这样的项目时,它就像是对许多团队和系统的压力测试。我们改进了推送工具、差异审查工具、测试基础设施、容量管理系统、流量路由系统和许多其他领域。这些团队都聚集在一起,因为他们希望看到更快的推送周期的主要项目取得成功。我们所做的改进将有助于确保公司为未来的发展做好准备。

  • 它使用户体验更好、更快。当需要数天或数周的时间来观察代码的行为时,工程师们可能已经开始研究新的东西了。通过持续交付,工程师不必等待一周或更长的时间来获得与他们的变更有关的数据反馈。他们可以更快地了解那些不起作用的功能,并在重新准备好后,立即交付小的增强功能,而不是等待下一个大版本。从基础设施的角度来看,这个新系统使我们能够更好地应对可能影响人们的罕见事件。最终,这拉近了工程师与用户的距离,提高了产品开发和产品可靠性。

移动端产品的持续交付

针对 web 端开发出来一个准持续部署系统是可能的,其中的一个原因是我们拥有整个服务堆栈,并且可以构建或改进实现它所需的工具。然而,在移动平台上的发布带来了更大的挑战,因为当前许多可用于移动平台的开发和部署工具都使得快速迭代变得困难。

Facebook 致力于通过构建和开源一系列专门针对快速移动发展的工具,包括 nucleut、Buck、Phabricator、各种iOS库、React Native 和 infer ,使这一点变得更好。总之,这些新的构建和测试堆栈使我们能够生成可以快速部署到移动平台的高质量代码。

我们的持续集成堆栈分为三层:构建、静态分析和测试。

每当代码从开发人员分支提交到我们的移动主干分支时,它首先是跨代码找出可能受到影响的所有产品进行构建。对于移动端而言,这意味着在每次提交时可能都要构建 Facebook、Messenger、Pages Manager、Instagram 和其他应用程序。我们还为每种产品构建了多种类别,以确保我们涵盖了这些产品支持的所有芯片架构和模拟器。

在构建过程中,我们运行 linters 和静态分析工具 Infer。这些工具有助于捕捉空指针异常、资源和内存泄漏、未使用的变量和有风险的系统调用,并将标记 Facebook 编码准则问题。

第三是个并发测试系统 mobile automated testing ,包括数千个单元测试、集成测试和由 roblectric、XCTest、JUnit 和 WebDriver 等工具驱动的端到端测试。

这个构建和测试堆栈不仅在每次提交时运行,而且在任何代码更改的生命周期中也运行多次。仅在 Android 上,我们一天的构建量就在 50000 到 60000 之间。

通过将传统的持续交付技术应用到我们的移动端开发中,我们已经从四周的发布版本变为两周的发布版本,然后,又改进到一周发布一个版本。今天,我们在移动设备上使用了以前在 web 端上使用的相同的 Branch/Cherry Picks 模型。尽管我们每周只推送一次生产,但在实际环境中尽早测试代码仍然很重要,这样工程师就可以得到快速的反馈。我们每天都为金丝雀用户提供移动版的候选版本,包括 100 万左右的Android beta 测试人群。

与此同时,我们增加了发布频率,我们的移动工程团队人数增长了 15 倍,我们的代码交付速度也大大提高。尽管如此,我们从 2012 年到 2016 年的数据显示,无论是以推送的代码行数,还是推送的次数来衡量,Android 和 iOS 的工程师生产率都保持不变。类似地,无论部署的数量如何,移动版本产生的关键问题的数量几乎是恒定的,这表明随着我们继续扩展,我们的代码质量不会受到影响*(译注:参见《持续交付 2.0 》 第12章,第 213 页,图 12-4 Facebook 公司不同严重级别的问题数量与 Android 和 iOS 每月提交次数的函数关系)*。

随着可用工具和方法的进步,在发布工程领域工作是一个令人兴奋的时刻。我为 Facebook 的团队感到骄傲,他们共同努力,为我们提供了我认为最先进的网络和移动部署系统。使这一切成为可能的部分原因是拥有一个强大的中央发布工程团队,这是基础设施工程领域的一流公民。Facebook 的发布团队将继续推动改进开发者和客户发布流程的计划,我们将继续分享我们的经验、工具和最佳实践。

原文作者: Chuck Rossi

原文链接:Rapid release at massive scale

发表时间: AUG 31, 2017