1. 持续集成与并行调度概述
1.1 持续集成到底在解决什么?
持续集成(Continuous Integration,简称CI)是我工作这么多年来,觉得最实用的研发实践之一。说白了就是:每次代码变更,都自动拉取、构建、跑测试,发现问题立刻反馈。你想想看,如果开发了一周才合并,冲突和Bug能堆成山。但真正让CI落地见效的,不是工具本身,而是怎么安排这些任务的执行顺序和方式。
我刚开始带团队的时候,用的就是最简单的串行CI——一个任务接一个任务的跑。那会项目小,倒也没觉得慢。可后来微服务一拆,模块一多,一次构建动辄半小时起步。等得让人抓狂。记得有一次线上紧急修复,push完代码后,CI跑了近50分钟。大家就盯着那个进度条干着急——这就是典型的串行瓶颈。
核心矛盾:开发团队规模增长 → 提交频率增加 → 串行排队时间暴涨 → 反馈延迟加剧 → 开发者开始绕过CI。
1.2 传统串行CI的痛点,你肯定遇到过
我把常见的几个坑总结了一下,你看看是不是感同身受:
- 流水线排队严重:十个提交串行跑,最后一个要等前面九个全部完成。要是中间有个测试挂了,重新跑又得从零开始。
- 资源利用率极低:构建机CPU经常在跑一个任务时闲置,其他模块只能干等。我算过一笔账,串行模式下资源利用率往往不到20%。
- 修复成本高:串行跑到后半段才发现问题,中间依赖的模块已经白跑了。我曾经一个项目里,因为数据库迁移脚本顺序没处理好,导致后续十几个测试全部失败——全白跑。
- 反馈链太长:开发者从push到收到结果,短则十几分钟,长则一小时以上。等结果的这段时间,人容易被打断,切换上下文成本很高。
避坑提醒:我曾经见过一个团队,为了追求“串行可控”,硬是把所有测试打包成一个Job。结果跑一次超过两小时。后来重构时才发现,因为历史原因,80%的测试根本不依赖其他模块——完全可以并行跑。所以,别为了让CI看起来“简单”而去牺牲效率。
1.3 并行调度:不只是“多开几个Job”那么简单
很多人一听到并行调度,第一反应就是“多开几台机器一起跑测试”。其实没这么简单。你想想看:如果两个任务都依赖同一个数据库资源,一起跑就会产生锁冲突。如果A任务需要B任务的产物,你乱并行就会拿不到数据。所以,并行调度的核心不是“同时跑”,而是“在依赖正确的前提下尽量同时跑”。
我最早试过简单的并行:比如把单元测试和代码检查放在不同容器里同步跑。效果立竿见影,时间降了一半。但很快又遇到新问题:集成测试要等部署完成,而部署又要等构建产物,这些依赖关系不梳理清楚,并行反而容易乱套。
这里有一个经验值:当项目模块数超过5个,并且交叉依赖超过3层时,手动维护并行策略基本不可行。这时候就需要依赖图来帮忙了。
| 维度 | 串行 | 简单并行 | 依赖图并行 |
|---|---|---|---|
| 任务顺序 | 线性固定 | 固定分组并行 | 按依赖动态排序 |
| 资源利用率 | 低(<30%) | 中等(~60%) | 高(>85%) |
| 依赖处理 | 自动等待前序 | 手动拆分,易冲突 | 自动识别,保证正确 |
| 扩展性 | 差,加模块需全改 | 一般,分组需调整 | 好,新增模块只需声明依赖 |
| 反馈速度 | 慢 | 中 | 快 |
1.4 依赖图:打开并行调度的钥匙
依赖图(Dependency Graph)说白了就是把一个CI流水线里的所有任务,以及它们之间的前后关系,画成一张有向无环图(DAG)。从这张图里,你能一眼看出来:哪些任务可以同时跑,哪些必须按顺序。
举个例子:模块A和模块B之间没有依赖,那它们就可以并行;模块C依赖A和B,那C必须等A和B都完成才能启动。依赖图自动帮我们算出“每层可并发任务列表”,然后调度器按这个列表去分配资源。
我的一个习惯:每次新建一个CI流水线时,我先不急着写Jenkinsfile或GitHub Actions YAML,而是先画一张依赖草图。用方框表示任务,箭头表示依赖。画完之后,自然就知道哪些地方可以并行,哪些需要排队。这张草图,其实就是一个简化的依赖图。
下面这张图展示了从串行到依赖图并行调度的演进对比,也是本章的核心框架:
从图中你能直观看到:串行模式下所有任务排成一队,而依赖图模式把无依赖的任务拆成并行分支,只在必要汇合点等待。这种调度方式,就是我后面将要详细展开的核心方法。
小结
这一章我们聊了持续集成的本质、串行CI的明显短板,以及为什么不能简单粗暴地“并行跑”。关键点在于:依赖关系决定了哪些任务可以同时进行。依赖图就是描述这些关系的工具。后续所有章节都将围绕“如何构建依赖图、如何依据图来做任务调度、如何应对动态变化”展开。记住一句话:没有依赖图的并行,就是一团乱麻。
一个小练习:把你当前项目的CI流水线画出来,看看所有任务之间的依赖关系。数一数有几个任务其实可以并行却被迫串行。你会发现,90%的团队都有至少30%的优化空间。