ReactNative在美团外卖客户端的实践

美团外卖自2013年创建以来,一直处于高速发展期。美团外卖所承载的业务,也从单一的餐饮业务,发展到餐饮、超市、生鲜、果蔬、药品、鲜花、蛋糕、跑腿等十多个大品类业务。伴随着业务的快速发展,我们深切地感受到3个痛点:

(1)业务要求快速发版试错和原生迭代周期长

美团外卖业务长期使用H5+Native的技术栈。由于原生应用需要依托于应用市场进行更新,这样的话,每次产品的更新必须依赖用户的主动更新,使得版本的迭代周期变得很长,无法实现快速发版快速试错的诉求。H5虽然具备随时发布的能力,但受限于内核的影响,平台兼容性并不好,性能也较差,而且调用Native的能力也受限,往往只能满足一定范围内的产品需求。

(2)有限的客户端研发资源无法满足日益增长的业务

业务的快速发展对客户端的开发效率不断提出挑战。如何通过技术手段,在有限的客户端人力资源下,支持更多的业务需求,解决有限的研发资源跟不断变大的业务需求量之间的矛盾呢?试想,如果能逐渐地磨平Android和iOS开发技术栈带来的问题,支持一套代码在2个平台上线,理论上人效可以提升一倍,支持的业务需求也可以提升一倍。

(3)业务持续增长带来的安装包的大幅增长

上图是外卖App引入MRN后的架构全景图,接下来我们会从下到上、从左到右逐步介绍:

RN官方对双端只提供了30多个常用组件,与成熟的Native开发相比,天壤之别。所以我们在开发的过程中面临的一个很重要问题就是组件的缺失。于是,MRN团队基于RN组件进行了丰富,引入了一些优秀的开源组件,但是源于外卖业务的特殊性,一方面需要业务定制,另一方面部分组件依然缺失。所以为了减少重复代码,提升外卖客户端MRN的研发效率,建设外卖组件库就变得非常有必要。

上图是我们外卖组件库的架构图,最底层依赖Android和iOS的原生服务;然后是MRN基建层,用于抹平Android和iOS系统之间的差异;再上一层则是外卖组件库及其依赖,如平台组件库和打包服务,组件库分为两类:纯JS组件和包含JS和Native的复合组件。再上一层则是Android和iOS的MRN容器,它提供了上层Bundle的运行环境。整个组件的架构思路,是利用中间层来屏蔽平台的差异,尽可能地使用JS组件,减少对原生组件的依赖。这样可以有效地减少上层业务开发时对平台的理解。接下来,我们主要讲一下WM-RN组件库:

目前,美团外卖App存在三种技术栈:Native、MRN、H5,面对业务持续增长和安装包不断变大的压力,选择合适的技术栈显得尤为重要。H5在性能和用户体验方面相比Native和基于Native渲染的RN相对弱一些,所以目前大部分H5页面只是用来承载需求变更频繁、需要即时上线的活动页面。那么MRN和Native的界限是什么呢?当有一个新的页面产生时,我们应该如何做取舍?通过实践,我们逐渐摸索了一套选型规则,如下:

具体选型细节可参考下表:

发布运维是一个成熟的软件项目中非常核心的部分,它保证了整个项目能够高效且稳定地运转。建立一个稳定可靠的发布运维体系是我们建设整个外卖MRN技术体系的重要目标。但发布运维的建设上下游牵扯了众多基建:拥有一个合理的工程结构对发布运维来说至关重要。如果工程结构臃肿且混乱,将会引起的一系列的权限问题、管理维护问题,这样会严重制约整个发布运维体系的效率。所以MRN的工程架构演进优化也是发布运维体系建设的重要组成部分。

业务分库

任何一个大型、长期的前端技术项目,良好的工程结构都是研发发布支撑中非常核心的部分。从2018年10月份,外卖正式启动MRN项目以来,面临涉及近百个MRN和几十人参与的大规模MRN应用计划。从项目初期,我们就开始寻找一个非常适合开发维护的工程结构。

