12. CI 的性能优化 1:并行化、矩阵构建与缓存策略
把 CI 时间从 30 分钟压到 5 分钟的方法论。
本章目标
把 CI 从“等半小时”优化到“几分钟出结论”:并行化、矩阵构建与缓存策略是三把最锋利的刀。
你会掌握
如何拆分流水线并行、如何用矩阵覆盖多版本/多平台、以及缓存 key/失效/命中率的设计方法。
真实收益
CI 更快意味着更少返工、更少上下文切换;更关键的是,团队更愿意遵守门禁,质量反而会更好。
CI 慢的本质不是“机器不够快”,而是“把本来可以并行的事情串行做了”。
你可以把 CI 想象成机场安检:如果所有旅客都排一个队,必然拥堵;如果按流程分流、按规则分组、重复检查可复用,速度会明显提升。
本章我们用三个杠杆把 CI 变快:并行、矩阵、缓存。
你可以把 CI 想象成机场安检:如果所有旅客都排一个队,必然拥堵;如果按流程分流、按规则分组、重复检查可复用,速度会明显提升。
本章我们用三个杠杆把 CI 变快:并行、矩阵、缓存。
1) 先定位:CI 时间都花在哪里?
常见耗时来源通常集中在:
- 依赖安装:npm/pip/maven 拉依赖很慢(且重复)
- 构建:编译、打包、打镜像
- 测试:单测/集成/端到端(尤其是后两者)
- 环境启动:数据库、服务依赖、容器编排
优化顺序建议:先把“重复工作”缓存掉,再把“互不依赖的工作”并行化,最后用矩阵扩大覆盖面。
不要一上来就堆机器,否则你只是在更贵地做同样的低效事。
不要一上来就堆机器,否则你只是在更贵地做同样的低效事。
2) 并行化:把串行长链拆成并行短链
并行不是“多开几个 job”,而是先把任务拆成可以独立运行的块:
- lint / unit tests / build 通常可以并行
- 测试可以按包/目录分片(sharding)
- 多语言项目可以按子项目并行
图 1:串行 → 并行的拆分(动态)
把“最长的那条链”剪短,CI 总时长往往就会明显下降。
并行化的两个坑
- 共享状态:多个 job 争用同一资源(数据库、端口、缓存目录)导致不稳定。
- 依赖顺序:确实有依赖的任务不要强行并行,先把依赖关系表达清楚。
3) 矩阵构建:用可控成本覆盖更多维度
矩阵构建解决的是“覆盖面”:多版本、多平台、多架构、多配置。典型例子:
- Python 3.10 / 3.11 / 3.12
- Node 18 / 20
- Linux / Windows
图 2:矩阵覆盖面(动态)
矩阵不是越大越好:你要用它覆盖“真实风险维度”,并用分层策略控制成本。
4) 缓存:最容易收益最大,也最容易踩坑
缓存的核心问题只有一个:哪些东西值得复用?通常包括:
- 依赖缓存(pip/npm/maven)
- 构建中间产物(build cache)
- 测试数据或工具链(例如浏览器驱动)
缓存 key 设计的基本公式
cache_key = OS + language_version + lockfile_hash + toolchain_version
其中最关键的是 lockfile_hash:依赖变化时缓存必须失效,否则你会得到“快但错”的 CI。
图 3:缓存命中/失效链路(动态)
缓存要“快且对”。命中率很重要,但比命中率更重要的是:失效规则必须正确、可解释。
5) 本章小结:让 CI 更快的“公式”
- 并行:总时长 ≈ 最慢 job 的时长。
- 矩阵:用可控成本覆盖真实风险维度。
- 缓存:优先缓存重复工作;key 设计要保证“快且对”。