GMTC全球大前端技术大会(北京站)门票9折特惠截至本周五,点击立减¥480 了解详情
写点什么

MCI:移动持续集成在大众点评的实践

2020 年 2 月 19 日

MCI:移动持续集成在大众点评的实践

一 、背景

美团是全球最大的互联网+生活服务平台,为 3.2 亿活跃用户和 500 多万的优质商户提供一个连接线上与线下的电子商务服务。秉承“帮大家吃得更好,生活更好”的使命,我们的业务覆盖了超过 200 个品类和 2800 个城区县网络,在餐饮、外卖、酒店旅游、丽人、家庭、休闲娱乐等领域具有领先的市场地位。


随着各业务的蓬勃发展,大众点评移动研发团队从当初各自为战的“小作坊”已经发展成为可以协同作战的、拥有千人规模的“正规军”。我们的移动项目架构为了适应业务发展也发生了天翻地覆的变化,这对移动持续集成提出更高的要求,而整个移动研发团队也迎来了新的机遇和挑战。


二 、问题与挑战

当前移动客户端的组件库超过 600 个,多个移动项目的代码量达到百万行级别,每天有几百次的发版集成需求。保证近千名移动研发人员顺利进行开发和集成,这是我们部门的重要使命。但是,前进的道路从来都不是平坦的,在通向目标的大道上,我们还面临着很多问题与挑战,主要包括以下几个方面:


项目依赖复杂


上图仅仅展示了我们移动项目中一小部分组件间的依赖关系,可以想象一下,这 600 多个组件之间的依赖关系,就如同一个城市复杂的道路交通网让人眼花缭乱。这种组件间错综复杂的依赖关系也必然会导致两个严重的问题,第一,如果某个业务需要修改代码,极有可能会影响到其它业务,牵一发而动全身,进而会让很多研发同学工作时战战兢兢,做项目更加畏首畏尾;第二,管理这些组件间繁琐的依赖关系也是一件令人头疼的事情,现在平均每个组件的依赖数有 70 多个,最多的甚至达到了270 多个,如果依靠人工来维护这些依赖关系,难如登天。


研发流程琐碎


移动研发要完成一个完整功能需求,除了代码开发以外,需要经历组件发版、组件集成、打包、测试。如果测试发现 Bug 需要进行修复,然后再次经历组件发版、组件集成、打包、测试,直到测试通过交付产品。研发同学在整个过程中需要手动提交 MR、手动升级组件、手动触发打包以及人工实时监控流程的状态,如此研发会被频繁打断来跟踪处理过程的衔接,势必严重影响开发专注度,降低研发生产力。


构建速度慢


目前大众点评的 iOS 项目构建时间,从两年前的 20 分钟已经增长到现在的 60 分钟以上,Android 项目也从 5 分钟增长到 11 分钟,移动项目构建时间的增长,已经严重影响了移动端开发集成的效率。而且随着业务的快速扩张,项目代码还在持续不断的增长。为了适应业务的高速发展,寻求行之有效的方法来加快移动项目的构建速度,已经变得刻不容缓。


App 质量保证

评价 App 的性能质量指标有很多,例如:CPU 使用率、内存占用、流量消耗、响应时间、线上 Crash 率、包体等等。其中线上 Crash 直接影响着用户体验,当用户使用 App 时如果发生闪退,他们很有可能会给出“一星”差评;而包体大小是影响新用户下载 App 的重要因素,包体过大用户很有可能会对你的 App 失去兴趣。因此,降低 App 线上 Crash 率以及控制 App 包体大小是每个移动研发都要追求的重要目标。


项目依赖复杂、研发流程琐碎、构建速度慢、App 质量保证是每个移动项目在团队、业务发展壮大过程中都会遇到的问题,本文将根据大众点评移动端多年来积累的实践经验,一步步阐述我们是如何在实战中解决这些问题的。


三、、MCI 架构

MCI(Mobile continuous integration)是大众点评移动端团队多年来实践总结出来的一套行之有效的架构体系。它能实际解决移动项目中依赖复杂、研发流程琐碎、构建速度慢的问题,同时接入 MCI 架构体系的移动项目能真正有效实现 App 质量的提升。