工程结构

在项目初期,对于每个库的工程结构,美团内部比较流行的工程结构有两种:一个是适合小型业务开发的单工程多Bundle方案,另一个是相对更适合中大型业务开发的多工程多Bundle方案。

单工程单Bundle方案

顾名思义,单工程单Bundle方案的意思就是一个前端工程承载所有的业务代码,最终的产物也只有一个RNBundle。通过入参决定具体加载哪个页面。

对于业务不多,参与人不多的团队,使用单工程单Bundle的方式即可快速完成开发、发布。因为通过一次发布就可以完成整个发布的工作,但是带来的弊端也是不可接受的:因为所有业务都耦合在一起,每次更新都会“牵一发而动全身”,增大了问题的隐患。如果多个业务需求同时提测的时候,在团队配合上也是一个极大的挑战,因为新版本号会覆盖旧版本号,导致两个需求提测时会出现相互覆盖的情况。所以我们在立项之初就排除了这种方案。

多工程多Bundle方案

多工程多Bundle方案的意思就是一个Git库中存放了多个页面文件夹,各个文件夹是完全独立的关系,各自是一个完整的前端工程。拥有自己独立的MRN配置信息、package.json、组件、Lint配置等(如下图所示)。每个页面文件夹都输出一个独立的RNBundle。

相比于单工程单Bundle方案,多工程多Bundle方案将页面进行解耦,使之基本可以满足中大型MRN项目的需求。在外卖MRN项目初期,一直都使用着这样的工程结构进行开发。但是我们也为之付出了相应的代价,即每个页面的依赖都需要对应RD去维护升级,依赖碎片化的问题日趋严重。同时在工程级别的管控,如统一Lint规则、GitHook等也变得更加复杂。

多工程多Bundle方案=>单工程多Bundle方案

随着外卖MRN页面规模以及参与人规模的进一步增大,多工程多Bundle方案的缺点日益凸显。特别对于那些前端技术底子相对薄弱的团队来说,依赖管理问题会变得很头疼。在这种情况下,单工程多Bundle的方案就应运而生了。

核心思路也很简单:观察一下单工程单Bundle方案和多工程多Bundle方案的优缺点可知,单工程单Bundle依赖管理方便的优点主要来自于“单工程”,而多工程多Bundle的业务解耦的优点主要来自于“多Bundle”。所以结合这两种工程方案的核心优点,就可以设计一种新方案:单工程多Bundle。即用一个工程去承接所有的页面代码,但是又可以让每个页面输出独立的RNBundle来保证互不影响。其实,这种方式类似于Native一个静态库的管理,如下图所示:

通过分析MRN的打包原理可知,MRN通过一个配置文件配置了一个Bundle的所有业务信息以及mrn-pack2的打包入口。所以我们只需要让配置文件支持多份Bundle信息的配置,通过打包命令与参数选择正确的mrn-pack2打包入口,即可打出我们最终所需要的业务Bundle。如下图所示:

核心优势:

这种工程组织形式也成为了MRN工程结构的最佳实践,而且美团内部也有多个团队采用了这种解决方案。目前已支撑超过几百个页面的开发和维护工作。

下图展示了我们的发布运维全景,共覆盖了开发交付、线上发布、线上监控、有效应对、复盘改进等五大模块。接下来我们会逐一进行介绍。

(1)开发交付

开发阶段,需求RD完成开发,提交到Git库的发布分支。对应的业务库主R角色(通常由RN经验较丰富的工程师来承担)进行CodeReview,确认无误之后会执行代码的合并操作。顺便说一下,这也是外卖RN质量保障长征路的第一步。

(2)线上发布

合入发布分支之后,就可以正式启动一次RNBundle发布。这里我们借助了美团内部的Talos完成整个发布过程,Talos的发布模板与插件流水线规范了一次发布需要的所有操作,核心步骤包括发布准备(Git拉代码、环境参数确认、本次发布说明填写)、发布自检(依赖问题检查、Lint、单元测试)、正式打包(Build、版本号自更新)、产物上传测试环境(测试/线上环境隔离、测试环境进行测试),双重确认(QA、Leader确认发布)、产物上传线上环境等等。

