目前携程大部分订单已来自移动端,App几乎承载了整个集团的所有业务形态。在内部研发中,携程的App已经发展成为拥有90+ Native Bundle,100+ Hybrid Bundle,30+ RN Bundle,几百名研发人员,每个版本(1个月)交付4000+个App包,Hybrid/RN/Hotfix/Bundle发布次数500+。 很难想象,如果没有一个有效的无线持续交付平台,很难实现大版本的集成发布在3天内完成。相比较市场上开源的无线持续集成工具fastlane、test flight、Jenkins都存在各种定制化需求的问题,因此我们从零开始,逐步打造适合携程研发流程的无线交付平台,系统化的解决研发支撑痛点。下面将从集成、测试、发布、运营四个子平台来展开分享我们是如何一步步打造无线持续交付平台的。
集成平台
从最初到现在携程无线持续交付模型经历了从1.0到2.0的迭代,在1.0之前App集成和发布还主要依靠人工操作Jenkins,需要由特定的打包人员负责打包,再将包通过IM/邮件等方式传递给其他测试人员,测试结果需要专人手工回收,把控App质量。此时最大的问题就是App管理混乱,人工介入过多,每次发布都需要花费很长的时间。
1.0 阶段
1.0 阶段我们引入MCD(Mobile Continuous Delivery)平台思路将打包人员的工作交给我们的平台来完成,提高了发布工作效率。这时不需要专职的打包人员负责出包,平台会定时自动打包,测试人员可以到平台上自由取包(通过下载链接或者扫描二维码)进行测试,与此同时测试人员也可以在平台上进行单独的打包和测试。测试结果也会统一反馈到平台上来,协调人员在平台根据各家的反馈结果决定需要重新出包还是继续下一步发布操作。
在这个阶段,App的打包还完全依赖于源代码进行的,由平台生成打包参数(主要包含App运行环境、与IOS签名相关的参数以及代码仓库相关的参数)提交给后台的打包系统,打包系统根据仓库地址和commit ID从代码仓库中拉取全量代码,打包系统再调用代码中预先准备好的build脚本构建App产物,构建完成后将构建结果保存到临时的文件服务中,最后由平台的回收进程将构建结果回收并处理之后放在云存储上供用户下载使用。
2.0 阶段
1.0 阶段虽然已经基本实现了集成打包的自动化,但是还存在以下几点不足:
1. 源码打包方式效率低下,采用源码打包每次都要从代码仓库中下载全量代码,再通过源代码生成出App产物,这样做使得每次Build时间都很长,而打包次数增加导致某些打包任务积压,系统不能及时出包。
2. 编译容易失败,任何一个checkin导致的编译失败,就会导致系统不能正常出包。
3. 系统之间采用轮询模式,Job任务扩展性差。
MCD系统发起Build请求之后会有另一个定时的Job任务去轮询Build Server查看Build结果。在初期阶段还能满足业务需求,但是后来由于打包数量的增加以及打包频率的提高,系统的处理效率变得越来越低。一方面打包资源不够(Android打包使用Linux虚拟机,iOS打包使用MAC),另一方面轮询Job的处理效率达到了瓶颈。打包机器采用Jenkins方式进行管理,因此很容易进行横向扩展,但是Job却很难扩容。
针对以上问题我们对平台进行了升级改造:
1. 引入消息机制,提高系统吞吐量;
2. 将工程进行拆分,按照Bundle的方式进行打包。
消息机制的改造:首先基本打包架构和流程保持不变,在MCD系统和Build Server之间增加消息系统,MCD发起Build之后不再轮询Build Server,而是消费由Build Server产生的Build完成消息,如下图所示。使用这样的生产消费模型MCD可以轻易的进行水平扩展,系统执行效率得到极大地改善。
工程拆分:App工程拆分成多个不同的Bundle模块,Bundle之间存在依赖关系。在这个情况下App的编译和打包也可以按照Bundle的方式进行组织。在开发阶段,开发人员提交完代码之后就能直接将自己负责的Bundle编译成可执行文件。测试可以自由选择Bundle进行打包,此时打包工作只需要将多个Bundle文件组装在一起就行,极大地加快了打包速度。通过测试的Bundle会被发布到指定地点,在App集成阶段只需把所有发布的Bundle组装成最终App供大家测试即可。
在开发自测阶段开发人员提交完代码之后在MCD平台上Build出所开发的Bundle标记为L(表示Latest)。相关测试人员(或者是开发人员自己)可以打测试包,测试包会使用所有Bunde的L版本进行构建。构建完成之后获取测试包进行功能测试,测试通过后就可以将该Bundle进行发布操作,即标记为RC版本(表示Release Candidate)。
在集成测试阶段,MCD平台会自动选取已发布(RC版本)的Bundle打出集成包,测试完成后测试人员可以将测试结果反馈到MCD平台中,待测试全部通过之后就可以安排App进入发布定版阶段,再进行一些后续市场包操作就可提交给App应用市场供用户下载。
由于App的开发是个连续的过程,测试包和集成包都可以很方便的配置是需要hourly build还是daily build,并且可以和测试平台的相关功能联动,从而实现持续集成。
我们也会将不同版本(不同功能)的App按照项目进行划分,主版App为标准项目,非主版(渠道/Hotfix/Bundle)App为非标准项目,同一项目内的Bundle可以自由组合,项目之间互相独立,不受影响。一个项目在创建的时候可以选择从另一个项目继承其各模块的最新版和发布版。项目在开发过程中也可以从其父项目中实时同步对应模块的最新版和发布版。这样就能基本满足各种开发和测试的需求。
测试平台
随着携程无线持续交付的发展,原有的测试模式以及流程渐渐显现出不足,主要体现在以下三点:
1. 快速验证与手工验证的冲突;
2. 自动化回归测试与手动测试效率的矛盾;
3. 设备兼容测试与设备不足的矛盾。
快速验证与白屏检测
在集成测试阶段,每一次出包首先会由基础测试人员负责验证此次出包的质量,主要是验证各个BU入口页面(Hybrid或者直连页面)是否正常,如果大量BU入口页面异常则会要求重新出包。这个过程看似很简单,但是(沟通成本+验证成本)x 出包次数所耗费的时间也是不容忽视的,而且这种冒烟测试对于测试人员也很枯燥无趣。
针对以上情况,最初引入了白屏测试等基础性测试功能,并与集成平台打通(见下图,可以直接从集成包列表选择相关测试功能)。白屏测试主要是检测APP首页各个入口页面是否显示正常,对于每一个页面会进行图像比对以及页面长度来验证页面是否正常,白屏会在多个设备进行测试,只要其中一台设备通过,则认为这个入口是正常的。
自动化回归测试
通过回归测试自动化,可以提高回归测试效率,有效缓解测试人员的压力。我们逐步开发了MCD测试平台用于自动化测试项目的管理、执行、报告和展示,支持Android/iOS App, H5/Hybrid testing。
测试平台架构简化图如下图所示,各个模块主要功能如下:
Portal负责与用户交互,查看报表,保持后台系统对用户透明;
1. Invoker是调度通道,用户通过Portal提交的测试任务通过此通道来调度,包括创建项目、设备占用、测试项目执行等;
2. Lab Center负责所有与设备相关的业务,Lab Center与二次开发的开源软件STF交互,所有设备挂载在STF上;
3. 当具体的测试项目在Jenkins上执行时,会将预先占用的设备远程连接到Slave上等待使用。
MCD测试平台提供了自动化测试(白屏检测、录制回放、回归测试)、系统测试(兼容性、性能、稳定性)、手动测试(远程租用、远程调试)三大类功能,基本达到了我们对于提高测试效率的需求。
另外日常测试中还经常遇到这些情况:需要快速验证App的一个功能,有些问题只能在特定机型上重现,测试目前却没有这款手机。因此我们基于STF二次开发出设备共享平台,将空闲设备收集起来在平台上共享,用户只需在平台上搜索需要的设备就可以立刻通过STF进行使用了。
我们也建立了代码质量分析功能的自动化,集成了Sonar、Facebook Infer和Uint Test功能,方便每个版本对代码质量进行跟踪。
发布平台
无线发布系统一直以来都是无线应用能快速迭代最关键的一环,一个好的发布系统能帮助开发快速的修复线上问题,并能快速的将新功能投送至用户帮助业务抢占市场,而发布系统的设计也随着CD(Continuous Delivery)概念的深入人心而日新月异。
无线发布的特点是静态资源包(不管是Hybrid,RN,还是Hotfix, Bundle),发布技术中涉及到的主要问题:
1. 如何最大限度的把静态资源的下载流量降到最低,以减少用户对应用更新的感知度,提高应用升级的成功率和用户体验。
2. 灰度发布,保证发布的质量。
资源包发布
针对静态资源包发布,经历了如下几个历程:
1. 全量包发布:携程最初使用的都是全量发布的方式,这种方式实现简单,但也简单暴力,而问题也比较明显,导致用户升级时流量巨大。
2. 文件字符串差分:这种方法避免了整包差分的问题,能够比较方便的实现快速迭代要求下的小量更新需求,并且文本差分工具简单,实现容易,出错较少。但是差分效果差。
3. 文件二进制差分:对每个文件进行二进制级别的差分能够具备小量快跑的特点同时进一步优化差分文件size。这也是携程目前使用的方式,它仍然使用了bsdiff作为差分工具,当文件没有更新的时候,不输出差分文件,而更新时也只产生size非常小的diff文件。
4. 按需差分:在按需差分前,我们采取过的方案是预差分方案,就是在发布时,把所有的版本间的差分准备好,有多少个历史版本就将产生多少个差分包,这种做法将随着发布次数的增多,发布差分包数量也急剧增长,对存储的要求将越来越高,也造成了浪费。
在此前提下:引入了按需差分,就是终端用户通过将自己的版本号与线上最新版本号做比较,发现落后时,触发差分过程,从而获取增量更新。
这里会有一个问题:终端用户第一次访问时没有差分包,我们的做法是:第一次只是返回全量包,用户不用等待。但是后续用户会拿到差分包。
另外一个问题是:避免重复打差分包。在计算时发现无差分包,会触发差分包过程,同时会把这个信息缓存(过期时间半个小时),当其他客户端同样的版本请求时,会先判断缓存,没有的话进行差分操作,有的话直接下发全量包。
灰度发布
网站发布通常是有灰度发布的过程,无线的发布跟网站发布是流程是类似的,但是做法有差别。二者的区别是:网站是centralize的,可以统一控制,而无线的发布是decentralized。无线发布包,像Hybrid,RN,Hotfix等静态资源,是需要客户端一个个来拉取的。如何确保整个发布的流畅,确保发布质量呢?我们的解决方案如下:
1. Offline灰度发布流程:灰度第一步是冒烟,网站的冒烟是导一部分流量到某台Server上,与网站的冒烟不同的是,我们通过配置一个白名单,只有客户端在白名单中的才会获取到最新发布。当测试没有通过,可以选择终止,然后再决定是否需要回滚,测试通过决定是否需要扩大比例。
2. 监控发布数据:当客户端收到下载物后,会把当前的下载信息上报上来,供发布人员进行监控查看。
3. 灰度发布设计中需要注意:a) 避免一直小白鼠:为了避免一个用户一直当小白鼠,每次灰度需要利用灰度ID+客户端信息进行取模运算;b) 灰度回滚:灰度回滚时只需要回滚已经更新这次灰度的客户端,对于没有更新到的,则无需回滚。
运营平台
运营是研发流程的最后一环,携程MCD平台思路是对发布结果、运营情况以及配置等功能有一个集中的管理,包含运营看板、性能看板、发布看板、无线配置、崩溃管理、App Size统计等模块。
其中无线配置经历了多次迭代,对于各种配置项,从版本,平台,渠道,AB多个角度进行了定义,做到灵活动态配置,粒度大小自由配置。下发时根据App的版本、平台、渠道等信息挑选符合条件的配置进行发布。需要修改的时候也是先修改测试环境配置,测试通过后再同步到生产。配置分为专用版和通用版两种,专用版只会下发给特定的渠道/版本,通用版以版本号为基准,在不发布新版本配置的情况下系统默认给App端下发最近的通用版配置。当同时存在符合条件的专用版和通用版的时候,只下发专用版配置。
崩溃管理也是无线运营的重要一环,目前行业内的QQ Bugly平台崩溃管理功能已经很强大,但是由于定制性需求我们还是开发了自有崩溃管理功能,方便快速发现线上问题,从而能够通过Hotfix/Bundle方式及时修复。
结束语
以上是携程无线基础工程团队在无线持续交付方面的一些工程实践,MCD的核心目标是能够对无线集成、测试、发布和运营的完整生命周期提供更好的平台支撑和管理,虽然取得了一些成果,但还有许多提升空间,例如多应用支持、支持自由条件发布等,无线持续发布之路依然有很多工作要做。
转载自团队成员作品,作者简介:
刘李丰,目前担任携程无线基础工程团队高级研发经理,负责无线技术平台、持续交付平台以及无线基础服务端的研发工作。十余年互联网工作经验,曾就职于eBay等公司。
欢迎关注携程无线技术公众号『CtripMobile』: