中心化决议管理——云端分析
作者:钱佳卫,研发工程师,产品研发和工程架构部-Client Infrastructure-App Infra-DevOps-Developer Tools
前言
CocoaPods 云端分析能力是字节跳动的终端技术团队(Client Infrastructure) 下 Developer Tools 部门提供的一系列云化基础设施之一, Developer Tools 团队致力于建设下一代移动端云化基础设施,团队通过云 IDE 技术、分布式构建、编译链接等技术,优化公司各业务的研发和交付过程中的质量、成本、安全、效率和体验。
一、背景
iOS 组件化研发模式下,CocoaPods 已然成为 iOS 业界标准的依赖管理工具。但随着业务能力不断拓展迭代,组件数量不断增多,导致App工程复杂度急剧增大,依赖管理效率严重下降,甚至出现潜在的稳定性问题。为了能够更快、更稳定得管理大型项目的组件依赖,iOS build 部门打造了一套中心化依赖管理服务——云端依赖分析,从工具链的层面收敛了依赖管理流程,加速了决议速度,聚合了失败问题。
二、什么是云端依赖分析
基于 CocoaPods 的 iOS 工程管理,每次执行 pod install,都需要先将组件索引信息 Spec 仓库同步到本地,一般都依靠于 git 仓库的 clone,然后读取 Podfile、Lockfile 以及其他配置文件,开始进入依赖分析、依赖下载、工程整合等几个步骤。
云端分析是一个依赖于字节跳动自研制品库平台,通过工具链上传本地工程构建物料,快速返回依赖分析结果,中心化管理 iOS 工程依赖的云端服务。云端分析服务会依赖于制品库提供所有组件索引信息;并且通过云端分析本地工具在环境准备过程中获取本地工程物料,统一上传至云端进行依赖决议任务,云端借助于一系列优化手段以及服务器性能,快速返回一个决议结果,本地接收到决议结果之后进行后续的依赖下载与工程整合过程。
云端分析的接入方式也极其容易,不需要增加配置文件,也不需要修改原有研发模式,以无侵入、无接入成本、不影响研发流程的方式接入到工程项目中。唯一需要做的,仅仅是在 CocoaPods 工具链中加入云端分析的 RubyGem 插件,并在 pod install 命令中增加一个开启优化功能的控制开关参数。
三、如何加速决议
3.1 制品库 (全量组件索引信息)
3.2 缓存机制
在分析每个 pod 时,为了能获取最新版本的 pod 依赖,CocoaPods 会对 source 仓库中的所有版本号建立对应的 Version 对象,并进行排序。目前,公司内部大部分制品版本已经达到上万的数量级,而且在不指定 source 源的情况下,二进制版本和源码版本都会被排序并读取,最终获取一个满足要求且最新的版本。由于组件版本号都以 “.” 和 “-” 分段,大部分组件版本都存在4个或者5个字段以上。这也致使上万个组件在进行排序的过程中,每次排序对比都需要遍历4次以上,使时间复杂度提升了好几倍,极大得增加了耗时。
为了更快得获取到有序的版本列表,由制品库服务维护了所有 pod 组件从大到小排序的版本文件;每增加一个新的 pod 版本,制品库都会向文件中插入一个新版本;删除时,则会删除相应的版本字段。
有了有序的版本文件,云端分析增加 Version 缓存的主要目的是为了将版本分段信息一直维持在 Version 对象中,可以快速判断当前 Version 是否满足依赖的要求。Version 缓存可以让依赖管理过程提速大约10-12秒左右。
云端分析在无版本缓存的情况下,会优先读取版本文件中的数据,直接获得有序的版本列表;如果版本列表长度与 source 中组件版本目录长度不一致,会回退到原始方法(版本列表出错,确保分析的正确性)。在缓存命中的情况下,也需要判断缓存版本列表长度是否与 pod 版本目录长度相等(有新增版本,缓存未新增),则会从版本列表数组中查找出差异版本,并对缓存进行修正。
CocoaPods 在从排序版本中查找满足依赖要求的 podspec 时,会将所有满足依赖要求的 podspec 版本内容全部读取进来,进行依赖决议遍历。如果在不注明具体版本的情况下,所有版本的 podspec 文件都将被读取,并且在不注明具体 source 源的情况下,所有 source 存在的 pod 也都会被读取。一万个 podspec 文件读取就需要花费 30 秒左右(据不同磁盘而定)。
云端分析会对每次分析任务 IO 读取的 podspec 文件内容进行缓存。在下次任务获取 Spec 对象时,可以根据 source,pod_name,version 三个字段直接得到对应的Spec对象。
同时,为了确保 Spec 的正确性,防止 Spec 在不改变版本而更改内容的情况出现。Spec 对象缓存是以一个多维数组的形式存在,通过判断 podspec 文件的修改时间,来更新缓存中的 podspec 内容为最新提交的,确保 checksum 计算与本地拉仓依赖分析的计算值相同,实现云端依赖分析的正确性。后续,也会增加 Spec 缓存命中次数,Spec 对象过期时间等,实现 Spec 缓存的清理策略。
完整的分析结果
和分析结果图 Graph
。平台信息 key
,来确定具体 app 信息;再对所有target 下的组件依赖逐个计算 hash 值,获得二级 hash 数组 key
,并对应一个分析结果图 Graph value;通过模糊匹配的方式对 hash 数组 key 进行匹配,匹配到依赖个数相同最多的相近图,来替换物料中的 locked_dependencies,来加速分析。当然,模糊匹配能力也有一定的局限性,无法对原本上传 lockfile 物料的分析任务进行加速。3.3 物料剪枝
云端分析会将 CocoaPods 对象转变为字节流进行传输。具体的上传物料与分析结果具体如下:
上传物料
结果返回
3.4 决议策略兼容
四、总结
扩展阅读
CocoaPods原理详解:
https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzA5MTM1NTc2Ng==&action=getalbum&album_id=1477103239887142918&scene=173&from_msgid=2458325057&from_itemidx=1&count=3&nolastread=1#wechat_redirect
CocoaPods优化:
https://www.infoq.cn/article/adqsbwtvsyzuvh429p8w
加入我们
我们是字节的 Client Infrastructure 部门下的 Developer Tools 团队,团队成员由 IDE 专家及构建系统专家组成,团队致力于通过客户端云化技术以及编译构建技术,优化公司各业务的研发和交付过程中的质量、成本、安全、效率和体验。同时,在实践的过程中我们也看到了很多令人兴奋的新机会,希望有更多对编译工具链技术感兴趣的同学加入我们一起探索。
职位链接
【扫码投递简历】