编译:伯乐在线 - 孙腾浩
如有好文章投稿,请点击 → 这里了解详情
【伯乐在线导读】:Quora 是国外知名的问答网站,曾经在 12 小时内发布了 46 次新版本。不过这对于 Quora 工程师来说,只是普通的一天。他们执行非常快的持续部署周期,代码变动提交后就直接推送到线上。 他们是如何做到的呢?请看 Quora 工程师 Martin Michelsen 的文章。
在 2013 年 4 月 25 日中午 12 点到晚上 11 点 59 分之间,Quora 站点发布了 46 次新版本。这对于我们来说只是普通的一天。我们执行非常快的持续部署周期,代码变动提交后就直接推送到线上。这使得我们可以在各个层面上实现平行化开发。我们希望推送系统足够快,让开发者尽快看到他们对生产环境的改动(目前生产环境修订版上线平均要 6、7 分钟),同时也要注意可靠性和灵活性,让我们可以迅速响应问题。
对开发者而言,只需要一个简单的命令把代码推送到到生产环境:git push
这背后发生的事情要复杂很多。每当一个开发者把提交推送到我们的主 git 仓库,一个 post-receive 钩子会将最新的修订版加入到发版申请列表,并记录到 MySQL 数据库。(post-receive 钩子也会把提交加到 Phabricator,我们用它做代码评审。更多关于我们代码评审的相关信息参阅这个回答 Does Quora engineering use a code review process?)一个内部监控网站展示每个等待发布的修订版的状态。
一个后端服务监控发版申请列表,每当提交新的修订版,服务收集此版本代码库中所有单元测试的名字。我们有上百个测试模块和上千个独立的测试,服务会将测试分配到一些 worker 机器中并行处理。当 worker 运行完测试,它们将结果返回给测试服务,服务在发版申请的列表中标记修订版的综合结果(成功或失败,以及多少个测试失败了和失败的详情)。
同时,另一个服务监控发版申请列表,等待打包新修订版。每当提交新的修订版,它将所有需要运行在我们服务器上的代码进行归档,并打包上传到 Amazon S3。
������,��������当修订版打包好后,一个集成测试服务将修订版推送到一台单独的机器(并不是生产环境),用新的包开启 web 服务,并向服务发送请求。只有每个请求返回 200 状态码,集成测试才算通过,如果任何请求返回 4xx 或 5xx 错误码,测试失败。
最后,第四个监控发版申请列表的服务由其他三个服务调用,当修订版的测试和打包没有问题,服务向 S3 上传一个包含版本号的小型元数据文件,来标记修订版的部署(发布)。Web 服务器和其他使用相同代码的机器会周期性检查元数据文件中的版本号,如果有变化,它们会立刻从 S3 上下载最新的包。下载并解压包大概需要一分钟,然后运行新的代码只需要几秒。每台需要代码的机器会独立完成上述操作。我们将这个系统命名为 Zerg,因为在所有需要包的机器上进行部署过程很像虫族(zerg)的 rush 战术。
下图描述了后端架构:
这套系统弹性很大,很少出现失败,但正如其他复杂的系统一样,也会出现失败情况。要么测试 worker 宕机,要么测试服务失败,要么打包程序出现问题。通过这种架构,内部的失败并不会引起一致性问题(比如把未通过单元测试的代码推送到生产环境),并且大多数时候只需要重启失败的机器或服务便可以让其正常工作。
对于大多数修订版,git push 到发布大约间隔 6 分钟,这取决于其中执行时间最长的任务。目前,单元测试是时间最长的任务;打包需要 2-3 分钟,集成测试需要 3 分钟多一点。之后 10 分钟(发布之后),机器下载运行新代码,同时后面的修订版开始测试和打包。(我们不会同一时间更新所有机器,这会导致每次我们发布时,Quora 会有几分钟处于不可用状态!)选择 10 分钟的间隔是为了可靠性 —— 如果我们需要响应突发事件,可以立刻覆盖部署代码。
我认为 6 分钟的测试 + 10 分钟的部署还不够好。我们可以改进测试系统,使其并行测试来提高效率。另外,我们去除掉其他服务中无用的东西,这让我们可以将部署时间由 10 分钟缩短为 5 分钟。
系统的设计主要基于其他公司部署项目时遇到的问题。我们在公司早期就决定采用持续部署方案。在公司规模、代码库、基础架构很小时便于使用这种方案,但我们仍努力多年来维护这一流程,因为持续部署在整个开发流程和开发文化中举足轻重:
持续部署让我们尽可能迅速地将产品的变更展现在用户面前,包括从 bug 的修复到主要特性等一系列东西。
持续部署让我们尽可能迅速隔离并解决出现的问题。当出现 bug,你倾向于在单个提交中 debug,还是从包含一百个提交的整体发版中 debug?
持续部署让我们在改进网站时不需要投入过多精力。我们直到经历了这些之后才意识到这点 —— 持续部署让我们在几分钟之内完成发现问题、快速修复、推送代码并部署到生产环境。如果这些动作时间过长,开发者可能会想“我难道要花一个小时来坐下跟踪代码的推送吗?”。更糟糕的是,如果隔天部署,开发者会想“我难道要明天再审查一遍然后测试代码吗”
持续部署减少了跟踪不同发布状态的多个版本这一工作上的投入。代码是在生产环境还是在发版列表的未推送状态,都一目了然。
持续部署让我们有测试的习惯。毫无疑问,测试非常重要。伴随着变更需要立刻上线的压力,我们没有之后再写测试的余地。我们总是先写好测试。
持续部署很有趣!写代码很有趣,我们的部署过程也应该同样有趣。
通过减少每次版本上线需要的时间,并加强测试,我们每天可以上线更多的修订版,并有效减小变更伴随的阻碍。这也是 Quora 这类快速起步的公司需要的东西。