阅读更多
引用
作者简介: 刘李丰,携程无线基础工程团队高级经理,负责无线交付平台和基础服务研发。十多年的互联网从业经验,曾供职于 eBay 等互联网公司,研发经验丰富。
责编:唐小引,技术之路,共同进步。欢迎技术投稿、给文章纠错,请发送邮件至tangxy@csdn.net。
声明: 本文为《程序员》原创文章,未经允许请勿转载,更多精彩文章请订阅 2017 年《程序员》

引用
导语:携程 App 几乎承载着整个集团的所有业务形态,亟需一个有效的无线持续交付平台来实现大版本的快速集成发布,由此,携程无线工程技术团队从零开始,一步步打造适合携程研发流程的无线持续交付平台。本文为“携程无线工程技术系列”第一篇。

目前携程大部分订单已来自移动端,App 几乎承载了整个集团的所有业务形态。在内部研发中,携程的 App 已经发展成为拥有 90+ Native Bundle、100+ Hybrid Bundle、30+ React Native Bundle,几百名研发人员,每个版本(1 个月)交付 4000+个 App 包,Hybrid/React Native/HotFix/Bundle 发布次数 500+。如果没有一个有效的无线持续交付平台,很难实现大版本的集成发布在 3 天内完成。而对比市场上开源的无线持续集成工具 Fastlane、TestFlight、Jenkins 都存在各种定制化需求的问题。因此我们从零开始,逐步打造适合携程研发流程的无线交付平台,系统化地解决研发支撑痛点。下面将从集成、测试、发布、运营四个子平台来展开,具体分享我们是如何一步步打造无线持续交付平台的。

集成平台
从最初到现在,携程无线持续交付模型经历了从 1.0 到 2.0 的迭代演进。在 1.0 之前,App 集成和发布还主要依靠人工操作 Jenkins,需要由特定的打包人员负责打包,再将包通过 IM/邮件等方式传递给其他测试人员,测试结果需要专人手工回收,以把控 App 质量。此时最大的问题就是 App 管理混乱,人工介入过多,每次发布都需要花费很长的时间。

1.0 阶段
在 1.0 阶段,我们引入 MCD(Mobile Continues Delivery)平台思路,将打包人员的工作交给平台来完成,提高了发布工作效率。这时不需要专职人员负责出包,平台会定时自动打包,测试人员可以到平台上自由取包(通过下载链接或扫描二维码的方式)进行测试。与此同时,测试人员也可以在平台上进行单独的打包和测试。测试结果会统一反馈到平台上来,协调人员在平台根据各家的反馈结果决定需要重新出包还是继续下一步发布操作。

在这个阶段,App 的打包还完全依赖于源代码进行,由平台生成打包参数(主要包含 App 运行环境、与 iOS 签名相关的参数以及代码仓库相关的参数)提交给后台的打包系统。它会根据仓库地址和 commit ID 从代码仓库中拉取全量代码,然后打包系统再调用代码中预先准备好的 Build 脚本构建 App 产物,构建完成后将结果保存至临时的文件服务中,最后由平台的回收进程将构建结果回收并处理之后放在云存储上供用户下载使用。

2.0 阶段
1.0 阶段虽然已经基本实现了集成打包的自动化,但是还存在以下几点不足:
  • 源码打包方式效率低下,每次都要从代码仓库中下载全量代码,再通过源代码生成 App 产物。这样做使得每次 Build 时间都很长,而打包次数的增加会导致某些打包任务积压,系统不能及时出包。
  • 编译容易失败,任何一个 Check-in 导致的编译失败,就会致使系统不能正常出包。
  • 系统之间采用轮询模式,Job 任务扩展性差。