MCI 完整架构体系如下图所示:



MCI 架构体系包含移动 CI 平台、流程自动化建设、静态检查体系、日志监控 &分析、信息管理配置,另外 MCI 还采取二进制集成等措施来提升 MCI 的构建速度。


构建移动 CI 平台

我们通过构建移动 CI 平台,来保证移动研发在项目依赖极其复杂的情况下,也能互不影响完成业务研发集成;其次我们设计了合理的 CI 策略,来帮助移动研发人员走出令人望而生畏的依赖关系管理的“泥潭”。


流程自动化建设

在构建移动 CI 平台的基础上,我们对 MCI 流程进行自动化建设来解决研发流程琐碎问题,从而解放移动研发生产力。


提升构建速度

在 CI 平台保证集成正确性的情况下,我们通过依赖扁平化以及优化集成方式等措施来提升 MCI 的构建速度,进一步提升研发效率。


静态检查体系

我们建立一套完整自研的静态检查体系,针对移动项目的特点,MCI 上线全方位的静态检查来促进 App 质量的提升。


日志监控 &分析

我们对 MCI 体系的完整流程进行日志落地,方便问题的追溯与排查,同时通过数据分析来进一步优化 MCI 的流程以及监控移动 App 项目的健康状况。


信息管理配置

最后,为了方便管理接入 MCI 的移动项目,我们建设了统一的项目信息管理配置平台。


接下来,我们将依次详细探讨 MCI 架构体系是如何一步步建立,进而解决我们面临的各种问题。


四 、构建移动 CI 平台

4.1 搭建移动 CI 平台

我们对目前业内流行的 CI 系统,如:Travis CI、 CircleCI、Jenkins、Gitlab CI 调研后,针对移动项目的特点,综合考虑代码安全性、可扩展性及页面可操作性,最终选择基于 Gitlab CI 搭建移动持续集成平台,当然我们也使用 Jenkins 做一些辅助性的工作。MCI 体系的 CI 核心架构如下图所示:



名词解释


  • Gitlab CI:Gitlab CI 是 GitLab Continuous Integration(Gitlab 持续集成)的简称。

  • Runner:Runner 是 Gitlab CI 提供注册 CI 服务器的接口。

  • Pipeline:可以理解为流水线,包含 CI不同阶段的不同任务。

  • Trigger:触发器,Push 代码或者提交 Merge Request 等操作会触发相应的触发器以进入下一流程。


该架构的优势是可扩展性强、可定制、支持并发。首先 CI 服务器可以任意扩展,除了专用的服务器可以作为 CI 服务器,普通个人 PC 机也可以作为 CI 服务器(缺点是性能比服务器差,任务执行时间较长);其次每个集成任务的 Pipeline 是支持可定制的,托管在 MCI 的集成项目可以根据自身需求定制与之匹配的 Pipeline;最后,每个集成项目的任务执行是可并发的,因此各业务线间可以互不干扰的进行组件代码集成。


4.2 CI 流程设计

一次完整的组件集成流程包含两个阶段:组件库发版和向目标 App 工程集成。如下图所示:



第一阶段,在日常功能开发完毕后,研发提 PR 到指定分支,在对代码进行Review、组件库编译及静态检查无误后,自动发版进入组件池中。所有进入组件池中的组件均可以在不同 App 项目中复用。


第二阶段,研发根据需要将组件合入指定 App 工程。组件 A 本身的正确性已经在第一阶段的组件库发版中验证,第二阶段是检查组件 A 的改变是否对目标 App 中原有依赖它的其它组件造成影响。所以首先需要分析组件 A 被目标 App 中哪些组件所依赖,目标 App 工程按照各自的准入标准,对合入的组件库进行编译和静态分析,待检查无误后,最终合入发布分支。


通过组件发版和集成两阶段的 CI 流程,组件将被正确集成到目标项目中。而对于存在问题的组件则会阻挡在项目之外,因此不会影响其它业务的正常开发和发版集成,各业务研发流程独立可控。


4.3 设计合理的 CI 策略