产物上传线上环境,实际上是上传到了美团内部的CD平台–Eva。在Eva上,我们可以借助RNBundle的发布配置去约束发布App的版本号、SDK版本等,以及具体的发布比例及地区,去满足我们不同的发布需求。最终执行发布操作,将RNBundle上传到CDN服务器,供用户下载,完成整个发布流程。

(3)运维监控

发布之后,运维是重中之重。首先我们的运维难点在于我们的业务横跨两个平台——美团App与外卖App。由于它们在基建、扩展、网络部分都存在差异,所以我们选取指标的维度不仅要从业务出发,还要增加全局的维度,来确保外卖平台MRN的正常运转。基于这个层面的思考,我们选取了一系列RN核心指标(在下面的章节会详细列举),进行了全方位的监控。目前外卖客户端,已经做到分钟级监控、小时级监控和日级别监控等三档监控。

除了监控报警手段之外,我们还会借鉴客户端高可用性保障的经验。用一些日常运维的手段去发现问题。比如使用灰度小助手、数据日报等手段从宏观角度主动去发现存在隐患的指标,及时治理,避免问题。

(4)有效应对

根据“墨菲定律”:如果事情有变坏的可能,不管这种可能性有多小,它总会发生。即便我们在发布管控和线上监控上做的再充分,线上问题最终还是无法避免的。所以当通过线上告、客诉等手段发现线上问题之后,我们需要及时的应对问题、解决问题,把问题带来的影响降低到最小,并以最快的速度恢复对用户的服务。

这两种备案保障了外卖MRN业务的整体高可用性。

(5)复盘改进

在以上四个大环节中,问题可能会出现在任意一个环节。除了及时发现问题与解决问题,我们还需要尽力避免问题。这一点主要是靠我们内部的例会、复盘会,对典型问题进行Review,将问题进行归类,包括复盘流程规范问题、操作失误问题、框架Bug等,并力图通过规范流程、系统优化来尽力地避免问题。

在外卖MRN项目实施过程中,我们共推动了二十多项规范流程、系统优化等措施,大大保障了整体服务的稳定性。

最后,我们用一张图对外卖监控运维体系做一个总结,帮助大家有一个全局的认知。

评审阶段

开发阶段

客户端以周维度进行开发,每周确定下周可提测的内容,根据提测内容是否为动态化的业务、下周是否在版本迭代周期内,决定跟版发布或周发布。

提测阶段

提测前,为了保证MRN页面的提测质量,RD首先需要按照QA提供的测试用例提前发现适配问题。提测时需要在提测邮件中注明:(1)提测的Bundle名称和对应的版本号;(2)标明哪些组件涉及Native模块;(3)依赖变更情况,如是否升级了基础库,升级后的影响范围;(4)重点测试点的建议。

上线阶段

引入MRN后,相对单平台而言,架构层级上,我们增加了2个MRN中间层去屏蔽Android和iOS平台、原生组件之间的差异。这样做的目的是为了让上层业务开发者可以很快地使用框架进行业务开发,完全不用关心平台和组件间的差异。通过引入MRN技术栈,带来的好处很明显:

(1)使用MRN实现的页面理论上可以实现一套代码,部署到不同平台上,开发效率得到大幅度提升。(2)采用MRN框架,无论是加载性能还是页面滑动性的用户体验上,都会比原来H5的方式要好。(3)部分页面具备了快速编译、快速发布的能力。

