[译]如何快速稳定地构建iOS应用

njkf2843 8年前
   <p>Voyager项目是为了开发LinkedIn新的旗舰级手机应用,去年年初,我们开始在项目中实践3x3哲学:</p>    <p>一天发布三次,从代码提交到用户可以使用,不超过三小时。</p>    <p>虽然我们不能每三个小时向App Store发布一次,但我们每天可以多次构建员工使用的企业产品。“3x3”听起来很快很容易,但说起来容易做起来难。三小时一发布的节奏,让我们没有时间做手工测试,所我们需要一个通道:</p>    <p>1.从代码提交到产品发布,每个环节都完全自动化</p>    <p>2.可靠性要好,甚至要高于手工测试</p>    <p>3.速度足够快,能够适应我们三个小时的窗口期</p>    <p>4.稳定性,确保每个合法提交都会被发布</p>    <p>今年年初的时候,Drew Hannay在他的博客,3x3:加速手机应用的发布中简要介绍了手机应用3x3哲学。围绕快速和稳定构造,我们将深入探索3x3在iOS应用开发中的应用。</p>    <h2>第一部分:速度</h2>    <p>为了获得一个从代码提交到发布小于三小时的通道,我们通过重构Swift代码,加速编译速度,加速我们的UI测试框架,构造和测试并行等手段,以优化我们的构造通道。</p>    <p>加速代码编译</p>    <p>我们选择Swift做为新的旗舰级应用Voyager的主力开发语言,从最早的1.0到2.0随着Swift的不断升级,我们的项目也在不断演变。</p>    <p>在Voyager项目早期,我们非常享受Swift的易用和先进的功能,但漫长的编译时间长长令我们沮丧。随着起来越多的代码提交到我们的iOS代码库(每天大约60次提交), 我们发现即便只有少数文件发生变更,编译时间也呈指数增长,从数秒到30分钟左右。更糟糕的是发布构建时间比调试构建时间更长,通常需要2个小时。秉承“测试要与开发同步”的原则,我们要另外再花两个半小时来写150个KIF测试。结果,我们需要花四个半小时完成从提交到发布的过程!</p>    <p>为了缓解开发者的挫败感,我们通过Apple开发者社区,Apple开发者论坛和公司合作伙伴关系努力与Apple工程师沟通。并就如何缩短我们的构建时间,获得了很多宝贵的反馈意见。 Jacek Suliga负责一个主要代码库的重构,将我们的工程分成不同的子项目和模块,用显式引用取代隐式引用。这使得调试构建时间几乎缩短了一半,发布构建时间从原来的2小时缩短到35分钟,从提交到发布时间缩短到3个小时。对于本地开发,我们为每个iOS开发人员购置了一台Mac Pro,以减少调试构建时间。</p>    <p>UI测试框架优化</p>    <p>构建时间优化之后,UI测试时间成为瓶颈。Jacek在 UI自动化:保持实用和稳定一文中介绍了我们如何优化开源项目KIF,让它可以5到10倍地提速。这大大缩短了测试时间,测试运行时间缩短了80%,只需要大概20分钟时间。然而,测试越来越多,一个月内增长了四倍,测试时间增长到80分钟,总时间增长到2个小时。</p>    <p>在对编译和UI测试框架做了优化之后,我们认为只有技术创新才能显著解决从提交到发布的时间问题,我们将重点放到了:分布式构建和测试。</p>    <p>分布式构建和测试</p>    <p>我们与基础设施团队密切合作,为iOS和Android提供分布式编译和测试支持。当我们将所有构建和测试任务分发到10台机器上,唯一的瓶颈就变成了发布构建时间,加上一些工具开销,需要35分钟完成。提交到发布的总时间下降到45分钟。使用更多的机器可以进一步提高构建时间,但是也会引入一些可靠性问题,我会在稳定性部分阐述</p>    <h2>第二部分:稳定性</h2>    <p>在我们的构建通道中,从提交到发布,有两个关键组件会影响整体稳定性:测试系统的稳定性和构建工具的稳定性。</p>    <p>1. 测试系统稳定性</p>    <p>在我以前的博客:测试稳定性 - 我们如何让UI测试变得稳定,我讨论了我们如何构建稳定的测试环境。主是是稳定的测试环境,从测试框架中移除不可预测的因素,净化我们的测试组件。请重温一下那篇博客,关于我们如何让我们的测试基础设施变得稳定的细节。</p>    <p>2. 工具稳定性</p>    <p><strong>2.1 硬件稳定性</strong></p>    <p>我们通过cfengine集中管理我们的机器池,现在我们有两类Apple硬件:</p>    <p>Mac Mini (2012年版)</p>    <p>①处理器 2.6GHz Quad-Core Intel Core i7</p>    <p>②内存 16GB 1600 MHz DDR3</p>    <p>③存储 1TB HDD</p>    <p>④Intel HD 显卡</p>    <p>Mac Mini (2014年版)</p>    <p>①处理器 3.0GHz Dual-Core Intel Core i7</p>    <p>②内存 16GB 1600MHz LPDDR3 SDRAM</p>    <p>③存储 512GB PCIe-based Flash Storage</p>    <p>④Intel Iris 显卡</p>    <p>有一次,我们看到建构池中出现内存问题,有10%的机器活动内存小于100MB,大量使用交换分区。当检查这些内存不够用的机器时,我们发现在后台有20多个长期运行的xcodebuild进程。我们意识到这是此前挂起的xcodebuild进程所致。</p>    <p>为了解决这个问题,我们采取了以下行动:</p>    <p>1. 添加重试逻辑,在运行新的任务前,清除所有挂起的xcodebuild进程。</p>    <p>2. 对有可能导致内存溢出的服务每天定期重启。</p>    <p>3. 对交换分区使用较多的机器设置自动报警。</p>    <p><strong>2.2 Mac 系统构建环境稳定性</strong></p>    <p>除了内存问题,我们偶尔也会发现机器上有运行iOS模拟器问题,这些问题影响了整体稳定性。一旦机器上出现模拟器问题,如果不正确处理,它会影响这台机器接下来的所有构建任务。我们曾经付出巨大的努力来解决模拟器问题(参见:企业级iOS持续集成管理),但当我们尝试解决这个问题时,发现还不如先前的效果,因为模拟器工具并不在我们的控制之中。</p>    <p>幸运的是,我们发现重启可以解决绝大部分模拟器问题。我们启动了一个叫PoolGuardian的项目,用来监控所有构建机器,并且定期检查是否有机器出现模拟器问题,如果发现有问题,它会重启这台机器,并且在重新使用这台机器前会做健康检查。</p>    <p><strong>2.3 并行测试稳定性</strong></p>    <p>分布式测试看起来很有前景,因为它确实解决了我们的速度难题,但是当我们遇到一些可靠性问题时,我们意识到它是一把双刃剑。</p>    <p>在我们的Mac系统工具链环境中,我们遇到一些Apple开发者工具链问题,包括间歇性编译崩溃,模拟器崩溃,模拟器重复性错误,和环境错误问题。总之,每天机器的稳定性大概在95%左右。看起来好像还不错,但是在分布式测试中,只有所有子任务全部通过,一个构建才能完成,确切一点说,10个子任务要全部通过。所以每加一个节点,总体可靠性下降到原来的95%,随着结点数的增加,整体可靠性呈指数下降。如果使用10个结点,工具链的可靠性下降到95%10 ≈ 60%。</p>    <p>为了改善上面提到的工具链可靠性问题,我们优化了我们的构建池,使用种种手段让我们的 Max OS X更加可靠。通过这些努力,工具链的稳定性从95%提高到略高于98%。加上其他结点,稳定性仍然有98%10 = 82%。这远远没有达到我们的预期—99%的可靠性。但是解决x10 = 99%需要 x = 99.9%,这就需要99.9%的机器可靠性,这需要更多的资源和精力。</p>    <p>同时,我们试图跳出这个怪圈,我们希望在高可靠性的同时,我们的构建通道可以快速完成提交到发布过程。然后我们有了一个突破:如果我们把所有任务都放到一个测试结点,同时使用多个模拟器跑测试会怎么样?基于这个想法产生了Hydra项目,Hydra的总体目标是:</p>    <p>1. 在一台服务器上使用多个模拟器并行跑测试,让构建时间提高5到10倍。</p>    <p>2. 启用不同模拟器之间的交互测试(iOS与iOS, Android与Android ,iOS与Android)</p>    <p>在这篇博客中,我只涉及第一个目标。下图是多模拟器测试架构。</p>    <p><img src="https://simg.open-open.com/show/f24dead3144cba1877154fef5e464262.png"></p>    <p>当一个提交发生后,测试运行器会构建应用并启动5个模拟器用来组成一个模拟器设备池。构建完成后,测试运行器将查询测试集群,获取一个测试类列表。根据测试用例的数目,测试类会动态分配到20个单元中,并形成一个测试队列。一旦初始化阶段完成,设备池会不断地获取测试任务并运行。同时设备池有一个健康监测进程保证设备池的健康运行。一个测试任务结束后,测试成果和测试报告会被收集并上传到持续集成工具,等待下一个发布周期。</p>    <p>你可能会问,为什么我们选择运行5个模拟器,这是因为OS对每个shell会话的进程有个默认限制,在Mac Mini上是709。每个模拟器会产生大约70个进程。当我们添加300个MacOS系统进程,我们同时只需启动5到6个模拟器。我们曾经试图取消shell进程限制数,但是当超过700个进程时,OS环境会变得很脆弱。所以,权衡扩展性和可靠性,我们选择5个模拟器。</p>    <p>有了Hydra的帮助,我们的构建稳定性从最初的0提高到今天的90%,而且我们还在不断的优化它。下图是一个示例,我们会以我们的方式开源这个项目,敬请关注!</p>    <p><img src="https://simg.open-open.com/show/7491eda1f3cc394cf2090212823bb2b0.jpg"></p>    <p><img src="https://simg.open-open.com/show/f9396a40444c178b82f337d655e61d30.jpg"></p>    <p><img src="https://simg.open-open.com/show/12561f71d5c49e56c143ab76492a423c.jpg"></p>    <p><img src="https://simg.open-open.com/show/860a15671361237fdba985e49eba3575.gif"></p>    <h2><strong>致谢</strong></h2>    <p>如果没有包括工具,测试,移动基础设施和其他LinkedIn团队的专业协作,我们不可能完成这些,谢谢大家。</p>    <p> </p>    <p>来自: <a href="/misc/goto?guid=4959671331058909347" rel="nofollow">http://www.jianshu.com/p/ed44573bab3f</a></p>    <p>原文: <a href="/misc/goto?guid=4959671331157347879" rel="nofollow,noindex">3x3: iOS Build Speed and Stability</a></p>    <p>作者: Keqiu Hu   译者: <a href="/misc/goto?guid=4958964003979423267" rel="nofollow,noindex">杰微刊</a> 兼职翻译张万程 </p>