组件的发版和集成能否通过 CI 检查,取决于组件当前的依赖以及组件本身是否与目标项目兼容。移动研发需要对组件当前依赖有足够的了解才能顺利完成发版集成,为了减小组件依赖管理的复杂度,我们设计了合理的发版集成策略来帮助移动研发走出繁琐的版本依赖管理的困境。


组件集成策略

每个组件都有自己的依赖项,不同组件可能会依赖同一个组件,组件向目标项目集成过程中会面临如下一些问题:


  • 版本集成冲突:组件在集成过程中某个依赖项与目标项目中现有依赖的版本号存在冲突。

  • App 测试包不稳定:组件依赖项的版本发生变化导致在不同时刻打出不同依赖项的 App 测试包。


频繁的版本集成冲突会导致业务协同开发集成效率低下,App 测试包的不稳定性会给研发追踪问题带来极大的困扰。问题的根源在于目标项目使用每个组件的依赖项来进行集成。因此我们通过在集成项目中显示指定组件版本号以及禁止动态依赖的方式,保证了App 测试包的稳定性和可靠性,同时也解决了组件版本集成冲突问题。


组件发版策略

组件向组件池发版也一样会涉及依赖项的管理,简单粗暴的方法是指定所有依赖项的版本号,这样做的好处是直观明了,但研发需要对不同版本依赖项的功能有足够的了解。正如组件集成策略中所述,集成项目中每个组件的版本都是显示指定并且唯一确定的,组件中指定依赖项的版本号在集成项目中并不起作用。所以我们在组件发版时采用自动依赖组件池中最新版本的方式。这样设计的好处在于:


  • 避免移动研发对版本依赖关系的处理。

  • 给基础组件的变更迭代提供了强有力的推动机制。


当基础组件库的接口和设计发生较大变化时,可以强有力的推动业务层组件做相应适配,保证了在高度解耦的项目架构下保持高度的敏捷性。但这种能力不能滥用,需要根据业务迭代周期合理安排,并做好提前通知动员工作。


五、、流程自动化建设

研发流程琐碎的主要原因是研发需要人工参与持续集成中每一步过程,一旦我们把移动研发从持续集成过程中解放出来,自然就能提高研发生产力。我们通过项目集成发布流程自动化以及优化测试包分发来优化 MCI 流程。


项目集成流程托管


研发流程中的组件发版、组件集成与 App 打包都是持续集成中的标准化流程,我们通过流程托管工具来完成这几个步骤的自动衔接,研发同学只需关注代码开发与 Bug 修复。


流程托管工具实现方案如下:


  • 自动化流程执行:通过托管队列实现任务自动化顺序执行,webhook 实现流程状态的监听。

  • 关键节点通知:在关键性节点流程执行成功后发送通知,让研发对流程状态了然于胸。

  • 流程异常通知:一旦持续集成流程执行异常,例如项目编译失败、静态检查没通过等,第一时间通知研发及时处理。


打包发布流程托管


无论 iOS 还是 Android,在发布 App 包到市场前都需要做一系列处理,例如 iOS 需要导出 ipa 包进行备份,保存符号表来解析线上 Crash,以及上传 ipa 包到 iTC(iTunes Connect);而 Android 除了包备份,保存 Mapping 文件解析线上 Crash 外,还要发布 App 包到不同的渠道,整个打包发布流程更加复杂繁琐。


在没有 MCI 流程托管以前,每到 App 发布日,研发同学就如临大敌守在打包机器前,披荆斩棘,过五关斩六将,直到所有 App 包被“运送”到指定地点,搞得十分疲惫。如同项目集成流程托管一样,我们把整个打包发布流程做了全流程托管,无人值守的自动打包发布方式解放了研发同学,研发同学再也不用每次都披星戴月,早出晚归,跪键盘了(捂脸)。


包分发流程建设


对于 QA 和研发而言,上面的场景是否似曾相识。Bug 是 QA 与研发之间沟通的桥梁,但由于缺乏统一的包管理和分发,这种模糊的沟通导致难以快速定位和追溯发生问题的包。为了减少 QA 和研发之间的无效沟通以及优化包分发流程,我们亟需一个平台来统一管理分发公司内部的 App 包,于是 MCI App 应运而生。


