如果 Medium 将此内容设置在付费墙后面,你也可以在这里查看这里(LinkedIn)。
我在亚马逊和谷歌期间,曾多年担任公司集成测试基础设施的技术主管,可以看出这两家公司对持续集成与持续交付的看法大相径庭。
我在亚马逊工作了11年多(2009-2020)。我是开发工具组织中的高级工程师,该组织负责公司所有的CI/CD基础设施和工具。我们负责运营那些数万名亚马逊员工每天用来编、审、建、测、部署代码的软件。
2020年,我对尝试完全不同的事情感到好奇,于是我加入了谷歌,在谷歌工作了4年,担任集成测试基础设施的技术负责人,这是谷歌CI/CD工具链中的重要一环。虽然领域相同,但这两套技术栈却完全不同。
我现在又回到了亚马逊,之前我在谷歌工作了一段时间,了解到完全不同的一家公司是如何看待这个问题的。现在用这种不同的视角来看待问题真是很有趣。
先定义为了让我们在同一页面上,我们先来定义一些术语:
- “CI/CD”代表持续集成(CI)和持续交付(CD)。简单来说,就是代码变更如何从本地开发者的工作站传递到生产环境部署。
- “Pre-Submit”指的是在提交代码之前开发者的体验。对我来说特别有趣的是,可以在代码提交前进行哪些验证。这可能包括在本地工作区对代码变更进行的测试,或作为代码审查过程的一部分。
- “Post-Submit”指的是提交代码之后开发者的体验。我们如何合并变更,如何将变更部署到接近生产环境的测试环境并进行验证,以及如何将变更引导至生产环境。
- 在这里,“测试”指的是集成测试或端到端测试,而不是单元测试。单元测试可以在任何地方轻松执行,但集成测试需要将候选代码部署到被测系统,并与依赖项连接,这会为基础设施增加指数级的复杂性。
最后我想说的是,谷歌在提交之前表现很好,但在提交之后表现一般,而亚马逊则相反,在提交之后表现很好,但在提交之前表现一般。
金库单代码库和微代码库的介绍有一段时间这个问题让我感到困惑,但现在我想我已经找到了根本原因。谷歌使用一个单代码库,让其120,000名工程师共享一个单一仓库,不使用分支。亚马逊则使用数以万计的小代码库(我们称之为“版本集”——从技术角度看,它们并不完全是“微代码库”,但在我们的讨论中,你可以将它们视为“微代码库”)。每个服务通常都有自己的“微代码库”(当然有很多例外,但在此次讨论中不予考虑)。
我有一位很好的朋友Alex Xu,ByteByteGo的联合创始人,写了一篇很好的文章,深入探讨了单代码库与多代码库的优劣,所以我不会在这里重复他已详细阐述的内容,但我会简要介绍它与提交前和提交后测试的相关内容。
注意:本文并非全面的“单代码库 vs 微代码库”的讨论。本文旨在集中讨论提交前或提交后的测试——这特别受到这种选择的影响——在持续集成/持续部署(CI/CD)的上下文中。
在Google上提前提交当有一个超过十万名开发者的团队使用同一个仓库,而且没有分支时,一次糟糕的提交可能对成千上万的其他工程师造成严重影响。在谷歌工作期间,我有时会因为一个随机的人在公司某个部门做出的随机提交而被阻塞,我完全搞不清楚为什么。谷歌投入了大量资源,以确保可以从本地开发环境或代码审查中,针对临时和隔离的测试环境进行端到端集成测试。事实上,谷歌就是谷歌,它不仅仅有一个基础设施,而是有四个在过去二十年里有机地、独立地发展起来的重复基础设施。我参与了将它们合并的尝试,这一过程将在我去世后仍会继续进行。这是一个巨大的努力,有超过一百名工程师参与其中。总体来说,能够在提交前运行适当的端到端集成测试,对我的亚马逊爬行脑来说真的是太神奇了。
Google, 提交后流程尽管预提交阶段非常神奇,但后提交的体验却出乎意料地糟糕。我在第一次代码提交时兴奋地问团队里的一个工程师:“我什么时候能在生产环境看到这些更改?”他漫不经心地回答说:“哦,星期四。”我震惊了。在我的亚马逊爬虫直觉里,这简直令人难以置信。亚马逊坚信每个代码变更应该在数小时内部署到生产环境(关于这一点,稍后再详细说明)。当然,对于跨越多个服务的代码更改,确实因为复杂性而需要更多时间,但大多数代码更改还是能在几小时内部署到生产环境。将代码变更仅在特定日期和时间部署的想法在我看来非常过时。谷歌面临的问题(由于其单代码库)是单个代码变更可能扩散到成千上万个部署。批量处理代码变更确实有所帮助,但一个部署可能包含数十甚至上百个独立变更,这意味着如果部署失败,就需要识别出问题的原因。再次,作为谷歌,我们为此目的有几十个“罪魁祸首”查找工具,总是冗余且相互冲突(你开始看出端倪了吧……)。
亚马逊, 提交前坚持使用微型仓库的哲学为亚马逊提供了内置的爆炸半径减小机制。一个糟糕的提交可能破坏一个单独的微型仓库,但提交后的测试通常会捕获此问题,并阻止其影响到其他微型仓库。你的糟糕提交可能会让你的团队成员感到烦恼,但它不会立即影响成千上万的陌生人的仓库(如果后期测试未能捕获此问题,它最终仍可能影响其他仓库)。
具有内置的减少爆炸半径的机制,对我们来说,并不需要像谷歌那样在提交前大量投资于测试基础设施。这对我们来说是方便的,但不是必须的。
我们并不是不想投入更好的预提交测试基础设施,但考虑到人力有限,我们觉得确保后提交的基础设施达到业界领先水平会更有效(因为无论预提交测试多么完善,问题终究会在某些时候漏到后提交阶段)。以亚马逊一贯坚持的节俭之道来看,我们的投资大约只有谷歌的十分之一。尽管我希望能为预提交测试搭建一些临时测试环境,但我必须在组织的人力投资上保持务实。
当然:将测试左移是一件很棒的事情。在本地开发中或最坏的情况下通过代码审查发现问题,比提交后发现问题更理想。你发现错误的时间越晚,修复它的成本就越高。回想起来,如果我在十年前就在亚马逊提议投资短暂且隔离的测试环境,这将比开发者为此付出的额外劳动更加划算。后知后慧,20/20。
Amazon, 提交后关于提交后的体验,亚马逊在这方面表现出色。与单代码库(monorepo)相比,微代码库(microrepo)是一个更加独立的环境,因此我们可以确保每个代码更改经过适当的测试,并在数小时内将其部署到生产环境,针对特定的服务。当有影响多个服务的更改并需要同步多个微代码库(microrepo)时,这种情况下微代码库会复杂得多,但实际上,大多数代码更改实际上只影响单个服务。亚马逊的微代码库哲学对独立微服务非常有效,亚马逊早在2002年贝索斯关于API的宣言时就对此深信不疑,并围绕这一点建立了“两个披萨团队”的概念。当你在浏览器中访问http://amazon.com时,它并不是一个单一代码库中的单体应用。实际上调用成百上千个服务,这些服务存在于同样数量的微代码库中,每个服务各自获取独立的数据片段,以便你能在亚马逊上下单。
最后的想法。这样的争论和“猫还是狗,哪种宠物更好?”或者“热狗算不算三明治?”一样没有结果。
我在这两种环境中都工作过。这是我注意到的:如果你是从使用微仓库开始的,你通常会不喜欢单代码库,反之亦然。来自Meta或Google的工程师来到亚马逊后,会觉得微仓库很不习惯,并希望说服我们切换到单代码库。而我则在谷歌时对单代码库有一种近乎本能的抵触情绪。这完全是个人偏好的问题。我认为我无法用数据驱动的论点来说服别人,证明其中一个比另一个更好。
最终,对于大型系统而言,CI/CD总是存在复杂性。谷歌以及采用单存储库(monorepos)的公司选择在一个地方解决这种复杂性的问题。亚马逊以及采用微存储库(microrepos)的公司选择在另一个地方处理另一种类型的复杂性。这种复杂性的程度大致相当,只是处理的位置不同。
为了使单仓库系统正常工作,谷歌不仅要投资于短暂的测试环境以支持提交前测试,还必须投资于智能选择测试和减少测试的波动性。当你进行代码更改时,你是如何决定要运行哪些测试的?构建依赖关系由Blaze(谷歌的构建系统)建模,因此理论上你可以计算构建图并执行所有依赖于你正在更改的包的测试。但是,当数十万工程师在同一个仓库上工作了数十年时,这些依赖图可能会变得极其庞大,你不能总是运行数百万个“以防万一”的测试。因此,谷歌构建了大量的基础设施以实现智能测试选择(以减少要执行的测试数量),而谷歌作为谷歌,他们有数十种重复且竞争的努力来减少测试的波动性。这很重要,因为测试不稳定性的增长呈指数级。即使是成功的概率为99%的3个简单测试,结合之后的成功概率仅为97%(99%³)。因此,减少要运行的测试数量以及减少它们的波动性,对于能够在谷歌规模上运作单仓库并保持其健康状态至关重要。总体而言,这些基础设施投资是巨大的,比如,每年花费40万美元维持300名工程师的成本(这里仅使用来自levels.fyi的公开数字,平均L4软件工程师的年薪为278,000美元,但请记住,一名软件工程师的成本要远高于他们的薪资)的年度费用就超过了一亿美元。让单仓库“运行”是昂贵的。
为了让微仓库正常工作,亚马逊不得不投资于基础设施,以管理代码变更的安全流动和及时更新,确保各个微仓库之间的同步,这也需要一支相当大的团队来支持。在单代码库的世界里,任何变更会立刻对所有部分生效;而在微代码库的世界里,如果你要使用或共享一个库或组件,你必须在不同的微代码库之间推送或拉取。如果你对此感兴趣,我的同事兼亚马逊高级首席工程师 Clare Liguori 已经详细撰写了关于亚马逊的 CI/CD 理念。
我的文章聚焦于CI/CD中的测试方面,但我也应该提到,单仓库(代码库)确实使得如安全补丁和跨公司项目或倡议等事情变得更加简单。而在微仓库中,依赖版本的管理可能会成为一个挑战:假设你的微仓库使用的是FooBar-1.2,而你的其中一个依赖库使用的是FooBar-1.3?但是为了简洁起见,我打算将文章的范围限定在两家公司的提交前集成测试的故事上。两家公司的提交前集成测试的故事。
关于预提交和后提交:最终,这不应该是“或”,而应该是“和”。我们应该有出色的预提交和后提交基础架构。这需要有意的投资,但当你有数以万计的开发者时,投资于减少开发者的负担是极具成效的,因此它会带来巨大的回报。
共同学习,写下你的评论
评论加载中...
作者其他优质文章