但一个硬币总有两面,混合式架构增加了架构的复杂度,使得原本只要考虑一个平台的事情,逐渐转变成需要考虑三个平台,另外Android本身具备碎片化的问题,这使得混合式架构的适配问题较为突出。当出现问题时,我们的第一反应由“这是什么问题”变成“它是否存在于两个平台,还是只在一个平台上?”、“如果仅在一个平台上,是在原生代码还是ReactNative代码出了问题?”、“历史版本的MRN是否存在问题,是否需要修复”、“修复的效果在Android和iOS上的表现是否一样”,这些问题增加了定位和修复工作的复杂性。另外,MRN的适应场景也是有限的,并非所有的业务和页面都适合改造成MRN,如何做选择也需要进行有效的判断,从而增加了决策成本。

针对上述问题,我们的建议是:

(1)减少分歧:-在研发、测试、发布和运维环节,MRN的页面尽可能对齐Native原有的环节,减少团队理解的成本。-在Debug开发环境下,利用页面浮层提示技术栈使用情况;Release环境下,利用工具、MRN自动化报表,及时的让开发同学明确知道是Native页面还是MRN页面,减少确认。-MRN页面尽可能地避免原生组件的使用,而使用纯JS代码实现,供MRN页面使用的原生组件的需要高质量的提供,减少下层组件的问题。-默认只修复当前的版本,出现严重问题时才考虑修复历史版本,减少多版本带来的复杂度提升。

(2)技术栈明确边界

(3)单技术栈转向多技术栈团队

正如在“监控运维”章节中所讲到的那样,线上运维是我们工作的重中之重。这个章节我们就讲一下我们对于监控指标的选取。鉴于外卖业务的特殊性,除了美团的外卖频道之外,外卖业务还需要运行在独立的外卖App上。如下图所示:

外卖App经过多年的发展,目前已逐渐成为一个平台级应用,承接了C端、闪购、跑腿等多个业务。与美团App相比,它们之间在很多基础建设、扩展、网络部分都存在差异。所以在监控核心指标的选取上,我们除了保证C端MRN业务在美团以及外卖两端的高可用性,还需要保证外卖App平台本身基建的稳定性,从而保证运转在外卖App上所有MRN业务的高可用性。

下载链路

加载链路

加载链路可以细分为初始化引擎部分以及业务Bundle加载部分。前者跟基建有关,代表从引擎创建到加载完Common包加载成功这段的成功率。这部分主要依赖MRNSDK的稳定性,从我们的日报上看,稳定性基本保持在99.99%以上。

使用链路

Bundle加载成功之后,页面成功被渲染。但是在使用的过程中,可能会因为JS代码,Native代码的Bug出现JSError、NativeCrash等问题,这样给用户带来的直观反馈就是应用闪退、页面白屏等,造成了服务的不可用。所以在使用链路上出现问题率,基本也可以直观反映出一个RN页面的质量以及它当前的运行状况。

页面退出成功率(MRNPageExitSuccess),理解起来不如前面的指标那么简单,因为它表示的是用户在退出MRN页面时,业务视图内容已成功渲染的比例。它会包含所有已知和未知的异常,但是用户进入页面后快速退出的场景,也会被错误的统计在其中,因为用户退出时可能页面尚在加载中。相比于JSError,它是一个更加综合的指标,基本上涵盖了加载失败、渲染白屏、使用时出现错误等多个异常场景,基本上可以反映出一次MRN业务的单次可用性,相比于之前的指标会更加严格。我们把这个指标同时列为了外卖App监控告警的全局指标与单Bundle告警的指标。我们希望它永远能保持在99.9%以上,否则就会触发告警。目前外卖大盘的MRNPageExitSuccess基本稳定在万分之三左右,我们最终的目标是希望稳定在万分之一左右。

加载链路耗时

使用时FPS

衡量用户使用体验比较直观的一个指标就是FPS,较高的FPS会让用户更加顺畅地体验功能,完成操作。

目前,MRN在外卖侧业务总体落地页面复杂度适中,遇到复杂动画也使用了BindingX来提升性能。通过监控,外卖侧的页面总体表现良好,在iOS上几近满帧,在Android上表现稍差,平均在55帧左右,较深的视图层级与较低的JS-Native的通信效率都是MRNFPS的杀手。如何提升MRN特别是在Android上的页面性能也是我们下一阶段研究的课题。

引入MRN,提升了本地的开发效率,但同时也增加了工程的复杂度,所以总体来说真的能提升实际开发效率吗?在完成几十个RN页面的开发后,总结了一些公式,希望可以给其他团队一些结论性的参考。首先设定三个方面去考量:人效提升、代码复用、维护成本衡量,将外卖的所有MRN页面加在一起,取平均值,可以得出较为准确的结论:

根据页面的交互程度去进一步的划分,得到如下的表格:

随着业务的快速发展,工程复杂度的不断提升,在没有外力的情况下,开发效率必然会持续下降。如何在资源有限的情况下不断提升开发效率是一个永恒的话题。美团外卖客户端通过借助美团基建MRN,推动混合式架构来提升效率。截至目前,美团外卖业务已经有60多个RN页面上线,每天的PV高达上千万,为用户提供了稳定可靠的服务。

混合式开发带来的不仅仅是技术层面的挑战,更是对团队成员、团队组织能力的挑战。MRN虽然能够做到跨端,但是有时候仍然需要针对特定平台单独编写代码来解决问题,这就间接要求工程师必须熟悉三个平台,团队也必须有效组织各技术栈人才共同协作,才能真正用好MRN。

晓飞、唐笛、维康,均为美团外卖前端团队研发工程师。

美团外卖长期招聘Android、iOS、FE高级/资深工程师和技术专家,Base北京、上海、成都,欢迎有兴趣的同学投递简历到tech@meituan.com(邮件标题注明:美团外卖前端团队)。

