Hyperloop 是服务于美团点评客户端的组件发版、持续集成、App 打包构建、资源调度等各个环节的发布调度系统。名称起源于美国 Elon Musk 构想的 Hyperloop 超级高铁,象征着现代、简洁、高效。
Hyperloop 提供了一站式的平台,管理着美团点评 iOS 业务的超过 300 个组件和包括美团 iOS 客户端在内的4个App。接入 Hyperloop 系统后,开发同学可以通过 Hyperloop 来管理自己的项目,配置发版和打包所需要的步骤和检查项。开发完成时,用户只需要登录 Hyperloop 进行相关操作,Hyperloop 就会根据项目的配置去调用不同的步骤,上报每个步骤的状态,给出错误日志、状态通知等。
说到发布,我们首先想到的就是持续集成和交付,而说到持续集成和交付,我们又会自然而然地想到 Jenkins。没错,我们之前的所有和发布工程相关的流程都是与 Jenkins 密切相关,其任务的调度、自动化的构建等功能深受我们的喜爱。
可是随着我们的业务爆发式的增长,加之对 Jenkins 的深入使用,一些问题逐渐暴露出来了:
业务量的增多,导致参与到整个发布流程中的同学也越来越多,而因为 Jenkins 偏向于专业的配置和运维步骤,给我们普通的开发同学带来很多 Jenkins 的使用和维护上的问题,让我们发布工程的同学不得不花大量的时间来进行答疑和维护。
Jenkins 中存在的 Job 数量也随着业务的扩张而变的十分庞大。
一级目录数量 | 总 Job 数量 |
---|---|
74 | 569 |
为什么会有这么多的任务呢?因为我们发布流程会提供一些必要的功能,而每个业务方在使用这些功能的时候需要配置一些自己的业务参数,出于 Jenkins 的一些局限性,常规的做法就是复制一份示例 Job 然后改成自己的构建任务。
所以说这么多的业务方乘以这么多的业务,就造就了这么多的 Job……
这么多的 Job 带来了不小的问题,不管是新策略的推广,还是 Job 的维护都是 N 倍的工作量。
这么多的 Job,结果基本上没有办法集中统计。此外,Jenkins 中数据分析和呈现能力偏弱,而数据对于我们现如今的开发是尤为重要的,不仅能够反应出我们的工作成果,还能及时反馈出我们工作中的问题。
有人会说,我们可以利用 Jenkins 插件来解决上述的问题。
的确,Jenkins 凭借着自己丰富的插件和较为成熟的社区,有着较高的拓展性,但是经过我们的调研和评估,发现由于整个系统的设计并不是一个集中式的管理系统,所以很多功能都局限于 Job 而非系统层面。
另外,由于对于数据的收集和存储能力偏弱,所以我们经常要考虑如何解决数据保存的问题。
如果能够完美的解决上述问题,从成本上来说,通过对 Jenkins 的二次开发的性价比相较于打造一个全新的系统就低了很多。
因此,我们认为一个拥有中央调度功能的系统可以为我们整个项目带来诸多便利,所以打造一个 Hyperloop 这样的系统的想法应运而生。
从技术角度划分,我们把 Hyperloop 划分为 Web 前端、后端和工具链。前端专注于良好的用户交互和清晰的数据展示,后端则负责数据收集分析、业务处理和任务调度,而工具链是负责具体的发版、集成等任务的执行。
后端接受来自前端用户触发的操作,反馈数据或者调用工具链执行相关任务,所有的任务数据流都流经后端,从而能够保证构建数据的完整性。
组件的发布和集成阶段都需要有准入,但实际上每个组件的准入步骤并不一定完全一致,并且随着业务的需要,准入步骤也会相应的调整。面对这样的需求,将准入步骤插件化则是一个比较灵活方式。
工具链会先行开发准入步骤,这是一个可以接受参数的 fastlane 的 action。完成开发后,我们会在 Hyperloop 后台上线对应的能力。
组件在自己的设置界面可以看到 Hyperloop 中所有已上线的能力,有一些是必选的,则默认就已经选上了,其他非必选的能力,则有该组件配置权限的同学可以根据自己业务需要勾选。
有一些检查,例如 warning 数,是可以设置一个目标值的,在未来的某个时间点达到什么样的目标,之后每一次准入都会由后台动态计算本次需要达到的目标。
App 的打包集成准入则是通过打包模板的方式来配置准入步骤,相较于发版的简单方式,集成打包则需要有多种情况供用户选择。除了和组件一样,可以配置目标值,打包模板还可以灵活设置参数配置方式。
将某个能力勾选之后,组件或者打包模板中就会生成对应的策略,不同于能力的是,策略中保存了组件或打包模板中业务方配置的参数。
每一次组件发版,每一次集成打包,都会生成一个版本,Hyperloop 后台会根据能力和策略生成本次执行时具体的步骤,和策略类似,不过步骤中参数则是更为具体的值。
随着发版和集成任务被触发,工具链被调用后会请求 Hyperloop 后台,下发本次执行的步骤,工具链拿到后就会按照具体的步骤和参数来执行任务了。
这样插件化的模型设计,大大减少了工具链的开发成本,并且增加了整个准入步骤的灵活性,更加符合业务方自己的需求。
组件是支撑整个美团 iOS 客户端的基础,前面也提到了,现在有超过300个组件通过我们的这个系统来发布,而在整个开发周期中,又有超过700次的发布需求。而作为整个客户端的发布流程的起点,组件发版又有着尤为重要的作用,所以在整个系统搭建之初,组件发版是我们优先考虑的功能。
在第一阶段,我们实现了基本的组件发布能力,业务方已经可以通过 Hyperloop 来对自己的业务组件进行发版。
但是对于一个全新的发布调度系统,仅仅用于发版是远远不够的,既然我们可以做到数据的汇总分析,那么就可以通过在准入中添加一些特殊的能力,使项目中一些可以优化的指标得以实现,例如 warning 数的分析和限制。所以在完成了基本的发版准入后,我们又增加了一些可选的优化能力。
提到限制,可不仅仅是设置一个数值这么简单,Hyperloop 允许用户设置目标值和目标时间,动态地计算出每一次需要达到的数值,从而通过程序这种强制性的手段,来实现工程上面的优化。
有了准入限制,只能说完成了这个功能的一大部分,数据的的展示有多种多样,既然我们拿到了组件发布时的全部数据,那就让它有一个很好的展示。所以第三阶段,我们又完善了整个组件发布的信息,以及添加了一些功能性的能力,例如 Changelog 的生成,以丰富整个发布过程,让用户能够更清楚地了解到这一次发布的状况。
如果发布失败了,我们会在出错的步骤中展示错误的原因和建议,以及出错的 log,方便大家调查出错原因。
组件发布后,就去集成到美团 iOS 客户端的主工程里面,所以完成了发布功能后,我们就开始着手实现打包集成。
作为美团点评最大的 iOS 项目之一,美团 iOS 客户端不管是从业务量级,还是整个打包集成发布的流程,都是非常复杂的,参与 RD 人数也很多。当我们对全公司 iOS 项目分析后发现,如果实现了美团 iOS 客户端的打包集成,那么别的独立 App 也都能够适用。
在这个功能的第一阶段,我们简单的适配了之前的集成流程,为了让整个发版集成流程尽早可以完整的连起来。满足了基本可用的条件后,我们参考组件发布的步调,开始完善整个集成的流程。第一步,就是增加准入限制。
如果说组件发版是整个美团 iOS 客户端搭建的第一步,那么集成就是第二步,也是至关重要的一步。作为集成来讲,准入尤为重要,可以说客户端的各项性能指标是否符合要求,基本上就看集成准入是否能够过滤掉不合格的组件。
所以我们会在基本的集成能力中加入例如包大小检查这样的增强型准入检查,而在集成包构建完成之后,会进行自动化测试,保证本次集成除了没有编译错误,还不会有运行时问题。
当然了,作为二进制集成,我们还需要保证我们的组件间 APIs 调用正确,所以我们还会进行全源码编译,来确保没有调用不一致的问题。
同样,Hyperloop 在集成时所收集的信息,都会展示出来。不同于组件发布,集成后有诸多产物,各位 RD 可能会有下载需求,我们还会把所有的产物都打包上传到美团云上,提供下载链接。
我们虽说有内部的分发平台,但是高频次的集成带来的集成包数量也是非常多的,在集成详情界面提供可以扫一扫就能下载的二维码,方便 RD 和 QA 下载下来验证自己的需求。
除了集成,我们还有个很重要的功能就是打包。作为一些小一点的业务方,自己并没有什么集成的需求,而更多的是希望能够按照自己的需求来打一个包出来。例如用于验证功能的 feature test,用户每日构建的 daily build,或者说用于提交 iTC(iTunes Connect) 的 App Store build。
之前的做法是,业务方自己创建 Jenkins job,自己配置构建脚本,虽说业务方之间任务独立,但是基本上很大程度都是重复的。
Hyperloop 为各业务方提供通用的打包能力,业务方可以根据需求组成自己的打包模板,每一次打包的时候只需要根据自己的需求选择相应的打包模板即可。
虽说能力都有参数,但是在设置打包模板的时候可以固定配置一些参数,简化每一次的操作步骤,甚至像 App Store build 就可以做到完全零配置,点一下打包即可完成构建触发。
同样的,完成打包后,相应的界面也能看到本次构建的详细信息。
从一开始我们就提到 Jenkins 对于我们普通的 iOS 开发者而言,不管是使用成本还是维护成本都是比较高的,而其他方面诸多限制致使我们想要搭建一个这样的系统。
虽说是因为要去 Jenkins,但是我们在一开始也只是降低了对 Jenkins 的依赖,但还是利用 Jenkins 来分配执行任务。
而仔细审视一下,我们不难发现,我们对 Jenkins 的使用也仅仅是分配任务了,为了这一个简单的需求我们还要保留 Jenkins,维护两套系统,并且通过系统间 APIs 来通信,非常恶心。
比较巧合的是,后台和工具链都是 Ruby 栈的,这样来看,工具链完全可以成为后台模块中的一部分,通过消息队列就能达到我们想要的效果,并且直接对数据库的操作,统一的功能开发,也让整套逻辑变得十分优雅。
这样来看,Jenkins 就彻底的从我们的视线中消失了。
如何才能让用户知道整个流程的结果?如何才能更好地向用户反馈出现的问题?除了前端界面展示详细数据外,主动通知能力也是个非常重要的功能,毕竟大家不可能一直守在 Hyperloop 面前。
我们提供有内部 IM 工具(大象)的消息通知,重要的问题我们还有邮件通知。
如果出现问题,用户会第一时间收到来自 Hyperloop 的消息,当然了,如果顺利结束,系统也会恭喜你顺利完成了此次构建。
除了常规的构建通知,一些重要事项的提醒我们也是有能力告知的,例如开发者证书是否要过期? Provisioning Profile 是否要更新?Hyperloop 有什么需要通知大家的新闻等等……
说了这么多,Hyperloop 是否能够解决我们之前所遇到的问题呢?
我们通过新的系统来取代 Jenkins,人性化的界面和交互流程,清晰的信息展示和问题反馈,基本上让用户能很轻松地完成自己的发布流程,大大降低了他们的学习操作成本。
Hyperloop 是一个中央集中式的系统,所有的业务方可以根据自己的业务来使用我们提供的能力,减少了各自为政所带来的冗余,重复的任务配置,也方便我们流程维护和技术升级。不管是运维成本还是技术推动成本都极大地降低。
不同于之前的流程,Hyperloop 有着强大的数据汇总和分析能力,由于对于整个流程的参与,所有的信息都存储在 Hyperloop 中,方便分析和展示。作为日常工作的重要指标,数据扮演着尤为重要的角色。
有了数据,我们就能从数据中发现问题,解决问题,从而优化我们的项目,也能从方向性上提升我们的工作效率。
Hyperloop 虽说已经能够处理解决大多数发布流程相关的任务,但是未来依然任重而道远。
虽说我们能够汇总和分析数据,但是很多方面的监控和统计力度仍然不够,例如静态分析问题,重复代码检查等等。只有不断丰富整个工程中的监控指标,才能逐渐暴露出隐藏在项目中的一些问题,解决并且优化整个项目。
目前整个 Hyperloop 上下游中已经充斥着 Git 托管平台,美团云,iTC 以及 IM 等诸多系统,可是作为整个开发流程来讲,我们可能还需要和更多系统之间的通信,例如在构建完成后可以自动管理相应的任务,可以在一个阶段完成后自动产生一个统计报表输出到 wiki 中等等。通过上下游多系统联动,从而进一步提升我们的开发效率。
Hyperloop 目前仅仅是支持 iOS 业务,但是整个发布工程可是不限于 iOS 的,所以我们未来希望能够让所有还在发布工程中挣扎的同学们都能搭乘上 Hyperloop,让开发专注于开发的本质,发布仅仅是点一个键的事情。
上面也提到过,我们一些功能是延承自之前的流程,而作为一个全新的系统,我们完全可以用更高效的流程来提升构建效率,运用政治经济学中生产力和生产关系的理论,我们有了更强大的生产力,那也需要有与之相适应的生产关系才能保证和进一步提高生产力。流程,正是如此。
我们做了这么多,其实本质就是让 RD 专注于开发,减少无谓的时间消耗,而发布的事情就让系统化的东西来解决。同时又能通过集中式的系统来保证整个流程的管控力度和数据统计,从另一个方面反推我们的开发。这就是 Hyperloop 名字的意义,不仅仅是个 loop,还是个现代、简洁、高效的 loop。
恩生(@zesming),美团点评高级工程师,2014年加入原美团,曾负责美团 iOS 客户端的首页、订单等重要业务。目前负责 iOS 发布工程的流程制定、Hyperloop 的功能设计和整个系统后台开发。
发现文章有错误、对内容有疑问,都可以关注美团点评技术团队微信公众号(meituantech),在后台给我们留言。我们每周会挑选出一位热心小伙伴,送上一份精美的小礼品。快来扫码关注我们吧!