最下层是Android/iOS系统服务层,因为MRN是跨端的,所以需要引入这一层。相对单一平台来说,由于MRN的引入,整个App的架构不可避免地需要考虑Android和iOS平台本身的差异性。
倒数第二层是平台服务层,这一层相对与单一平台来说,并没有太大区别。
再往上一层是MRN基建层,这一层的工作主要是:(1)尽可能地屏蔽Android和iOS系统的差异性;(2)打通已有的平台基建能力,让上层业务不能感知到差异。
再上一层是业务组件层,这一层相对于单一平台来说,区别不大,主要是增加了Android和iOS的RN容器,同时业务组件是可以被RN调用的。
继续往上是MRN接口层,该层的主要任务是尽可能地屏蔽Android和iOS组件之间的差异,让上层页面使用的RN接口保持一致。
最后是业务层,这一层是用户可直接接触到的页面,页面的实现可以是Android/iOS/RN。
左上角是研发支撑,主要包括代码规范、代码检查工具、Debug插件、准入规范、准入检查工具、代码模板插件等。这块相对于单一平台来说,主要的差异体现在:由于编译器和语言不同,使用的工具有所区别,但工具要做的事情基本是一致的。
左下角是测试支撑,主要包括UI自动化测试、自测覆盖率检查、AppMock工具、业务自测小助手、性能测试、云测平台等。这块相对于单一平台来说,基本也是一致的,主要的差异同研发支撑,主要是语言不同,使用的工具有所区别。
右上角是发布支撑,主要包括打包Bundle和APK、打包检查、发布检查、发布Bundle和APK等。这块相对于单一平台来说,保持了打包发布平台的一致性,区别在于:需在原有的基础上,增加MRN的打包发布环节。
右下角是运维支撑,主要包括基建成功率监控、业务成功率监控、线上问题追踪、网络降级等。这块相对于单一平台来说,保持了一致性,区别在于:需在原有的基础上,增加MRN的监控运维。
研发测试支撑 外卖业务MRN组件架构RN官方对双端只提供了30多个常用组件,与成熟的Native开发相比,天壤之别。所以我们在开发的过程中面临的一个很重要问题就是组件的缺失。于是,MRN团队基于RN组件进行了丰富,引入了一些优秀的开源组件,但是源于外卖业务的特殊性,一方面需要业务定制,另一方面部分组件依然缺失。所以为了减少重复代码,提升外卖客户端MRN的研发效率,建设外卖组件库就变得非常有必要。
上图是我们外卖组件库的架构图,最底层依赖Android和iOS的原生服务;然后是MRN基建层,用于抹平Android和iOS系统之间的差异;再上一层则是外卖组件库及其依赖,如平台组件库和打包服务,组件库分为两类:纯JS组件和包含JS和Native的复合组件。再上一层则是Android和iOS的MRN容器,它提供了上层Bundle的运行环境。整个组件的架构思路,是利用中间层来屏蔽平台的差异,尽可能地使用JS组件,减少对原生组件的依赖。这样可以有效地减少上层业务开发时对平台的理解。接下来,我们主要讲一下WM-RN组件库:
如上图所示,WM-RN组件库主要包含三部分:RN interface、RN Native组件、外卖RN JS组件。RN Interface主要包括Native组件的Bridge部分和Native组件在JS侧的封装,封装一层的好处是方便调用Native暴露出的接口,也可以用来抹平Android和iOS系统间的差异;RN Native组件分为Android和iOS两端,依赖各自的业务模块,为RN提供外卖Native的业务能力,如购物车服务、广告服务;外卖RN JS组件则是纯JS实现,内部兼容外卖App与美团外卖频道间的差异、Android和iOS平台间的差异,依赖现有的MRN组件库和外卖开源Beeshell组件库,减少组件的开发成本;从工程的物理结构来看,建议将Native组件、RN Interface放在一个仓库进行管理,主要是因为Native与JS侧的很多通信都是通过字符串来匹配的,放在一起方便双端与JS侧的接口统一对齐,发布时也会更加方便。目前,外卖组件库已经扩展了几十个业务组件,支持了线上近百个MRN页面。
Native/MRN/H5选型标准目前,美团外卖App存在三种技术栈:Native、MRN、H5,面对业务持续增长和安装包不断变大的压力,选择合适的技术栈显得尤为重要。H5在性能和用户体验方面相比Native和基于Native渲染的RN相对弱一些,所以目前大部分H5页面只是用来承载需求变更频繁、需要即时上线的活动页面。那么MRN和Native的界限是什么呢?当有一个新的页面产生时,我们应该如何做取舍?通过实践,我们逐渐摸索了一套选型规则,如下:
Native选型规则,强交互(同时存在2种及以上手势 *** 作),无法用二元函数描述的复杂动效,对用户体验要求极致的页面,类似首页、点菜页、提单页等。
对于强交互或强动画,MRN技术栈支持效果不理想,不建议使用。其他情况下,建议使用MRN。
H5适用于需要外链展示的轻展示页面,比如向外投放活动的运营页面等等。
具体选型细节可参考下表:
发布运维支撑发布运维是一个成熟的软件项目中非常核心的部分,它保证了整个项目能够高效且稳定地运转。建立一个稳定可靠的发布运维体系是我们建设整个外卖MRN技术体系的重要目标。但发布运维的建设上下游牵扯了众多基建:拥有一个合理的工程结构对发布运维来说至关重要。如果工程结构臃肿且混乱,将会引起的一系列的权限问题、管理维护问题,这样会严重制约整个发布运维体系的效率。所以MRN的工程架构演进优化也是发布运维体系建设的重要组成部分。
MRN分库 & 工程结构演进业务分库
任何一个大型、长期的前端技术项目,良好的工程结构都是研发发布支撑中非常核心的部分。从2018年10月份,外卖正式启动MRN项目以来,面临涉及近百个MRN和几十人参与的大规模MRN应用计划。从项目初期,我们就开始寻找一个非常适合开发维护的工程结构。
在最开始的时候,我们的目标是快速验证及落地,使用了一个Git库与一个Talos项目(美团自研发布系统)去承接所有页面的开发及发布工作,同时对权限进行了收缩,保证初期阶段的安全发布。然而随着页面的增多,每个版本的发布压力逐渐增大。发布SOP上的三大关键节点权限:Git库 *** 作权限、Talos的发布权限、美团自研的线上降级系统Horn权限,互不相关,负责人也各异,导致发布时常因各个节点的权限审批问题,严重阻塞效率。
随着项目的大规模铺开,我们的页面数量、合并上线次数与初期已不可同日而语。为了解决逐渐臃肿的代码仓库问题及发布效率问题,我们将庞大而臃肿的RN库根据业务维度和维护团队拆分成了4个业务库,分别是订单业务、流量业务、商家业务、营销业务,并确认各库的主R,建立对应的Talos项目,而主R也是对应Talos项目的负责人。同时所有的主R都有MRN灰度脚本的管控权限。这样一来,MRN的工程结构和Native的工程结构完全对齐,每个责任人都非常明确自己的职责,不会来回地穿插在不同的业务之间,同时业务库任意页面的发布权限都进行了集中,RD只需要了解业务的负责人,即可找到对应的主R完成这个业务的所有相关工作。
工程结构
在项目初期,对于每个库的工程结构,美团内部比较流行的工程结构有两种:一个是适合小型业务开发的单工程多Bundle方案,另一个是相对更适合中大型业务开发的多工程多Bundle方案。
单工程单Bundle方案
顾名思义,单工程单Bundle方案的意思就是一个前端工程承载所有的业务代码,最终的产物也只有一个RN Bundle。通过入参决定具体加载哪个页面。
对于业务不多,参与人不多的团队,使用单工程单Bundle的方式即可快速完成开发、发布。因为通过一次发布就可以完成整个发布的工作,但是带来的弊端也是不可接受的:因为所有业务都耦合在一起,每次更新都会“牵一发而动全身”,增大了问题的隐患。如果多个业务需求同时提测的时候,在团队配合上也是一个极大的挑战,因为新版本号会覆盖旧版本号,导致两个需求提测时会出现相互覆盖的情况。所以我们在立项之初就排除了这种方案。
多工程多Bundle方案
多工程多Bundle方案的意思就是一个Git库中存放了多个页面文件夹,各个文件夹是完全独立的关系,各自是一个完整的前端工程。拥有自己独立的MRN配置信息、package.json、组件、Lint配置等(如下图所示)。每个页面文件夹都输出一个独立的RN Bundle。
相比于单工程单Bundle方案,多工程多Bundle方案将页面进行解耦,使之基本可以满足中大型MRN项目的需求。在外卖MRN项目初期,一直都使用着这样的工程结构进行开发。但是我们也为之付出了相应的代价,即每个页面的依赖都需要对应RD去维护升级,依赖碎片化的问题日趋严重。同时在工程级别的管控,如统一Lint规则、Git Hook等也变得更加复杂。
多工程多Bundle方案 => 单工程多Bundle方案
随着外卖MRN页面规模以及参与人规模的进一步增大,多工程多Bundle方案的缺点日益凸显。特别对于那些前端技术底子相对薄弱的团队来说,依赖管理问题会变得很头疼。在这种情况下,单工程多Bundle的方案就应运而生了。
核心思路也很简单:观察一下单工程单Bundle方案和多工程多Bundle方案的优缺点可知,单工程单Bundle依赖管理方便的优点主要来自于“单工程”,而多工程多Bundle的业务解耦的优点主要来自于“多Bundle”。所以结合这两种工程方案的核心优点,就可以设计一种新方案:单工程多Bundle。即用一个工程去承接所有的页面代码,但是又可以让每个页面输出独立的RN Bundle来保证互不影响。其实,这种方式类似于Native一个静态库的管理,如下图所示:
通过分析MRN的打包原理可知,MRN通过一个配置文件配置了一个Bundle的所有业务信息以及mrn-pack2的打包入口。所以我们只需要让配置文件支持多份Bundle信息的配置,通过打包命令与参数选择正确的mrn-pack2打包入口,即可打出我们最终所需要的业务Bundle。如下图所示:
核心优势:
整个工程采用一个package.json,管理业务库中所有的依赖。这样可以有效地解决各自页面去管理自己依赖时,必然产生的依赖版本碎片化问题,避免同一依赖库因为版本不一样,而导致页面表现不一样的问题。
从依赖角度去规范各自页面的使用工具规范,如A页面使用某一种三方库来实现某种功能,B页面使用另一种三方库也实现了同一种功能,单一依赖管理就可以从库依赖的角度强制做技术选型,减少各个页面的实现差异,从而降低维护成本。
让业务同学可以更加专心地开发业务代码,不用关心复杂的依赖问题,大大提升了开发效率。
实现了工程级别的管控,如Pre-Commit,脚手架方案管理将变得更加便捷。
这种工程组织形式也成为了MRN工程结构的最佳实践,而且美团内部也有多个团队采用了这种解决方案。目前已支撑超过几百个页面的开发和维护工作。
外卖发布运维体系下图展示了我们的发布运维全景,共覆盖了开发交付、线上发布、线上监控、有效应对、复盘改进等五大模块。接下来我们会逐一进行介绍。
(1)开发交付
开发阶段,需求RD完成开发,提交到Git库的发布分支。对应的业务库主R角色(通常由RN经验较丰富的工程师来承担)进行CodeReview,确认无误之后会执行代码的合并 *** 作。顺便说一下,这也是外卖RN质量保障长征路的第一步。
(2)线上发布
合入发布分支之后,就可以正式启动一次RN Bundle发布。这里我们借助了美团内部的Talos完成整个发布过程,Talos的发布模板与插件流水线规范了一次发布需要的所有 *** 作,核心步骤包括发布准备(Git拉代码、环境参数确认、本次发布说明填写)、发布自检(依赖问题检查、Lint、单元测试)、正式打包(Build、版本号自更新)、产物上传测试环境(测试/线上环境隔离、测试环境进行测试),双重确认(QA、Leader确认发布)、产物上传线上环境等等。
产物上传线上环境,实际上是上传到了美团内部的CD平台–Eva。在Eva上,我们可以借助RN Bundle的发布配置去约束发布App的版本号、SDK版本等,以及具体的发布比例及地区,去满足我们不同的发布需求。最终执行发布 *** 作,将RN Bundle上传到CDN服务器,供用户下载,完成整个发布流程。
(3)运维监控
发布之后,运维是重中之重。首先我们的运维难点在于我们的业务横跨两个平台——美团App与外卖App。由于它们在基建、扩展、网络部分都存在差异,所以我们选取指标的维度不仅要从业务出发,还要增加全局的维度,来确保外卖平台MRN的正常运转。基于这个层面的思考,我们选取了一系列RN核心指标(在下面的章节会详细列举),进行了全方位的监控。目前外卖客户端,已经做到分钟级监控、小时级监控和日级别监控等三档监控。
在监控手段上,首先我们使用了美团开源的Cat告警平台(这部分已经通过Talos插件完全自动化配置),确保当核心指标在线上出现波动、异常的时候,相关RD、QA以及业务负责人可以及时接受到报警,并由对应的RD主R负责,快速进入到“有效应对”的环节。同时为了能够分阶段、更好地处理问题,我们将核心指标报警分为【P1】与【P0】两个级别,分别代表“提高警觉,确认问题”与“大事不好,马上处理”。保障了一个问题出现之后能够及时被发现并快速进行处理。
除了监控报警手段之外,我们还会借鉴客户端高可用性保障的经验。用一些日常运维的手段去发现问题。比如使用灰度小助手、数据日报等手段从宏观角度主动去发现存在隐患的指标,及时治理,避免问题。
(4)有效应对
根据“墨菲定律”:如果事情有变坏的可能,不管这种可能性有多小,它总会发生。即便我们在发布管控和线上监控上做的再充分,线上问题最终还是无法避免的。所以当通过线上告、客诉等手段发现线上问题之后,我们需要及时的应对问题、解决问题,把问题带来的影响降低到最小,并以最快的速度恢复对用户的服务。
在有效应对的方面,我们主要靠两种手段。第一种是存在B方案兜底的情况,使用Horn灰度配置,关掉MRN开关,短时间内恢复成Native页面或者H5页面继续为用户提供服务,同时通知相关RD和QA快速定位问题,及时修复,验证并上线。第二种是无兜底方案的情况,CDN服务器(Eva)上撤掉问题Bundle,实现版本回滚,接下来的问题定位过程跟手段保持一致。
这两种备案保障了外卖MRN业务的整体高可用性。
(5)复盘改进
在以上四个大环节中,问题可能会出现在任意一个环节。除了及时发现问题与解决问题,我们还需要尽力避免问题。这一点主要是靠我们内部的例会、复盘会,对典型问题进行Review,将问题进行归类,包括复盘流程规范问题、 *** 作失误问题、框架Bug等,并力图通过规范流程、系统优化来尽力地避免问题。
在外卖MRN项目实施过程中,我们共推动了二十多项规范流程、系统优化等措施,大大保障了整体服务的稳定性。
最后,我们用一张图对外卖监控运维体系做一个总结,帮助大家有一个全局的认知。
混合式架构流程针对混合式架构的流程,目前外卖技术团队采用的是正常双周版本迭代流程+周迭代上线流程。MRN页面既可以跟版迭代,也可以不跟版迭代,这样可以有效地减少流程的复杂度和降低QA的测试成本,而周迭代流程可以有效地利用MRN动态发版的灵活性。混合式开发和原生开发应尽量保持时间节点和已有流程的一致。这种设计的好处在于,一方面随着动态化的比例越来越高,版本迭代将可以无限拉长,另一方面从双周迭代逐渐演变成周迭代的切换成本也得到大幅的降低。详细可分为下面几个阶段:
评审阶段
业务评审阶段在原有的流程上,增加了技术选型阶段。在技术选型时,明确是否会存在需要使用MRN页面的情况,如果页面可以完全不涉及到Native部分即可完成,就可以进入周迭代的发版流程。如果需求用MRN实现,但是又涉及到Native部分,仍然走周迭代的上线流程。除正常开发需求的时间外,RD需综合考虑到双端上的适配成本。
开发阶段
客户端以周维度进行开发,每周确定下周可提测的内容,根据提测内容是否为动态化的业务、下周是否在版本迭代周期内,决定跟版发布或周发布。
提测阶段
提测前,为了保证MRN页面的提测质量,RD首先需要按照QA提供的测试用例提前发现适配问题。提测时需要在提测邮件中注明:(1)提测的Bundle名称和对应的版本号 ;(2)标明哪些组件涉及Native模块 ;(3)依赖变更情况,如是否升级了基础库,升级后的影响范围;(4) 重点测试点的建议。
上线阶段
MRN由于其可动态发布的特性可以跟版发布,也可不跟版发布,但上线时间和灰度时间节点都保持了一致。不过版本还是动态发版,都默认周二上线,周四全量。
跟版发布:默认只对当前版本生效,需在双周迭代三轮提测节点,周二当天将Bundle上线服务器,MRN的灰度开关全量打开。通过周四App的发版灰度比例来控制MRN的灰度比例,上线时需配置报警和灰度助手监控,实时掌握MRN的线上数据。
不跟版发布:也同样以周四作为全量发布窗口,Bundle需在周二时上线指定线上版本,指定QA白名单。测试通过后,在周三按照比例逐步灰度,周四正式全量,和跟版发布一样,上线时需要配置报警和监控。
架构总结最后我还整理了很多Android中高级的PDF技术文档。以及一些大厂面试真题解析文档。需要的朋友都可以点击GitHub直接获取方式
Android高级架构师之路很漫长,一起共勉吧!
PDF技术文档。以及一些大厂面试真题解析文档。需要的朋友都可以点击GitHub直接获取方式**
[外链图片转存中…(img-4Y0DbekD-1643792375477)]
Android高级架构师之路很漫长,一起共勉吧!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)