优化端到端流水线 | Slack 工程博客
在 DevOps 和开发者体验 (DevXP) 的世界中,速度和效率对工程师的日常工作影响巨大。今天,我们将深入探讨 Slack 的 DevXP 团队如何利用现有工具来优化端到端 (E2E) 测试流水线。这降低了构建时间并减少了冗余流程,为 Slack 的工程师节省了时间和资源。
问题:不必要的前端构建
对于我们最大的代码仓库之一(一个单体仓库,或称 monorepo),Slack 有一个 CI/CD 流水线,在将代码合并到 main 分支之前运行 E2E 测试。这对于确保 Slack 应用程序的整个技术栈(前端、后端、数据库以及其间的少数服务)的变更得到验证至关重要。然而,我们发现了一个瓶颈:构建前端代码花费的时间比预期长,并且发生得过于频繁,即使没有与前端相关的更改时也是如此。以下是详细分解:
- 开发者工作流程:开发者进行更改并推送到分支。
- 构建过程:前端代码被构建(约 5 分钟)。
- 部署:构建产物被部署到 QA 环境。
- 测试:我们运行超过 200 个 E2E 测试,又需要 5 分钟。
整个过程每次运行大约需要 10 分钟。其中大约一半的时间,即大约 5 分钟,被前端构建消耗,即使没有涉及前端更改。
考虑到每天有数百个拉取请求 (PR) 被合并,这些冗余构建不仅耗时,而且成本高昂:
- 每周数千次前端构建,每次构建在 AWS S3 中存储近千兆字节的数据。
- 其中一半的构建与上次合并到
main相比不包含前端更改,导致了数 TB 的重复数据。 - 每次构建 5 分钟,给流水线增加了不必要的延迟(每周数千小时)。
解决方案:采用带缓存前端资产的更智能构建策略
为了解决这个问题,我们利用现有工具重新思考了我们的构建策略。
步骤 1:条件化前端构建
我们的第一步是确定是否需要全新的前端构建。我们通过使用 git diff 及其三点表示法来检测更改,以识别当前检出分支的最新公共提交与 main 分支之间的差异。如果检测到更改,我们就调用前端构建任务。如果未检测到更改,我们则完全跳过构建并复用预先构建的版本。
步骤 2:预构建资产与内部 CDN
当不需要前端构建时,我们从 AWS S3 定位一个现有的构建。为了提高效率,我们使用一个仍在生产环境中使用的近期前端构建。我们将为 E2E 测试提供预构建前端资产的任务委托给一个内部 CDN。这减少了在每个 PR 上创建新构建的需求,同时仍然确保我们在当前资产上进行测试。
挑战:大规模下的效率
虽然方法看似简单,但将此解决方案扩展到我们的 monorepo 时出现了一些挑战:
- 识别前端更改:我们的仓库包含超过 100,000 个被跟踪的文件。确定是否存在前端更改需要高效的文件跟踪,而 Git 只需几秒钟就能处理。
- 寻找预构建资产:每天有数百个 PR 被合并到这个仓库中,要找到一个足够新的预构建版本需要强大的资产管理。通过使用简单的 S3 存储概念,我们能够平衡新鲜度、一致的文件命名和性能来管理我们的资产。
- 保持快速:我们平均能够在不到 3 秒的时间内判断出前端构建是否不必要,并找到一个最近的构建产物。
成果:构建频率降低 60%,构建时间减少 50%
我们的努力取得了回报,带来了显著的改进:
- 构建频率降低 60%:通过智能复用预构建的前端资产,我们将不必要的前端构建次数减少了一半以上。
- 每月节省数百小时:减少了云计算时间和开发者的等待时间。
- 节省数 TB 的存储空间:我们每月减少了数 TB 的 AWS S3 存储。这些重复的资产原本会存储一年。
- 构建时间改进 50%:这是前端 DevXP 团队及其合作团队的第二个主要项目。第一个项目升级了我们的 Webpack 设置,将平均构建时间从约 10 分钟减少到约 5 分钟。本项目将平均构建时间从约 5 分钟进一步减少到仅约 2 分钟。随着两个项目的成功,我们将 E2E 流水线的平均构建时间从约 10 分钟减少到约 2 分钟:这是今年的一项巨大改进!
两个意想不到的成果:
- 更可靠、更可信的 E2E 结果:我们的测试不稳定性(指测试间歇性或不一致地失败,尽管没有代码更改)显著降低。这种改进源于优化的流水线、减少了对复杂前端构建的需求以及一致的资产交付。根据月度测量结果,我们观察到了有史以来最低的测试不稳定性百分比。
- 重新发现遗留代码:实施此优化需要深入研究多个系统中长时间未经过重大修改的遗留代码。这种探索产生了宝贵的见解,引发了关于代码库行为的新问题,并生成了用于未来增强的任务积压。
结论:重新思考前端构建效率
通过战略性地利用 git diff 和内部 CDN 等现有工具,我们成功地节省了宝贵的开发者时间,降低了云成本,并提高了整体构建效率。
对于其他公司中面临 DevOps 和 DevXP 类似瓶颈的团队,教训是质疑你的流水线中什么是真正必要的,并据此进行优化。这个项目的改进事后看来似乎是显而易见的,但忽略那些尚未完全失效的系统中的低效现象是很常见的。在我们的案例中,重新思考我们如何处理前端资产,为组织带来了巨大的成功。
致谢
像这样的项目有很多动态部分:用于构建和测试的复杂流水线、云基础设施、内部 CDN、用于前端代码的复杂构建系统,以及我们整个系统中现有的自定义设置。它包括用 Python、JavaScript、Bash、PHP/Hack、Rust、YAML 和 Ruby 编写的代码。我们在没有任何停机的情况下完成了这项工作!好吧,几乎是。我们的部署流水线内部有十分钟的停机时间,但很快就修复了。
这项工作的成功离不开以下各位的贡献: Anirudh Janga, Josh Cartmell, Arminé Iradian, Anupama Jasthi, Matt Jennings, Zack Weeden, John Long, Issac Gerges, Andrew MacDonald, Vani Anantha 和 Dave Harrington
有兴趣接手有趣的项目、让人们的工作更轻松,或者只是构建一些非常酷的表单吗?我们正在招聘!