MCI App 提供如下功能


  • 查看下载安装不同类型不同版本的 App。

  • 查看 App 包的基础信息(打包者、打包耗时、包版本、代码提交 commit 点等)。

  • 查看 App 包当前版本集成的所有组件库信息。

  • 查看 App 包体占用情况。

  • 查询 App 发版时间计划。

  • 分享安装 App 包下载链接。


未来 MCI App 还会支持查询项目集成状态以及 App 发布提醒、问题反馈,整合移动研发全流程。



六、提升构建速度

移动项目在构建过程中最为耗时的两个步骤分别为组件依赖计算和工程编译。


组件依赖计算


组件依赖计算是根据项目中指定的集成组件计算出所有相关的依赖项以及依赖版本,当项目中集成组件较多的时候,递归计算依赖项以及依赖版本是一件非常耗时的操作,特别是还要处理相关的依赖冲突。


工程编译


工程编译时间是跟项目工程的代码量成正比的,集团业务在快速发展,代码量也在快速的膨胀。


为了提升项目构建速度,我们通过依赖扁平化的方法来彻底去掉组件依赖计算耗时,以及通过优化项目集成方式的手段来减少工程编译时间。


依赖扁平化


依赖扁平化的核心思想是事先把依赖项以及依赖版本号进行显示指定,这样通过固定依赖项以及依赖版本就彻底去掉了组件依赖计算的耗时,极大的提高了项目构建速度。


  • 减轻研发依赖关系维护的负担。

  • App 项目更加稳定,不会因为依赖项的自动升级出现问题。


优化集成方式

通常组件代码都是以源码方式集成到目标工程,这种集成方式的最大缺点是编译速度慢,对于上百万行代码的 App,如果采用源码集成的方式,工程编译时间将超过 40 分钟甚至更长,这个时间,显然会令人崩溃。


使用源码集成


使用二进制集成

实际上组件代码还可以通过二进制的方式集成到目标工程:



相比源码方式集成,组件的二进制包都是预先编译好的,在集成过程中只需要进行链接无需编译,因此二进制集成的方式可以大幅提升项目编译速度。


二进制集成优化

为了进一步提高二进制集成效率,我们还做了几件小事:


(1)多线程下载


尽管二进制集成的方式能减少工程编译时间,但二进制包还是得从远端下载到 CI 服务器上。我们修改了默认单线程下载的策略,通过多线程下载二进制包提升下载效率。


(2)二进制包缓存


研发在 MCI 上触发不同的集成任务,这些集成任务间除了升级的组件,其它使用的组件二进制包大部分是相同的,因此我们在 CI 服务器上对组件二进制包进行缓存以便不同任务间进行共享,进一步提升项目构建速度。


二进制集成成果

我们在 MCI 中采用二进制集成并且经过一系列优化后,iOS 项目工程的编译时间比原来减少 60%,Android 项目也比原来减少接近 50%,极大地提升了项目构建效率。




七、、静态检查体系

除了完成日常需求开发,提高代码质量是每个研发的必修课。如果每一位移动研发在平时开发中能严格遵守移动编程规范与最佳实践,那很多线上问题完全可以提前避免。事实上仅仅依靠研发自觉性,难以长期有效的执行,我们需要把这些移动编程规范和最佳实践切实落地成为静态检查强制执行,才能有效的将问题扼杀在摇篮之中。


静态检查基础设施

静态检查最简单的方式是文本匹配,这种方式检查逻辑简单,但存在局限性。比如编写的静态检查代码维护困难,再者文本匹配能力有限对一些复杂逻辑的处理无能为力。现有针对 Objective-C 和 Java 的静态分析工具也有不少,常见的有:OCLint、FindBugs、CheckStyle 等等,但这些工具定制门槛较高。为了降低静态检查接入成本,我们自主研发了一个适应 MCI 需求的静态分析框架–Hades。


Hades 的特点


  • 完全代码语义理解

  • 具备全局分析能力

  • 支持增量分析

  • 接入成本低


