构建缓存怎么用才不坑自己:增量编译的实践细节
缓存能省时间,也可能给出错误结果。这篇梳理缓存失效判断、命中率优化与常见问题定位的几个要点。
缓存记录的是输入到输出的关系
构建缓存的本质是把一次计算的输入集合算成指纹,指纹相同就直接复用上次的产物。听起来简单,风险全在输入集合是否列全:源码内容、依赖版本、编译参数、环境变量、工具链版本,任何一项漏掉都会造成错误的复用。
常见事故是隐式的环境依赖。构建脚本读取了某个全局配置或者系统时间,这些输入没有被纳入指纹,于是在另一台机器上复用了不适合的结果,表现往往是难以复现的诡异行为。
指纹粒度决定命中率
把整个项目算一个指纹最省事,但只要改一行代码就全部失效,命中率很低。按文件粒度计算能显著提升命中率,代价是需要维护依赖关系图,判断某个文件变化会影响哪些产物。
粒度再细可以到函数或者模块级别,收益递减而复杂度上升。多数项目做到文件级加依赖图已经够用,剩下的优化空间不如花在减少无效变更上。
哪些变更会无谓地打穿缓存
动态写入的时间戳、写入产物的版本号、每次构建都变化的构建号,都会让指纹漂移。处理办法是把这类易变信息从参与计算的输入中剔除,只在发布阶段注入。
注释和格式化改动也会触发重编,这在大型仓库里累积起来很明显。保持提交前统一格式,能减少相当一部分无意义的失效。
远程缓存的注意事项
团队共享远程缓存能把新机器、流水线的冷启动成本压下来,前提是上传与下载的开销小于重新编译的开销。产物体积大的时候,网络往返可能反而更慢,需要实测判断。
缓存服务本身的可用性与淘汰策略也要考虑。缓存不可用时应该优雅降级为本地构建,而不是直接让流水线失败;淘汰策略不当则会让命中率在高峰期莫名下降。
怎么判断缓存是否健康
值得长期盯的指标有三个:整体命中率、缓存读取耗时占比、以及失效原因分布。命中率长期偏低说明输入定义过宽或者无效变更太多;读取耗时占比过高说明该考虑产物压缩与就近存储。
定期做一次强制全量构建并与缓存构建对比结果,是验证正确性的有效手段。两份产物如果不一致,说明输入集合有遗漏,这个检查应该纳入常规的持续集成流程。
本文由美格工具信息网编辑部整理撰写,观点仅供参考;转载请注明来源与链接。