本文整理于蚂蚁金服无线工程师刺胃在 2019 安卓巴士开发者大会现场的分享《蚂蚁金服 mPaaS 模块化开发与架构重构深度解析》,通过“模块化开发架构设计”作为切入口,聚焦 mPaaS 如何深度应用与实践模块化开发架构,以及在架构重构中遇到了哪些挑战和具体解决思路。
内容概要
主要分为以下三个部分:
- 支付宝在移动端的架构演进与思考
- mPaaS 模块化架构及能力
- 基于 mPaaS 架构的重构思考
支付宝在移动端的架构演进与思考
支付宝现状
根据 2019 年移动互联网最新的数据报告,目前支付宝全球总用户数已超过 10 亿人,月活用户数超过 6.5 亿,成为国内第二大 App。
在研发上面,支付宝的客户端研发人员超过 300+,整体工程数同样也是超过 300+,总体代码超过 200 万行,提供的服务超过 200+,并且整体的闪退率维持万分之五以下,那么支付宝是如何保证在如此庞大的研发规模下,保证服务的告诉迭代,以及应用的整体稳定性的呢?
三个阶段
支付宝做到今天,主要分为三个阶段:
1. 独木舟阶段
支付宝刚开始推出的时候,和很多简单的应用一样,都是一个单体应用,除了一些简单的公共组件被作为 lib 模块,其他大部分业务代码全部写到一起。这种单工程的轻量结构,对于当时的支付宝来说,还算是可以满足需求,但是随着支付宝业务的迅速成长,问题开始暴露出来了,由于单工程,所有工程师代码都要合到一起,并行开发变得异常艰难,同时,由于发布时间固定,各团队匆忙合并代码,很可能出现代码覆盖、污染的情况,从而导致稳定性无法保证。这种开发模式,我们称之为「串行开发模式」。
2. 战列舰阶段
为了解决独木舟阶段我们存在的问题,在 13 年底,支付宝进行了一次彻底的重构,基于 OSGi 模块化思想,推出了 Quinox 容器化框架。基于这套框架,支付宝完成了从单体应用到平台型应用的转变,从单工程「串行开发模式」变为了多工程「并行开发模式」。各工程之间只关注接口,不用在意实现细节,页面间路由只需一个 id。代码完全隔离,开发、发版效率有了明显提升。因为基于框架提供的 pipeline 机制,业务治理变得非常方便,使得整体应用的启动性能有了明显的提升。
3. 航空母舰阶段
时间来到了 15 年,在解决了协作效率、启动性能等问题后,随着移动支付的普及,业务的井喷,用户对应用体验要求的提高,弹性动态、高可用这两个变为了这个阶段的重点。为了解决这些问题,支付宝引入了 Nebula 容器、小程序、多维发布以及全链路的监控等组件,来保障转型成为超级 App。
架构升级技术挑战及解决方向
通过刚才我们简要的回溯支付宝近些年的架构升级历程,我们可以总结出,重构升级成超级 App,需要解决的几大块技术点:
- 协同开发,业务解耦
- 启动性能调优,业务治理
- 复杂业务动态化,多维发布
- 保证高可用,数据全链路采集,多维度修复
mPaaS 模块化架构及能力
带着上面提出的四个技术问题,我们来先了解下 mPaaS 的整体架构图
- 整个客户端架构总共分成四层:框架层、组件层、服务层、业务层。框架层:最关键的部分,整个模块化的基础。提供微应用、微服务、pipeline、切面、监控等服务。整体模块化协同开发,都是基于框架层提供的能力,来达到「并行开发」的目的。
- 组件层:这一层提供的是客户端通用能力,如安全、网络、多媒体、存储这些,这些组件都是支付宝多年沉淀下来的经典组件,它们提供稳定的接口给上层使用者,作为客户端的基石,它们至关重要。
- 服务层:本层就是和支付宝相关的一些核心服务能力,我们将他们抽取出来,进行服务化,服务 App 本身,也服务各个生态业务。
- 业务层:业务方和第三方服务提供者,只需专注于业务逻辑与界面的实现,调用整体框架提供的各种能力,最后通过整体应用的动态化能力进行多维发布。
通过 Quinox 框架、微服务、微应用,即可实现上面的架构分层,接下来我们将逐一介绍。
Quinox 框架
Quinox 客户端框架是类 OSGi( like-as)框架的实现。Quinox 一词来源于著名的 OSGi 框架的实现 Equinox。
- 基于 mPaaS 的 App 研发,就像积木搭建(Bundle)一样轻松,天生具有以下优势:灵活性:模块/组件可插拔,不影响编译
- 独立性:模块可由团队或个人独立维护
- 复用性:模块可被任意宿主程序所引用
- 隔离性:接口和实现分离,微应用路由跳转
微服务
mPaaS 框架提供微服务功能,该服务类似于 Android 原生的 Service,直接通过框架的方法,即可获得服务的实现。这种设计模式本身核心是控制反转,依赖注入的这种理念,减少各模块间的依赖,初始化等复杂的工作,完成解耦。
作为使用者方,无需了解实现细节,只需要提供参数,调用服务提供的接口即可获得服务。
作为开发者,只需要将服务接口注册到框架上,框架在初始化后,会自动去生成服务,控制服务的生命周期。
微应用
mPaaS 框架提供微应用功能,微应用我们可以理解为 mPaaS 的路由。
作为使用方,通过唯一的 appId,进行不同微应用之间的调用,使用者并不需要引用对方的 activity,也无需关注对方内部的跳转逻辑。
作为开发者,只需要将 appId 注册到框架上,当有业务调到该 ID 后,后续的操作完全有开发者掌握,业务之间完全隔离解耦。
微应用的概念不仅适用于原生页面,同样也适用于H5和小程序。注册为H5或者小程序类型的应用 ID,框架会自动将启动过程delegate给H5或者小程序容器,而使用者完全不必关心应用 ID 对应的应用类型。
综上所述,微应用和微服务可以使各个业务之间的耦合降到最低,大家都无需关注其他团队的实现,代码之间无侵染,这样整体的协作研发效率也就随之提升上来了。
Pipeline 机制及启动优化
上面的内容主要是讲如何高效的进行协同开发,接下来该第二个技术点,也就是 mPaaS 是如何对框架的性能进行治理的。对于性能优化,mPaaS 框架主要从业务和技术两个方面进行处理:
技术优化:
- mPaaS 通过黑科技,将启动时的 JIT 关闭,从而有效降低因即时编译导致的性能问题
- 通过关闭启动时的 GC,从而将启动速度提升到最快,当启动完成后,在进行一次较大的 GC。
- 提供各种切面及监控能力,全方面监控启动异常
业务优化:
- mPaaS 框架提供统一的启动流程、线程池、并发工具类等,可以有效的使业务规范化
- 并且,mPaaS 提供 pipeline 机制,可以根据业务优先级进行初始化调优,从而达到启动优化的目的。
动态化
解决了上面两个技术点,mPaaS 框架就已经具备成为战列舰的能力了,接下来,我们看下如何更近一步,提供航空母舰的能力。
作为超级 App 的核心能力,就是如何构建生态。”快速起飞、降落,承载大量、不同的舰载机“是其要解决的核心问题。解决这个问题的关键就是框架的 Hybrid 能力,mPaaS 上面,采用了支付宝多年积累下来的 Hybrid 经验,使用 Nebula 作为 H5 容器,同时承载 H5 离线包以及小程序。H5 容器及离线包的特点:
- 全面兼容主流 H5 框架,迁移成本低
- 使用离线包技术,体验接近原生,网络请求走原生,高效安全。
- 提供统一 UC 内核,性能及稳定性有保障
- 离线包差量更新,节省流量
- 提供容错机制,下载失败后走线上 fallback
- 实时触达客户,通过推拉结合,下发离线包
H5 离线包作为动态化方案,有点多多,但是,其有一点不足就是无法管控质量,宽泛的前端规范让服务管控变得异常困难,如果所有服务都是我们内部的业务还好说,如果开放给第三方,就需要有完整的规范来约束。这时,我们就要引入小程序来规范化服务,提供给第三方。小程序特点:
- 统一的小程序架构,可在任意基于 mPaaS 架构开发的应用上进行投放
- 强大的 Web 渲染引擎
- 提供丰富组件,快速实现业务
- 整合离线包技术,可以复用 H5 插件
- 完善的生命周期管理
当我们解决完动态化的技术点后,应用将会有以下四点优化:
- 包尺寸有效减少,节省流量和存储。
- 服务不再受发版所限制,快速发布,快速迭代。
- 业务开发效率更加优秀,一次开发,多端运行。
- 应用升级为平台,提供优质服务并按需加载。
多维发布
作为一套完整的动态化方案,光有容器其实是不够的,我们还需要有多维触达用户的手段,将各种服务发布给用户,接下来,我们就聊聊 mPaaS 多维发布都具备哪些能力。
通过 mPaaS 发布平台,我们可以轻松地将我们的 App 新版本、H5 离线包、小程序包、热修复包以及开关配置进行下发。
同时发布平台提供了正式发布和灰度发布,通过灰度发布,我们可以有效的验证待发布的内容,检查是否有潜在的风险,若灰度发布时出了问题,可进行及时回滚,减少覆盖面,有效的降低了正式发布的风险。
另外发布平台还提供不同的纬度,包括白名单、机型、城市、系统版本等,这些纬度可以使发布可以更具有针对性。
运维体系
上面解决了协同开发、性能优化、动态化等技术点,最后一个技术点就是如何保障高可用,确保应用的稳定性。
mPaaS 提供一套完整的运维体系来保证线上 App 的稳定。
1. 开发测试
通过接口实现分离,各模块充分进行单元测试,集成之后进行联调测试,联调测试之后,交给 mPaaS 云测平台,进行稳定性测试以及功能测试。充分的测试,可以将 80% 问题发现出来,并在发版前及时修复。
2. 灰度发布
结合上面提供的灰度能力,进行灰度发布。对于客户端来说,有些问题,模拟测试环境是很难测出来的,那么这个时候,真实的线上灰度环境就是预防风险的重要手段之一了。通过灰度发布,逐步放量,不断扩大灰度范围,直到闪退率、卡死率等指标符合发布标准后,再进行全量的发布。
3. 实时监控
全方面监控各种纬度的 App 数据,如闪退、卡死、卡顿、电量、流量等。指定一定的异常规则,有问题及时进行报警。这些诊断数据是会周期性的进行上报,不过当有些特定机型或者特定用户出现无法复现的问题时,我们还可以通过捞日志的方式,将指定设备的开发日志上报给服务端,进行分析排查。
4. 动态修复
最后,当问题发现并解决后,可以通过上面提到的发布平台,将修复后的配置、离线包、小程序、热修复 patch 包等,下发到对应设备上,进行容灾修复。
基于 mPaaS 架构的重构思考
上面介绍完了 mPaaS 的能力,接下来我们聊下基于 mPaaS 的重构思考,本章会从五个维度来考虑重构。
架构重构
当我们决定架构重构后,一般会有两种选择进行重构,一种是全部推倒重来,还有一种是融合迁移。
这两种方案,我们可以比喻为一架比较老的飞机,已经不足以满足现在的飞行任务,第一种方案就是将飞机飞回机场,重新拆掉,结合新的设计架构从新组装。第二种方案是在执行飞行任务的过程中,我们逐步去替换发动机、替换不满足架构的地方,直至飞机满足最新的任务需求。
无论我们采取哪种方式进行重构,首要的工作就是梳理现有业务,将整体结构进行模块化拆分,同时对我们整体的架构进行合理分层。基于第一种方案,我们首先需要基于 mPaaS 架构搭建一个全新的框架,同时,由于我们是推倒重建,所以我们需要尽量减少在此阶段提的新需求。等当整体架构完成后,再增加新需求。框架搭好后,我们需要将各项业务也进行重构,并逐个插到 mPaaS 容器化框架上来。最后当所有业务全部重构完成后,我们再进行全量的回归测试。
这种方式的优势和劣势都很明显,优势就是完全基于新的架构来实现,抛弃原有的包袱以及不合理的地方,但是劣势就是,完全重构所需要的工作量是巨大的,同时有些企业可能无法接受如此长的时间不能或只能少量的更新需求。
基于第二种方案,第一件事情就是将 mPaaS 架构接入进我们原有的工程中,然后再对原有框架进行融合适配:比如开发一个兼容新老框架跳转的路由,兼容新老 H5 容器的原生插件等等。兼容工作完成后,我们就要对原有业务进行改造升级,我们可以将业务逐渐的拆分出来,跑在新的框架上。每完成一点,我们都可以进行一次迭代发布,测试的压力也会比较小。
这种方式的好处就是整个重构过程是一个持续性的过程,每一步都可以有产物输出,小步快跑,持续迭代。但是劣势就是,可能最终的版本,会有融合的痕迹存在,一些历史包袱也可能无法很好地甩掉。
当然,这两种重构方式没有谁好谁坏,根据业务自身的需求来选择自己合适的方式才是最好的。
能力重构
上面我们介绍了架构重构以及相应的方式,接下来我们来聊聊能力重构。
所谓能力重构,就是我们希望通过整合整个架构,在基础层面,将通用的组件下沉,避免重复创造轮子,同时标准化服务接口,为更多的上层业务提供优质、稳定且标准的服务。
那么我们就需要从两个方面来处理这个事情。
基础组件
我们在开发过程中可能会存在这样一个问题,就是两个团队协作开发,可能大家有自己的一套存储逻辑、网络请求、工具库或是其他冗余重复的代码,这时候我们就需要将重复的部分,进行合并,沉淀,通过公共 bundle 的形式,对其他团队提供能力。
当然,mPaaS 框架自带了非常优秀的网络、安全、存储、多媒体等 App 开发过程中都需要使用的组件,供开发者直接调用。
核心能力服务化
组件沉淀后,对于一些核心的业务能力,我们需要将这部分能力进行服务化,抽象出标准的服务接口,供其他团队或是第三方生态调用。比如说支付宝的支付服务、芝麻信用服务等,都是依托于服务化,最终良好的为其他业务提供服务的。
业务重构
在我们完成框架重构和能力重构之后,整体的骨架和能力就已经具备了,剩下的就是基于这套框架,将我们的业务界面进行重构,在这里,我们建议大家参考以下原则:核心业务微应用化
针对一些非常核心的业务逻辑,比如支付报的支付,以及一些对性能要求比较高的业务,比如首页,亦或是一些特殊交互的页面。通常我们是希望通过使用原生页面,并将页面打成微应用的形式进行重构优化。因为这些页面,通常不会有大改,所以对动态化能力要求不是很严格,同时原生又能满足这些页面多种多样定制化的需求。
复杂业务 H5 化
对一些复杂的二级业务,可能业务本身会频繁的进行迭代,那么对于原生 native 将会是灾难般的开发体验,这时候,我们需将这部分业务剥离出来,通过前端技术将业务打成 H5 离线包,再通过发布服务将离线包发布到应用上。这样,就满足了我们业务复杂多变的场景。
三方生态小程序化
我们不仅自身提供各种各样的服务,也需要引入第三方服务来服务更多的人群,传统的 H5 页面由于过于宽泛的前端标准,加上有一定的技术门槛,这里就不如规范、简单的小程序了。所以,一般第三方的服务,我们希望将其小程序化。
发布重构
当一切开发工作都 OK 之后,我们是否能够说,本次的重构就完成了呢?答案是否定的。重构,不仅仅是针对代码层面的重构,基于新的架构之后,整体的发布、运维理念也需要进行重构。
如上图所示,我们重新定义了研发模式与发布流程,Native 应用、H5 业务、小程序,都可以有自己的发布流程,无需阻塞等待其他团队。各业务团队进行完全拆分,每个业务独立演进,独立发布。在发布过程中,要遵守以下流程:
- 指标线性,定义每次发布的业务和性能指标
- 智能灰度,内部灰度、外部灰度、指定灰度
- 实时监控,修复循环
- 线上运维修复手段技术兜底
运维重构
在上面我们也讲到了运维理念的重构,在这里,我们要介绍下 mPaaS 架构是如何保障线上应用的质量的呢?
我们引入了多维度运维的概念,如图所示
最上面一层是开关。通过开关,将一些我们新开发的,或者是将稳定性不太确定的代码包起来。这样,如果真的线上发生故障,我们可以及时通过服务器推送开关,将故障代码关闭,这种方式是推拉结合的,即时到达率 100%。
第二层纬度就是通过 H5 离线包。如果某些故障是发生在离线包内,那么我们可以定位到问题,直接再发送新的版本即可,这种方式也是推拉结合,但由于离线包需要下发,所以不如开关那么即时,不过在 1 分钟之内也能覆盖 99% 以上的用户
第三个纬度就是小程序。如果故障发生在小程序上,那么同离线包,我们只需要重新修改小程序,重新发布,不过这里可能会涉及到审核问题,效率比离线包要略慢一点。
在下一个纬度第四个纬度是我们的热修复。不到万不得已一般不会进行热修复,这是一个原生 Native 兜底的手段,通过热修复补丁包的下发,我们来弥补我们的缺陷,一般成功率会在 95% 以上。最后如果以上手段都无法修复,那么我们会启动紧急发版流程,发布新的版本来覆盖故障。
重构案例
12306
2017 年底通过 mPaaS 进行了系统的重构,使用了 mPaaS 框架以及多项组件及服务,解决了 12306 移动端开发多年的痛点。比如 12306 的弹性动态化,之前会有在启动页面强制更新下载的情况,用户体验不太好,通过 mPaaS 优化后,进行了无感知更新,用户体验提升了一个台阶;还有就是 12306 使用了 mPaaS 的网关,其服务安全性得到了质的提升,也使得正常用户的整体购买流程得到了好的体验优化。
作为开发角度,客户表示当年是移动端开发、运营最轻松的一年。作为使用者角度,多数用户也表示使用体验改善了很多。
广发银行
广发银行之前采用其他移动端研发平台,性能一直是瓶颈,尤其启动时间,在部分低端机型上体验不太友好,使用 mPaaS 重构后,平均启动性能有了质的提升。
广发银行是“发现精彩”与“手机银行”两款 App 先后完成上线,两个 App 均使用 mPaaS 框架进行重构。其内部有多个模块的功能是重叠的,通过 mPaaS 模块化架构拆除可复用的微服务、微应用以及离线包,使得开发后的手机银行客户端在研发工时上节省了大龄的研发工时。
针对移动端架构设计和重构实践,相信大家也有自己相应的思考,以及实际开发过程中遇到的相关问题和痛点,欢迎大家添加钉钉群“23124039”和我们互动交流。