MCD 系统发起 Build 请求之后会有另一个定时的 Job 任务去轮询 Build Server 查看 Build 结果。在初期阶段还能满足业务需求,但是后来由于打包数量的增加以及打包频率的提高,系统的处理效率变得越来越低。一方面打包资源不够(Android 打包使用 Linux 虚拟机,iOS 打包使用 Mac),另一方面轮询 Job 的处理效率达到了瓶颈。打包机器采用 Jenkins 方式进行管理,因此很容易进行横向扩展,但是 Job 却很难扩容。

针对以上问题,我们对平台进行了升级改造,主要为:
  • 引入消息机制,提高系统吞吐量;
  • 将工程进行拆分,按照 Bundle 的方式进行打包。
消息机制的改造:
首先基本打包架构和流程保持不变,在 MCD 系统和 Build Server 之间增加消息系统,MCD 发起 Build 之后不再轮询 Build Server,而是消费由 Build Server 产生的 Build 完成消息,如图 1 所示。使用这样的生产消费模型 MCD 可以轻易地进行水平扩展,系统执行效率得到极大改善。

图 1 Bundle 打包

工程拆分:
App 工程拆分成多个不同的 Bundle 模块,Bundle 之间存在依赖关系。在这个情况下 App 的编译和打包也可以按照 Bundle 的方式进行组织。在开发阶段,开发人员提交完代码之后就能直接将自己负责的 Bundle 编译成可执行文件,测试可以自由选择 Bundle 进行打包。此时打包工作只需将多个 Bundle 文件组装在一起就行,极大地加快了打包速度。通过测试的 Bundle 会被发布到指定地点,在 App 集成阶段只需把所有发布的 Bundle 组装成最终 App 供大家测试即可。

在开发自测阶段,开发人员提交完代码后在 MCD 平台上 Build 出所开发的 Bundle(标记为 L,表示 Latest)。相关测试人员(或开发人员自己)可以打测试包,测试包会使用所有 Bunde 的 L 版本进行构建。构建完成之后获取测试包进行功能测试,测试通过后就可以将该 Bundle 进行发布操作,即标记为 RC 版本(表示 Release Candidate)。

图 2 测试打包发布

如图 2 所示,在集成测试阶段,MCD 平台会自动选取已发布(RC 版本)的 Bundle 打出集成包,测试完成后测试人员可以将测试结果反馈到 MCD 平台中,待测试全部通过之后就可以安排 App 进入发布定版阶段,再进行一些后续市场包操作就可提交给 App 应用市场供用户下载。

由于 App 的开发是个连续过程,测试包和集成包都可以很方便地配置是需要 Hourly build 还是 Daily build,并且可以和测试平台的相关功能联动,从而实现持续集成。

我们也会将不同版本(不同功能)的 App 按照项目进行划分,主版 App 为标准项目,非主版(渠道/HotFix/Bundle)App 为非标准项目,同一项目内的 Bundle 可以自由组合,项目之间互相独立,不受影响。一个项目在创建时可以选择从另一个项目继承其各模块的最新版和发布版。项目在开发过程中也可以从其父项目中实时同步对应模块的最新版和发布版,这样就能基本满足各种开发和测试的需求。

测试平台
随着携程持续交付的发展,原有的测试模式以及流程渐渐显现出不足,主要体现在以下三点:
  • 快速验证与手工验证的冲突;
  • 自动化回归测试与手动测试效率的矛盾;
  • 设备兼容测试与设备不足的矛盾。
快速验证与白屏检测
在集成测试阶段,每一次出包首先会由基础测试人员负责验证此次出包的质量,主要是验证各个 BU 入口页面 Hybrid 或直连页面是否正常,如果大量 BU 入口页面异常则会要求重新出包。这个过程看似很简单,但是“(沟通成本+验证成本)*出包次数”所耗费的时间也是不容忽视的,且这种冒烟测试对于测试人员也很枯燥无趣。

图 3 集成包

