8

优酷 Android 构建速度优化实践

 2 years ago
source link: https://my.oschina.net/alimobile/blog/5376093
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

优酷 Android 构建速度优化实践

作者:苏彦郊(木磊)

Android 项目一般使用 gradle 作为构建打包工具,gradle 简洁、动态的功能特性为人津津乐道,同样,构建执行速度缓慢的缺陷也一直为人诟病。

近年来,随着优酷功能特性日益丰富,优酷的代码规模也急剧增加,同时,庞大的代码规模也带来了构建耗时的不断增加。整包构建耗时一度高达35min,严重影响集成与迭代效率。因此构建速度优化势在必行。截止 2021年 11 月份,优酷构建耗时优化取得较为理想的优化结果(如下),现将构建速度优化的实践方案记录成文。

android构建类型 2020年 2021 android debug 包构建耗时 12min 2.5min android release 包构建耗时 35 min 12min

方案与收益统计图:

技术优化类项目一般采用照设定数据指标、技术优化、成果防腐化三个维度展开。套用技术优化类项拆解可知,我们需要完成如下三个子项目:

  1. 设定数据指标:即收集与选取核心优化的数据指标,体现成果价值。本文选取构建耗时、构建失败率、小时维度构建次数等指标作为成果优化的数据支撑;
  2. 技术优化:通过影响构建速度的影响因素可知,包括软件与硬件两部分,所以构建速度优化可分为软件优化与硬件优化两大方向;
  3. 成果防腐化: 即维持技术优化指标不恶化,保障优化成果。

接下来,我将按照设定数据指标与结果防腐、技术优化——软件优化、技术优化——硬件优化三个部分展开。

设定数据指标与结果防腐

优化类项目需要建立健全相应的数据指标体系,借由数据评判体积优化项与优化方案进行有效性判定。进行构建优化前,笔者基于阿里巴巴Aone FaaS( Severless 服务)平台搭建了数据评判与监控大盘。该大盘有构建类型、构建时间、构建成功率、构建任务耗时等多项指标,满足构建优化项目需要根据类型、任务频率、高耗时任务排查的需求。

完成相关数据能力建设后,通过构建关键数据指标——构建耗时与构建成功率的追踪和分析,进而得出构建耗时的主要影响因素为高耗时任务,构建成功率的主要影响因素为不合理的构建任务。因此,我们可以通过高耗时任务报警与不合理任务报警,快速发现并分析构建速度恶化情形,进而保障构建耗时优化成果。

构建侧去atlas

Atlas是伴随着手机淘宝的不断发展,进而衍生出来的一个运行于android系统上的容器化框架,我们也叫动态组件化(Dynamic Bundle)框架。它主要提供了解耦化、组件化、动态性的支持。覆盖了工程师的工程编码期、Apk运行期以及后续运维期的各种问题。

依托于深度定制的产物结构与高度复杂、深度hook 的运行时框架,Atlas可以视为移动端 OSGI 实现方案与组件化方案。但随着优酷移动端架构调整与自研远程化方案落地,Atlas运行时框架逐渐丧失了OSGI框架作用,遂在运行期去除Atals 框架。

当运行期将Atlas依赖去除后,Atlas的复杂构建流程(如下图所示)也失去了存在意义。随即,优酷启动了构建侧Atlas 去除项目,目标是将Atlas构建插件去除、构建原生化、纯净化、精简化。通过产物原生化、构建任务清理、工具链升级等一系列动作,在完成了构建侧Atlas去除目标的同时,构建性能也有部分提升。

收益:debug 包构建耗时降低 3min左右。release 包构建耗时降低4min-5min。

gradle 升级和android gradle plugin 升级

gradle 团队一直在持续优化gradle 的构建速度等性能指标, 同时 google 团队也在持续优化 android gradle plugin 构建工具性能。为了进一步提升优酷android 端构建性能,决定对优酷android构建系统进行升级,将android gradle plugin 构建工具版本由3.0.1(2017年)提升至3.4.3(2019年)版本,将gradle构建工具由4.4(2017)至5.5 (2019年)版本。

对比升级前后构建耗时,可以发现构建工具升级后,性能提升主要源于三个方面:

  1. 随android gradle plugin 升级,aapt2、proguard 等构建工具也进行了升级,这部分工具升级后,构建性能有小幅提升;
  2. 更好任务排布与并行化机制:升级gradle 与agp 后,agp 3.4.3 版本进行了签名、压缩、对齐任务的整合优化;
  3. 配置按需加载与异步化策略:android gradle plugin 3.4.3 采用资源的异步加载策略,即configuaration 阶段仅做依赖拉取工作,不再进行产物的解压、过滤、合并工作,这样可以有效避免io 拥塞问题,避免cpu 忙等现象。

收益:debug 包构建耗时降低 2min左右 。release 包构建耗时降低4min左右。

dx 构建优化

升级到 android gradle plugin 3.4.2 版本后,agp 新增了三个个dx构建参数,经过测试可以显著提升dx处理class文件速度。经过测试 设置如下三个属性降低构建耗时。

android.dexingNumberOfBuckets=16 
android.dexingWriteBuffer.size=256 
android.dexingReadBuffer.size=256

仔细阅读agp源码可知,这几个参数构建构建内存中dx 缓存大小、dex 读取写入片大小。默认dexingNumberOfBuckets 为cpu个数的一半、读取写入大小为1KB。这样就造成高io情形下,cpu 忙等情形。采用降低磁盘写入次数、增加缓存方式能够明显降低构建耗时。

收益:debug release 包构建耗时降低3min左右。

冗余任务整理

随着我们不断迭代、平台升级,一些 构建任务、构建功能等已经废弃,但由于构建系统的特殊性——无产物回滚能力,导致构建系统的任务一直处于单增状态。且由于构建系统高风险、低收益、逻辑功能复杂陈旧的特点,导致构建速度治理动力不足。

针对上述问题,通过构建逻辑梳理、构建配置项清理、 单任务调试等手段,逐步摸清构建每个构建任务的功能,并对postPackageDebug等30+ 无用任务进行清理、对transform管理、任务管理等核心功能进行简化。下表为构建冗余任务清理列表。

任务名 作用产出 是否保留 postPackageDebug apk后处理 可以废弃 remoteSignAppDebug 远程签名 可以废弃 DexCountDebug dex个数 可以废弃 ChannelPackageDebug 渠道包构建 可以废弃 generateAppInfoDebug appinfo生成 可以废弃 uploadBuildFilesDebug 文件上传 可以废弃 buildPatchBaseApkDebug 热修复构建 可以废弃 ....

收益:debug 包构建耗时降低 15s+ ,release 包构建耗时降低20s+。

任务pipeline化

gradle 采用任务情形进行构建任务排布,基于这一拓展特性可以对产物进行后置处理。例如对 apk 后置处理有渠道处理、arsc 处理、对齐、签名、分包处理、图片压缩等任务,每一个任务都需要apk进行反复的解压、压缩、拷贝操作,浪费cpu 、系统io,徒增构建耗时。

为了降低apk构建耗时、简化apk产物操作复杂,我们对现有任务进行重整与拓展、实现了一种低拷贝、一次解压、一次压缩的产物pipeline处理机制,下图为构建过程apk后处理机制流程图。

收益:debug 包耗时降低21s,release 包耗时降低11s。

构建模版优化

按照用途区分 android 有多种构建变种,debug版本、release版本、远程与非远程等。对于开发阶段来说,一些插件的优化功能如turbo dex 缩减、7zip 压缩完全无必要,可以直接禁止掉。

收益:debug 缩短1-2min 左右,release 包无变化。

缩减代码规模

构建耗时中 java 代码混淆耗时约占整体构建耗时的60%,同时混淆耗时与代码规模正相关。所以构建耗时与代码规模成正相关关系。

代码规模的膨胀一部分来源于业务扩张,一部分来源于冗余代码的工程腐化。自2020年下半年至 2021年上半年期间,优酷进行了常态化的包体积治理,包体积取得了较为优异的成果,代码腐化问题也得到了部分缓解。

如下图所示优酷android 端自2020下半年至今,可知 android 端 java 代码规模降低25%,构建速度贡献约为45s+。