Hades 的核心思想是对源码生成的 AST(Abstract Syntax Tree)进行结构化数据的语义表达,在此基础上我们就可以建立一系列静态分析工具和服务。作为一个静态分析框架,Hades 并不局限于 Lint 工具的制作,我们也希望通过这种结构化的语义表达来对代码有更深层次的理解。因此,我们可以借助文档型数据库(如:CouchDB、MongoDB 等)建立项目代码的语义模型数据库,这样我们能够通过 JS 的 Map-Reduce 建立视图从而快速检索我们需要查找的内容。关于 Hades 的技术实现原理我们将在后续的技术 Blog 中进行详细阐述,敬请期待。


MCI 静态检查现状

目前 MCI 已经上线了覆盖代码基本规范、非空特性、多线程最佳实践、资源合法性、启动流程管控、动态行为管控等 20 多项静态检查,这些静态检查切实有效地促进了App 代码质量的提高。



八、日志监控 &分析

MCI 作为大众点评移动端持续集成的重要平台,稳定高效是要达成的第一目标,日志监控是推动 MCI 走向稳定高效的重要手段。我们对 MCI 全流程的日志进行落地,方便问题追溯与排查,以下是部分线上监控项。


流程时间监控分析

通过监控分析 MCI 流程中每一步的执行时间,我们可以进行针对性的优化以提高集成速度。



异常流程监控分析

我们会对异常流程进行监控并且通知流程发起者,同时我们会对失败次数较多的 Job 分析原因。一部分 CI 环境或者网络问题 MCI 可以自动解决,而其它由于代码错误引起的异常 MCI 会引导移动研发进行问题的排查与解决。



包体监控分析

我们对包体总大小、可执行文件以及图片进行全方面的监控,包体变化的趋势一目了然,对于包体的异常变化我们可以第一时间感知。




除此之外,我们还对 MCI 集成成功率、二进制覆盖率等方面做了监控,做到对 MCI 全流程了然于胸,让 MCI 稳定高效的运行。


九、信息管理配置

目前 MCI 平台已经接入公司多个移动项目,为了接入 MCI 的项目进行统一方便的信息管理,我们建设了MCI 信息管理平台——摩卡(Mocha)。Mocha 平台的功能包含项目信息管理、配置静态检查项以及组件发版集成查询。


项目信息管理

Mocha 平台负责注册接入 MCI 项目的基本信息,包含项目地址、项目负责人等,同时对各个项目的成员进行权限管理。


配置静态检查项

MCI 支持不同项目自定义不同的静态检查项,在 Mocha 平台上可以完成项目所需静态检查项的定制,同时支持静态检查白名单的配置审核。


组件发版集成查询

Mocha 平台支持组件历史发版集成的记录查询,方便问题的排查与追溯。


作为移动集成项目的可视化配置系统,Mocha 平台是 MCI 的一个重要补充。它使得移动项目接入 MCI 变得简单快捷,未来 Mocha 平台还会加入更多的配置项。


十、总结与展望

本文从大众点评移动项目业务复杂度出发,详细介绍了构建稳定高效的移动持续集成系统的思路与最佳实践方案,解决项目依赖复杂所带来的问题,通过依赖扁平化以及二进制集成提升构建速度。在此基础上,通过自研的静态检查基础设施 Hades 降低静态检查准入的门槛,帮助提升 App 质量;最后 MCI 提供的全流程托管能力能显著提高移动研发生产力。


目前 MCI 为 iOS、Android 原生代码的项目集成已经提供了相当完善的支持。此外,MCI 还支持Picasso项目的持续集成,Picasso 是大众点评自研的高性能跨平台动态化框架,专注于横跨 iOS、Android、Web、小程序四端的动态化 UI 构建。当然移动端原生项目的持续集成和动态化项目的持续集成有共通也有很多不同之处。未来 MCI 将在移动工程化领域进一步探索,为移动端业务蓬勃发展保驾护航。


作者简介

  • 智聪,大众点评 iOS 技术专家,专注于移动工具链开发,对移动持续集成、静态分析平台建设有深刻理解和丰富的实践经验。

  • 邢轶,大众点评 Android 技术专家,专注于移动持续集成、静态分析、静态化等 App 基础设施建设。


2020 年 2 月 19 日 20:51208

评论

发布
暂无评论
发现更多内容

