作者:钱佳卫,研制工程师,产品研制和工程架构部-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 制品库 (全量组件索引信息)

依据 Cocoapods 的 iOS 开发体系对 iOS 的产品办理是十分粗放的,直接将不同的 git 库房作为构建产品(podspec 文件)的索引库房,担当了制品库的人物。随着 iOS 工程的复杂化,git 库房的文件信息添加导致组件索引信息查询困难,库房的同步速度缓慢。BitNest 制品库是公司自研的移动端的产品办理体系,用于办理持续集成进程中所发生的构建产品。制品库将别离在各个 git 库房的 podspec 源进行了中心化的办理,经过一套完好的 CLI 指令,能够快速拉取、查询 podspec 信息。云端剖析服务借助于制品库才能的帮助,能够在云端实时访问一个全量完好的 podspec 源信息。每次CocoaPods 使命都不需求再去更新 podspec 源信息,也不会因为不及时更新 podspec 源信息而找不到最新发版的组件 podspec 信息。

3.2 缓存机制

中心化决议管理——云端分析

在介绍缓存机制之前,先简略介绍一下 pod install 中依靠剖析的运转流程。在第一次履行的时分(疏忽 lockfile),CocoaPods 会经过 DSL 从 Podfile 中读取详细的 plugin,source,target,pod 等内容,创立相应的目标完结准备阶段。在每个 Target 目标中每个 pod 都创立成了 Dependency 目标,并且都会有详细的 Requirements 目标。一切 Target 目标的一切 Dependency 目标都逐一被参加到库房中,并创立一个 Graph 依靠节点图。每个 Dependency 目标依据其 Requirements 去对应的 Source 库房寻觅对应的 pod,如果 Requirements 中没有库房信息,就从 podfile 公共 Source 中遍历寻觅。找到对应的 pod 之后,会先树立一个版别列表,并从版别列表中找出一切契合 Requirements 要求的 pod,然后读取对应是 podspec 文件内容。抉择中会对 Spec 目标中隐式的 pod 创立新的 Dependency 参加到剖析库房和 Graph 中。如果某个版别的 Spec 在遍历 Graph 依靠图时不满意另一个同名依靠的 Requirements,就会进行出栈回撤和依靠图回撤,直至一切 Dependency 都被找到对应的 Spec 目标为止,剖析就完结了。可见,在 CocoaPods 依靠办理进程中,有许多重复的目标创立和排序查找进程,极大的降低了研制功率。试想,让 CocoaPods 使命所需的目标一向保持就绪状况,每逢收到使命恳求当即履行依靠剖析作业,就能够快速回来成果。云端剖析服务集中化了一切 CocoaPods 的依靠办理使命,针对重复的作业搭建了目标缓存机制。采用懒加载的方法,对新增目标进行缓存,在下一次使命进来之后马上进入依靠抉择进程。

3.2.1 排序 Version 缓存

中心化决议管理——云端分析

在剖析每个 pod 时,为了能获取最新版别的 pod 依靠,CocoaPods 会对 source 库房中的一切版别号树立对应的 Version 目标,并进行排序。现在,公司内部大部分制品版别现已达到上万的数量级,并且在不指定 source 源的情况下,二进制版别和源码版别都会被排序并读取,最终获取一个满意要求且最新的版别。因为组件版别号都以 “.” 和 “-” 分段,大部分组件版别都存在4个或者5个字段以上。这也致使上万个组件在进行排序的进程中,每次排序比照都需求遍历4次以上,使时刻复杂度提升了好几倍,极大得添加了耗时。

为了更快得获取到有序的版别列表,由制品库服务保护了一切 pod 组件从大到小排序的版别文件;每添加一个新的 pod 版别,制品库都会向文件中刺进一个新版别;删去时,则会删去相应的版别字段。

有了有序的版别文件,云端剖析添加 Version 缓存的首要目的是为了将版别分段信息一向维持在 Version 目标中,能够快速判别当前 Version 是否满意依靠的要求。Version缓存能够让依靠办理进程提速大约10-12秒左右

云端剖析在无版别缓存的情况下,会优先读取版别文件中的数据,直接取得有序的版别列表;如果版别列表长度与 source 中组件版别目录长度不一致,会回退到原始方法(版别列表犯错,保证剖析的正确性)。在缓存命中的情况下,也需求判别缓存版别列表长度是否与 pod 版别目录长度持平(有新增版别,缓存未新增),则会从版别列表数组中查找出差异版别,并对缓存进行修正。