THE END
1.开发,测试,运维这三个岗位该如何选择开发测试运维作为互联网行业的测试、运维、和开发职位,这些岗位的需求量都很大。这些职业也都有各自的优缺点; 开发工程师负责项目的概要设计、详细设计以及编码;测试工程师从质量上对软件实施保障工作,确保软件能够符合用户需求;运维工程师负责保证软件产品在生产环境能够工作解决用户使用产品遇到的一些异常。 https://blog.csdn.net/jiegeniuboyi/article/details/139455578
2.测试开发和运维,这三个哪个比较轻松?网友(埃拉)职场问答我做了多年的开发工作,对测试和运维工作也了解一些,根据我的经验来看,这三个工作都不轻松,要是一定https://zq.zhaopin.com/question/7140893/
3.运维开发测试等IT岗位薪酬体系大公开!你拖后腿了吗?网站运维将成为一个融合多学科(网络、系统、开发、安全、应用架构、存储等)的综合性技术岗位,给大家提供一个很好的个人能力与技术广度的发展空间。运维工作的相关经验将会变得非常重要,而且也将成为个人的核心竞争力,具备很好的各层面问题的解决能力及方案提供、全局思考能力等。 https://www.51cto.com/article/595625.html
4.运维是做什么的?运维和测试开发岗位的区别而运维开发岗位的火热也是对相关需求的应运而生,我们都知道互联网岗位是需要不断学习新的计算机语言知识的,这一点对于年纪大点的程序员来说就不太友好了。所以运维岗位如果想转化到开发或者测试岗位最好早点考虑。 以上就是我今天给大家带来的运维是做什么的小分享,另外还有运维和开发、测试岗位的一些区别。大家都看https://baidu-mip.xianjichina.com/news/details_271215.html
5.运维是做什么的?运维和测试开发岗位的区别运维和测试、开发岗位的区别 运维(Operation)是指负责维护和支持软硬件服务的一系列过程,它既可以是一项运行活动,也可以是一个完整的工作岗位。一般来说,运维工作包括:建立操作标准和流程,构建和维护网络和服务,管理服务器和存储设备,维护计算元件和电子化系统,监控网站和其他应用的安全性和可用性,发现潜在的流量和HDDhttps://www.sgpjbg.com/info/6f3cd6c834c7c5ed284ae66955c86d05.html
6.你了解软件测试和运维吗?没错!正如你所看到的,什么都得会,一个需要会这么多技术才能做好的工作,你是不是觉得工资不低了,但其实不然,运维工程师是工资普遍低于开发工程师,而且发展空间小,一般开发工程师3-5年基本可以往管理层发展,月薪2-5万,但是运维工程师的工资想要提升却是举步维艰,一直停留在6k-8k也是很正常的事情。 https://www.jianshu.com/p/f07449fe7c41
7.软件测试”“移动应用设计与开发”“大数据应用开发”“5G4月11日-12日,由吉林省教育厅主办长春职业技术学院承办的2024年吉林省职业院校技能大赛(高职组)“软件测试”“移动应用设计与开发”“大数据应用开发”“5G组网与运维”四个赛项在我校信息学院圆满落幕。 “软件测试”赛项共有来自省内12所高职院校的24支参赛队,共44名选手参赛。本赛项内容以企业级真实项目为载体http://www.cvit.edu.cn/info/1180/2194.htm
8.RAM账号权限管理内部技术团队分为开发、测试和运维,环境分为开发环境、测试环境、生产环境。由此构建相应的用户组和RAM用户遵循以下原则:不创建云账号AccessKey,不使用云账导进行日常运维管理,仅做用户及权履管理,开启MFA;需要控制台置陆的RAM用户不要生成AK,开启MFA。程序调用API的RAM用户不要授权控制台登陆。https://developer.aliyun.com/article/858399
9.系统运维岗位职责20篇5、负责配合开发搭建测试平台,协助开发设计、推行、实施和持续改进。 6、负责相关故障、疑难问题排查处理,编制汇总故障、问题,定期提交汇总报告。 岗位要求: 1、 2年以上大中型在线系统运维工作经验、精通Linux系统及常见服务的安装配置,熟悉常见的`负载均衡实现方案并有实际实施经验; https://www.yjbys.com/hr/gangwei/3844025.html
10.python教程Python语言简介一个互联网产品的生成一般经历的过程是:需求分析、研发部门开发、测试部门测试、运维部门部署发布以及长期的运行维护。运行维护的日程主要工作包括服务部署、服务监控等。运维的工作繁琐重复,即使最谨慎的人,也会犯错,尤其是面对着重复性工作。通过运维自动化工具来完成这样的工作,错误率将大大降低。 https://www.xiaomawang.cn/help/71640.html
11.运维测试招聘网2025年运维测试招聘信息猎聘2025年运维测试招聘信息,海量高薪猎头职位等你来选,了解运维测试岗位要求、薪资待遇等真实招聘信息,找高薪职位,上猎聘!https://www.liepin.com/zpyunweiceshi/
12.开发一个手机app需要多少人?1个人能完成开发吗?如果用传统方式编程开发手机app,需要经过需求分析、UI设计、前端开发(安卓开发/苹果开发)、后端开发、测试上线、后期维护等流程。至少需要配置1名产品经理、1名UI设计师、1名安卓开发工程师、1名IOS开发工程师、1名后端开发工程师、1名测试工程师、1名运维工程师等7人。 http://www.apppark.cn/t-38971.html
13.软件开发环境的几个名词(DEVSITUATPROD)在软件开发、测试、运维,经常听到DEV,SIT,UAT,Prod等名词,按时间阶段排序: DEV:Development Environment 持续集成开发环境 源代码编译打包,单元测试,服务API自动化测试,服务UI自动化测试,合并代码,开发联调 SIT:System Integrate Test Environment 系统集成测试环境(内测) https://blog.oxings.com/article/80
14.软件供应链安全减少开发和安全团队对漏洞进行发现、审查、确认、修复的时间。 悬镜灵脉IAST灰盒安全测试平台 灵脉IAST为研发、测试、运维等非安全专家设计,简单易用的界面和自动化的检测能力使得任何人都可快速上手,变身安全专家。灵脉IAST可集成于悬镜夫子、Jira、Jenkins等第三方漏洞管理和项目管理平台,不改变原有的工作流程,不增加https://www.xmirror.cn/page/solution/