针对以上情况,最初引入了白屏测试等基础性测试功能,并与集成平台打通(见图 3,可以直接从集成包列表选择相关测试功能)。白屏测试主要是检测 App 首页各个入口页面是否显示正常,对于每一个页面会进行图像比对以及页面长度来验证页面是否正常,白屏会在多个设备进行测试,只要其中一台设备通过,则认为这个入口是正常的。

自动化回归测试
通过回归测试自动化,可以提高回归测试效率,有效缓解测试人员的压力。我们逐步开发了 MCD 测试平台用于自动化测试项目的管理、执行、报告和展示,支持 Android/iOS App、HTML5/Hybrid Testing。

图 4 测试平台架构

测试平台架构简化图如图 4 所示,各个模块主要功能如下:
  • Portal 负责与用户交互,查看报表,保持后台系统对用户透明;
  • Invoker 是调度通道,用户基于 Portal 提交的测试任务通过此通道来调度,包括创建项目、设备占用、测试项目执行等;
  • Lab Center 负责所有与设备相关的业务,Lab Center 与二次开发的开源软件 STF 交互,所有设备挂载在 STF 上;
  • 当具体的测试项目在 Jenkins 上执行时,会将预先占用的设备远程连接到 Slave 上等待使用。
MCD 测试平台提供了自动化测试(白屏检测、录制回放、回归测试)、系统测试(兼容性、性能、稳定性)、手动测试(远程租用、远程调试)三大类功能,基本达到了我们对于提高测试效率的需求,如图 5、图 6 所示。

图 5 Mobile 项目列表


图 6 自动化测试 Task Case 页面

另外,日常测试中还经常遇到这些情况:需要快速验证 App 的一个功能,有些问题只能在特定机型上重现,测试目前却没有这款手机。因此我们基于 STF 二次开发出设备共享平台,将空闲设备收集起来在平台上共享,用户只需在平台上搜索需要的设备就可以立刻通过 STF 进行使用了,如图 7 所示。

图 7 设备租用

同时,我们还建立了代码质量的自动化,集成 Sonar、Facebook Infer 和 Uint Test 功能,方便每个版本对代码质量进行跟踪,如图 8 所示。

图 8 代码质量自动化追踪

发布平台
无线发布系统一直以来都是无线应用能快速迭代最关键的一环,一个好的发布系统能帮助开发快速地修复线上问题,并能快速将新功能投送至用户,帮助业务抢占市场,而发布系统的设计也随着 CD(Continuous Delivery)概念的深入人心而日新月异。
无线发布的特点是静态资源包(不管是 Hybrid、React Native 还是 HotFix、Bundle),发布技术中涉及到的主要问题如下:
  • 如何最大限度地把静态资源的下载流量降到最低,以减少用户对应用更新的感知度,提高应用升级的成功率和用户体验。
  • 灰度发布,保证发布的质量。
资源包发布
针对静态资源包发布,经历了如下几个历程:
  • 全量包发布: 携程最初使用的都是全量发布的方式,这种方式实现简单,但也简单暴力,而问题也比较明显,导致用户升级时流量巨大。
  • 文件字符串差分: 这种方法避免了整包差分的问题,能够比较方便地实现快速迭代要求下的小量更新需求,并且文本差分工具简单,实现容易,出错较少,但缺点是差分效果差。
  • 文件二进制差分: 对每个文件进行二进制级别的差分能够具备小量快跑的特点,同时进一步优化差分文件 Size。这也是携程目前使用的方式,它仍然使用了 bsdiff 作为差分工具,当文件没有更新时,不输出差分文件,而更新时也只产生 Size 非常小的 diff 文件。
  • 按需差分: 在按需差分前,我们采取的是预差分方案。就是在发布时,把所有的版本间差分准备好,有多少个历史版本就将产生多少个差分包。按照这种做法,随着发布次数的增多,发布差分包数量也将急剧增长,对存储的要求越来越高,也造成了浪费。
在此前提下,引入了按需差分,就是终端用户通过将自己的版本号与线上最新版本号做比较,发现落后时,触发差分过程,从而获取增量更新。

这里会有一个问题——终端用户第一次访问时没有差分包,我们的做法是:第一次只返回全量包,用户不用等待,但是后续用户会拿到差分包。

另外一个问题是,避免重复打差分包。在计算时发现无差分包,会触发差分包过程,同时会把这个信息缓存(过期时间半个小时)。当其他客户端同样的版本请求时,会先判断缓存,没有的话进行差分操作,有的话直接下发全量包。

灰度发布
网站发布通常是有灰度发布的过程,无线的发布跟网站发布流程是类似的,但是做法有差别。二者的区别是:网站是 centralize 的,可以统一控制,而无线的发布是 decentralized。无线发布包,像 Hybrid、React Native、HotFix 等静态资源,是需要客户端一个个来拉取的。那么,如何确保整个发布的流畅,确保发布质量呢?我们的解决方案如下:
Offline 灰度发布流程
灰度第一步是冒烟,网站的冒烟是导一部分流量到某台 Server 上,而我们则是通过配置一个白名单,只有客户端在白名单中的才会获取到最新发布。当测试没有通过,可以选择终止,然后再决定是否需要回滚,测试通过决定是否需要扩大比例。

监控发布数据
当客户端收到下载物后,会把当前的下载信息上报上来,供发布人员进行监控查看。
灰度发布设计中需要注意:
  • 避免一直小白鼠:为了避免一个用户一直当小白鼠,每次灰度需要利用灰度 ID+客户端信息进行取模运算。
  • 灰度回滚:灰度回滚时只需要回滚已经更新这次灰度的客户端,对于没有更新到的,则无需回滚。
运营平台
运营是研发流程的最后一环,携程的 MCD 平台思路是能够针对发布结果、运营情况以及配置等功能有一个集中的管理。目前包含了运营看板、性能看板、发布看板、无线配置、崩溃管理、App Size 统计等模块。

其中无线配置经历了多次迭代,对于各种配置项,从版本、平台、渠道、A/B 多个角度进行了定义,做到灵活动态配置,需改就改,粒度大小自由配置。下发时根据 App 的版本、平台、渠道等信息挑选符合条件的配置进行发布。需要修改的时候也是先修改测试环境配置,测试通过后再同步到生产。配置分为专用版和通用版两种,专用版只会下发给特定的渠道/版本,通用版以版本号为基准,在不发布新版本配置的情况下系统默认给 App 端下发最近的通用版配置。当同时存在符合条件的专用版和通用版的时候,只下发专用版配置。

崩溃管理也是无线运营的重要一环,尽管目前行业内已经有崩溃管理功能强大的平台,但由于定制性需求我们也搭建了自有崩溃管理功能,方便快速发现线上问题,从而能够通过 HotFix/Bundle 方式及时修复,如图 9 所示。

图 9 崩溃管理页面

结束语
以上是携程无线基础工程团队在无线持续交付方面的一些工程实践,MCD 的核心目标是能够对集成、测试、发布和运营的完整生命周期提供更好的平台支撑和管理。虽然取得了一些成果,但还有许多提升空间,例如多应用支持、支持条件发布等,无线持续发布之路依然有很多工作要做。
  • 大小: 73.4 KB
  • 大小: 63.3 KB
  • 大小: 40 KB
  • 大小: 45.3 KB
  • 大小: 38.3 KB
  • 大小: 51.8 KB
  • 大小: 24.6 KB
  • 大小: 36.5 KB
  • 大小: 47.1 KB
1
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • mybatis的一级缓存和二级缓存

    一、什么是缓存 ...二、mybatis一级缓存 1、一级缓存简介 一级缓存作用域是sqlsession级别的,同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第

  • MyBatis 的一级缓存和二级缓存

    文章目录一、前言二、一级缓存三、二级缓存3.1、开启二级缓存:四、测试一下五、总结: 一、前言 先说缓存,合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,...

  • 4.二级缓存解析

    二级缓存也称作是应用级缓存,与一级缓存不同的,是它的作用范围是整个应用,而且可以跨线程使用。所以二级缓存有更高的命中率,适合缓存一些修改较少的数据。在流程上是先访问二级缓存,在访问一级缓存。

  • MyBatis一级缓存和二级缓存

    根据缓存存放位置,缓存可以分为本地缓存和分布式缓存。根据缓存作用范围,缓存可以分为永久缓存和临时缓存。在 MyBatis 中,根据作用范围,分别有一级缓存和二级缓存两种类型。

  • Mybatis一级缓存与二级缓存

    通常我们会为每个单表创建单独的映射文件,由于MyBatis的二级缓存是基于namespace的,多表查询语句所在的namspace无法感应到其他namespace中的语句对多表查询中涉及的表进行的修改,引发脏数据问题。

  • Mybatis二级缓存

    Mybatis二级缓存原理

  • MybatisPlus开启二级缓存

    本篇博客是讲解如何开启MyBbatisPlus的二级缓存教程,若文章中出现相关问题,请指出! 所有博客文件目录索引:博客目录索引(持续更新) 开启二级缓存 1、mapper接口添加注解 @Repository @Mapper @CacheNamespace ...

  • Mybatis 中的一级缓存与二级缓存

    Mybatis 中的一级缓存与二级缓存

  • SpringBoot整合Redis配置MyBatis二级缓存

    本文讲的是在SpringBoot项目中整合使用 Redis,并使用 Redis实现MyBatis 的二级缓存。使用场景就是在高并发的环境下,大量的查询直接落入DB,会导致数据库宕机,从而导致服务雪崩的情况。我们使用Redis作为MyBatis二...

  • mybatis之一级缓存和二级缓存~

    根据二级缓存的工作机制一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中`,**如果当前会话关闭了,这个会话对应的一级缓存就没有了,但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级...

  • Mybatis二级缓存详解

    基于3.5.10版本的Mybatis源码,彻底搞清楚二级缓存是什么,是在哪里生效的,是怎么开启的,各自作用域是什么

  • Mybatis的CachingExecutor与二级缓存

    上次我们讲Mybatis的缓存时,我们提到了CachingExecutor,知道了这个带缓存的执行器就是二级缓存的来源,这次我们系统的分析下其是如何产生作用的。

  • Mybatis 之 二级缓存

    但是⼀级缓存是基于sqlSession的,⽽⼆级缓存是基于mapper⽂件的namespace的,也 就是说多个sqlSession可以共享⼀个mapper中的⼆级缓存区域,并且如果两个mapper的namespace 相同,即使是两个mapper,那么这两个...

  • mybatis一级缓存和二级缓存使用详解

    针对mybatis一级缓存和二级缓存使用进行详细说明,搞清楚mybatis缓存的生命周期。

  • 一级缓存和二级缓存的区别

    一级缓存指的是Session,而不同的SQLSession缓存数据的区域是互不影响的,只能作用于在同一个Session中 二级缓存 指的是mapper级别的缓存,实现不同会话中数据的共享,跨SQLSession的,作用范围更大

  • 一级缓存二级缓存的区别

     ②、二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。二级缓存底层还是个HashMap去实现。 开启二级缓存代码: <!....

  • MyBatis——关于一级缓存 & 二级缓存的案例详解

    文章目录: 1.写在前面 2.关于MyBatis中的缓存 3.一级缓存案例详解 3.1 首先写一个实体Bean 3.2 dao接口、对应的mapper映射文件 ...3.3 mybatis配置文件、...4.1 开启二级缓存之后,实体类需要实现序列化 4.2 dao

  • 安卓桌面应用EyeRoom.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

  • 仿随手记的炫酷饼图.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

  • webview重载使用&自定义网址.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

Global site tag (gtag.js) - Google Analytics