一个三本生的Java进阶之路:6年时间,从菜鸟到阿里P7!

Java架构之路

Java 程序员 架构 面试 编程语言

“看得见 摸不着”的数字货币 助推数字经济强国建设

CECBC区块链专委会

数字经济

开课啦 dubbo-go 微服务升级实战

阿里巴巴云原生

容器 微服务 云原生 k8s dubbo

牛批!阿里P9用一图点透程序员在大厂晋升“潜规则”与“方法论”(附:阿里内部笔记分享)

Java成神之路

Java 程序员 架构 面试 编程语言

滚雪球学 Python 之内置函数:filter、map、reduce、zip、enumerate

梦想橡皮擦

28天写作 3月日更

音乐api接入HIFIVE音乐开放平台,获取百万正版音乐,最快30分钟集成上线!

HIFIVE嗨翻屋

API sdk 音乐 物联网,API,sdk

守护网络安全不是问题,iptables的四表五链为你开启“八卦阵”

华为云开发者社区

网络安全 iptables 虚拟私有云 安全组 网络ACL

进阶面试皆宜!阿里强推Java程序员进阶笔记,差距不止一点点

周老师

Java 编程 程序员 架构 面试

【动态规划/路径问题】强化 DP 分析方法练习题 ...

宫水三叶的刷题日记

LeetCode 数据结构与算法 面试数据结构与算法

Redis 如何存储上亿级别的用户状态?

薇薇

数据库 redis 存储

一份MyBaits框架PDF文档,阿里架构师直呼牛逼!Java程序员快收藏吧

Java成神之路

Java 程序员 架构 面试 编程语言

世纪联华的 Serverless 之路

Serverless Devs

Java Serverless 架构 运维 云原生

Linux C/C++ 学习路线(已拿腾讯、百度等)

赖猫

c++ Linux服务器开发 LinuxC/C++

四年Java开发,面试核心知识点(腾讯+阿里+快手面经)附答案

Java架构之路

Java 程序员 架构 面试 编程语言

Linux 查询 OS、CPU、内存、硬盘信息

薇薇

Linux cpu 内存

2021版阿里Java亿级并发设计手册:基础+数据库+缓存+消息队列+分布式+维护+实战

Java成神之路

Java 程序员 架构 面试 编程语言

三面阿里成功入职,多亏了面试前刷了这份Redis速成笔记,我才成功抗住了Redis连珠炮!

程序员小毕

Java redis 架构 面试 阿里

偶获阿里大佬纯手码“887”页Java面试手册,突击学习,成功跳槽阿里!

互联网架构师小马

Java 程序员 面试 求职 找工作

大厂社招Java面经:蚂蚁金服、拼多多、字节跳动(现已入职蚂蚁)

Java架构之路

Java 程序员 架构 面试 编程语言

身份和访问管理(IAM)

龙归科技

iam 身份和访问管理

如何破解区块链人才的结构性问题?

CECBC区块链专委会

区块链

震荡的比特币:区块链的“照妖镜”

CECBC区块链专委会

数字货币

2021年爆锤39K月薪Offer!阿里巴巴Java面试(知识点)整理

Java架构追梦

Java 阿里巴巴 架构 面试 全栈知识点

2021首面斩获P7Offer!阿里Java面试(知识点)整理开源分享!

Java王路飞

Java 程序员 面试 阿里 offer

Nacos配置安全最佳实践

Robert Lu

nacos 配置中心

Mysql是怎么运行的-读书笔记1

一个大红包

3月日更

华为云PB级数据库GaussDB(for Redis)介绍第四期:高斯 Geo的介绍与应用

华为云开发者社区

数据库 redis 华为云 geo Gauss DB

大作业(二)

cc

金三银四面试技术储备:阿里Spring Security Oauth2.0认证授权全套技术笔记开源分享!

程序员小毕

Java 源码 程序员 架构 springsecurity

#开工新姿势#开启一年新征程,云社区叫你来充电啦!

华为云开发者社区

内容 技术人 华为云 文章 云社区

亿级用户中心的设计与实践

互联网架构师小马

Java 程序员 架构 亿级流量 用户中心

MCI:移动持续集成在大众点评的实践-InfoQ