3.2.2 Spec 目标缓存

中心化决议管理——云端分析

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 缓存的整理战略。

3.2.3 缓存复用

中心化决议管理——云端分析

云端剖析也会对剖析成果进行缓存,下一次遇到相同的剖析使命能够直接复用。云端在获取一次物料之后,会对物料做一次大局 hash 核算和一次分段 hash 核算,分别缓存完好的剖析成果剖析成果图 Graph。针对下一次剖析使命,如果是完全相同的物料能够直接回来一个可用的完好剖析成果;如果未匹配,会经过一些 target,platform 等信息核算出一级平台信息 key,来确认详细 app 信息;再对一切target 下的组件依靠逐一核算 hash 值,取得二级hash 数组 key,并对应一个剖析成果图 Graph value;经过含糊匹配的方法对 hash 数组 key 进行匹配,匹配到依靠个数相同最多的附近图,来替换物料中的 locked_dependencies,来加快剖析。当然,含糊匹配才能也有必定的局限性,无法对原本上传 lockfile 物料的剖析使命进行加快。

3.3 物料剪枝

云端剖析会将 CocoaPods 目标转变为字节流进行传输。详细的上传物料与剖析成果详细如下:

中心化决议管理——云端分析

1. 上传物料

云端剖析东西链会将 Podfile 目标、lockfile 生成的 Molinillo Graph 目标、指定的 Source 目标、插件适配器,一切的外部源 Specs 目标(详细为指定 git,path 和 podspec 的 pre-release 目标)作为上传物料。但其实,云端剖析并不需求这些本地目标的悉数信息,能够对这些目标进行剪枝,例如 Podfile 目标仅需求 target_definitions 的链表即可;Molinillo Graph 目标仅需求一切 pod 对应的节点,而不需求记载操作节点的 log;Source 目标仅需求知道 name 和 repo_dir 即可,等等。其间,部分抉择优化插件需求经过插件适配器额定传输一些装备 Config 目标。

2. 成果回来

云端剖析回来的成果为以 Target 为 key,相应的 Specs 数组为 value 的 hash 目标。成果回来之前,会先对一切 Spec 的 Source 进行剪枝。因为每个 Spec 对应的 Source 在后续流程中仅运用到 url 的字段进行分类与生成 lock 文件。因此,能够删去 Source 目标其他无用的字段,最小化传输内容,加快呼应时刻。对回来成果进行剪枝后,传输内容大小能够减少大约10MB以上

中心化决议管理——云端分析

3.4 抉择战略兼容

为了保证抉择成果的正确性和仅有性(single truth),云端剖析兼容了字节跳动内部各 CocoaPods 抉择战略优化的东西链。依据工程中构建装备参数,云端剖析本地插件识别出详细的抉择战略,并传递到云端剖析服务器并激活对应抉择战略算法进行快速抉择。同时,结合已有的抉择优化战略和云端的优化加快机制,让 CocoaPods 的依靠办理流程达到秒级回来

四、总结

本文首要共享了现在字节跳动内部的一种 CocoaPods 云端化的优化计划,针对许多重复的 iOS 工程流水线构建使命进行了收敛和复用,在保证依靠抉择正确性的前提下加快了依靠办理速率,提升了研制效能。现在云端剖析服务现已完结第一阶段的开发并落地运用,已被公司内部几个核心的生产线运用。如头条接入云端剖析服务后,pipeline 的依靠剖析阶段耗时加快60%以上。后续,关于 CocoaPods 的下载优化,工程缓存服务也现已在技能探究中,相关技能文章将连续共享,敬请期待!

扩展阅读

CocoaPods原理详解:mp.weixin.qq.com/mp/appmsgal…

CocoaPods优化:www.infoq.cn/article/adq…

参加咱们

咱们是字节的 Client Infrastructure 部分下的 Developer Tools 团队,团队成员由 IDE 专家及构建体系专家组成,团队致力于经过客户端云化技能以及编译构建技能,优化公司各事务的研制和交给进程中的质量、本钱、安全、功率和体会。同时,在实践的进程中咱们也看到了许多令人兴奋的新时机,期望有更多对编译东西链技能感兴趣的同学参加咱们一同探究。

职位链接

jobs.bytedance.com/referral/pc…

中心化决议管理——云端分析

【扫码投递简历】