13. CI 的性能优化 2:增量构建、影响面分析与变更集驱动
只跑需要跑的任务:更快、更省、更稳。
本章目标
让 CI 从“每次全跑”升级为“只跑需要跑的”:在不牺牲可信度的前提下,把时间和成本砍下来。
你会掌握
增量构建、影响面分析、变更集驱动(change-set driven)与路径过滤,以及它们的边界与反例。
真实收益
当仓库变大(多模块/monorepo)时,你仍能把 PR 的反馈控制在分钟级,而不是让 CI 变成“半小时彩票”。
CI 优化的第一阶段是“并行 + 缓存”;第二阶段是“只跑该跑的”。
后者更像手术:你要切掉无效工作,但不能切到关键神经。
所以本章不仅讲怎么做,更讲边界:什么时候不能省,什么时候可以大胆省。
后者更像手术:你要切掉无效工作,但不能切到关键神经。
所以本章不仅讲怎么做,更讲边界:什么时候不能省,什么时候可以大胆省。
1) 为什么“只跑需要跑的”这么关键?
当项目规模上来,CI 时间往往不是线性增长,而是指数式爆炸:
- 模块变多 → 测试总量变多
- 依赖关系复杂 → 变更影响范围更大
- 环境更多 → 组合维度(矩阵)更多
如果仍然坚持“每次全跑”,你的 CI 会变成团队的隐形税。
2) 影响面分析:从“改了什么”推导“影响了谁”
影响面分析的核心思路是:
- 识别变更集:本次 PR 改了哪些文件/模块?
- 沿依赖图传播:哪些模块依赖它?哪些测试覆盖它?
- 选择测试集合:只跑“受影响的测试 + 关键兜底测试”。
图 1:影响面传播(动态)
把“全跑”变成“受影响集合 + 兜底集合”。兜底用来防止依赖图不完整导致的漏检。
实现方式(从简单到高级)
- 路径过滤(path filter):改了 docs 就不跑 build;改了 backend 才跑 backend tests。
- 模块级选择:monorepo 里按包/目录切分测试集合。
- 依赖图驱动:用构建系统/包管理器的依赖图推导影响面。
3) 增量构建:让“同样的构建”越来越快
增量构建解决的是:同一项目在相似变更下,重复工作占比很高。
- 输入稳定:依赖不变、工具链不变 → 结果可复用
- 输出可缓存:中间产物/编译缓存/测试缓存
图 2:增量构建缓存链(动态)
把构建视为函数:输入相同 → 输出相同。只要输入指纹正确,就能安全复用结果。
增量构建的底线:输入指纹必须正确。指纹不正确,缓存命中会导致“快但错”。
一条经验:宁可多失效一点,也不要误命中。
一条经验:宁可多失效一点,也不要误命中。
4) 变更集驱动(change-set driven):把 CI 做成“路由器”
变更集驱动强调:CI 不是“跑全部任务”,而是根据变更集选择任务图(job graph)。
典型规则:
- 只改文档 → 只跑 markdown lint
- 改后端模块 A → 跑 A 的单测 + 依赖它的集成测试
- 改共享库 → 扩大到所有依赖方的关键测试
图 3:变更集驱动流水线(动态)
把流水线当“路由器”:变更从入口进入,按规则分流到不同任务集合,最终汇总成一个可信结论。
5) 边界与兜底:什么时候不能省?
- 共享组件/基础设施变更:例如 auth、common utils、DB schema,影响面可能很大。
- 依赖图不完整:当你无法可靠推导影响面时,需要更强兜底测试。
- 高风险发布:安全/支付/权限相关变更,宁可多跑也不要漏检。
专业的做法是:在“省”与“稳”之间建立一条硬规则——关键链路永远有兜底 smoke tests。
本章小结:从“全跑”到“智能路由”
- 影响面分析让测试选择可解释:受影响集合 + 兜底集合。
- 增量构建靠输入指纹:宁可多失效,也不要误命中。
- 变更集驱动把 CI 变成路由器:用规则分流,既省成本又不牺牲可信度。