收益:release 包构建耗时降低约为45s+。debug 包构建耗时约为5s-10s。

私有构建租户池

采用iostat、tsar 等linux 性能分析工具对优酷android 端构建过程分析(如下图)可知。整个构建流程cpu io-wait 现象严重,即构建过程中存在大量的io操作,由于构建机器io性能不足,导致构建耗时偏长, 侧面印证软件优化中降低io能够构建速度的有效性。

针对io瓶颈问题,主要有两种解决办法:采用buffered io 处理、提升 Io 性能:

  1. 首先,仅保留agp插件进行构建,发现并无构建速度明显提升。证明:自定义插件无io 优化空间;
  2. 其次,对android 构建流程分析,io 碎片化写入较少,所有采用buffered io 处理 io 瓶颈,优化空间不大;
  3. 最后,通过采用使用SSD 替换机械硬盘效果较好。物理机构建比较数据如下:
机器类型 非首次构建 (依赖缓存情形) 主要情形 首次构建(无依赖缓存情形) 硬件情况 组一(台式机) 12min57s 21 min SSD Ex900 521G / 写入峰值约900Mb/s / intel 2.9Ghz 16线程 /16G内存 组二(Dell R740 刀片服务器) 25min 40min 机械硬盘 /写入峰值约254Mb/s / 骁龙 2.1Ghz 24线程/ 48G内存 组三(Dell WorkStation) 19min58s 27min SSD EX900 521G / 写入峰值约900Mb/s /骁龙 2.2Ghz 20线程 /32G内存 组四(台式机) 10min10s 23min SSD 512G / 写入峰值约1G/s AMD 3.5Ghz 24线程 32G内存 组五(devops集群) 23min 40min 多为机械硬盘,视调度具体机器而定

收益:debug 减少5min 左右,release 包减少10min。

综上所述,为了维护构建速度优化的成果,我们可以进行如下方面的工作:

  1. 为了满足数据指标设定与构建优化防腐的需求,我们需要设置构建优化指标,建立合理的数据评测体系;
  2. 通过对构建模板拆分、冗余任务清理、gradle 升级和android gradle plugin 升级、合理设定构建相关参数——dx构建优化等软件优化手段,我们可以获得大部分构建速度优化成果;
  3. 硬件优化部分需要建立构建流程关键瓶颈的分析上,各应用构建瓶颈可能不同。

受限于技术手段与稳定性问题, 构建速度优化还有如下未完成部分。

  1. 混淆规则控制与清理:混淆任务执行速度与混淆规则数量存在正相关关系,不合理的混淆规则会导致混淆任务耗时增长;
  2. 工程腐化程度治理:无用代码规模是工程腐化程度的重要标志,同时无用代码规模是影响构建速度的重要因素。但是如何治理大型项目的工程腐化程度,是应用架构以及全体应用开发需要探索的下一个重要课题;
  3. r8构建优化:通过对android dex 构建工具链——r8 的升级测试发现,优酷release 包构建有较为明显的构建速度提升。但由于部分google bug 导致r8 优化delay。

未来,优酷技术团队也将针对上述问题,持续优化构建耗时,欢迎大家随时与我们交流讨论。

【相关文档】

我们招聘啦!

优酷 — 技术中心 — 架构团队招人,描述如下。

【职位描述】

  1. 负责以优酷为核心的android基础架构工作,包括基础框架、中间件等。

  2. 负责app的稳定性、性能、包瘦身等长效治理工作,提升基础用户体验。

  3. 研究移动端前沿技术工程化,以及技术趋势探索。

  4. 解决各类疑难问题,支撑业务快速、稳定、高效迭代。

【职位要求】

  1. 熟悉Android SDK、Framework等基础技术,并有较好的源码分析能力。

  2. 精通Java语言,基本功扎实,有Kotlin、C/C++开发能力者优先。

  3. 对Dalvik/Art虚拟机中,任意部分有经验者优先。

  4. 有关键技术选型、疑难Bug修复、内存优化等经验者优先。

简历投至方式[email protected]

关注【阿里巴巴移动技术】微信公众号,每周 3 篇移动技术实践&干货给你思考!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK