作者介绍:古塘,目前主要负责支付宝框架和各个组件通过移动开发平台 mPaaS 对外输出工作,今天给大家分享的主题是敏捷开发与动态更新在支付宝 App 内的深度实践。
活动推荐:CodeDay#1 线下沙龙杭州站已上线,具体活动信息及报名地址见文章尾部。
支付宝App架构演进
首先来快速看一下支付宝的架构演进,支付宝在移动端躬耕多年,从简单的工具型App到平台型、到现在的超级App。与目前市面上大部分App的发展路线类似,目前我们构建平台的同时,做了更多服务化、模块化的工作。
针对支付宝在超级 App 方面方向下的架构优势,我们总结了如下特点:
多应用的生态:不限于形式,原生模块、离线包、小程序。
开放:底层同一个架构,业务很方便的迁移。
动态化:业务可以随时在线更新,无需发版,随时响应线上活动,比如双十一、双十二,春节扫福等活动
高可用、高性能、高灵敏度:完善的监控运维体系、发现问题后多层次的修复技术、客户端良好的性能启动体验,强大的网络性能,防刷抗流量等。
工程化挑战
从工程化的角度来看,业务和团队的快速发展也会带来巨大的挑战。支付宝的业务量在 15、16 年后有一个指数级的增长,包括团队人数、模块数量,大家看现在的支付宝也不仅仅是一个简单的支付工具了,而是包含了各种各样的业务,服务我们的生活的方方面面。
所以我们需要一个灵活开放的架构来支撑多团队的快速协同开发,需要建立超级 App 的运维体系。
业务复杂性带来的技术挑战
下面我们快速看一下业务复杂性会带来怎样的技术挑战,总体来说,分为 4 个方面。
1、基础能力要求更高:
比如支付宝的核心场景扫码支付,有更好的识别率和识别速度,push 就是大家听到的萌妹子语音:“支付宝到账多少多少元”,这就涉及到要求我们的框架怎么做保活,怎么提高推送到达率。
移动安全方面,作为金融级的 App,要做到防范黑产,各种羊毛党。
应急和快速修复方面,这是我们已经提到过的,框架需要快速响应线上问题,并提供相应的修复方案,能做到动态更新,最大程度的保证线上的稳定性。
2&3、性能和环境方面:
随着业务体量的不断增大,如果业务同学无脑的把初始化放到启动过程中,必然会造成启动时间的不断增加,在使用过程中,也很容易会产生电量、流量、内存、存储等各种问题,造成线上舆情,网络环境也是一样,因为现在还在一些偏远地区可能网络不太好,弱网优化也是需要的,同时我们也需要对千元机、低端机器保持友好,保证低端机的用户体验,于是乎,我们急需良好的框架运维机制来支撑业务的快速发展和敏捷发布。
4、多 App 生态:
这也正是我们基于 mPaaS 做的对外输出。支付宝这套框架不止是支付宝自己用,也需要快速赋能我们的合作伙伴,大家都是统一的架构底层,支持业务之间的灵活联动和快速扩张,这也是前面提到的超级 App 的技术特点。
架构现状
接下来我们来具体看一下支付App的架构现状:
从下到上,分别是「容器层、组件层、框架层、服务层和应用层」
容器层:最底层的基础层,管理这每个模块 bundle 的加载和资源的处理,在 Android 上和现在流行的插件化框架类似。
组件层:是我们抽离出来的通用组件,提供一些通用能力,比如网络、缓存、日志、图像加载等等。
框架层:这层和原生的 Android,iOS 系统 SDK 类似,是我们定制的用来做每个模块 bundle 之间解耦、交互和通信的基础层,有 Native,H5 和图上没提到的小程序。
服务层:我们基于框架封装的一些业务服务层,提供登录、支付、LBS 等服务。
最上面的就是应用层了:即用户可见的具体业务,对于支付宝来说就是扫码、转账、余额宝等。
所以说支付宝的框架有着明显的分层结构,除了支付宝本身,蚂蚁系内部的 App 也都是依托于此,比如网商银行、蚂蚁财富、口碑等,大家的 App 是底下这 4 层可以做到几乎一样,唯一区别就是在应用层搭建不同的业务,而且因为是同样的架构底层,同一个业务很方便的做多端迁移,比如大家比较喜爱的余额宝业务在支付宝里有,在蚂蚁财富App 里也能看到,这套框架也依托于 mPaaS 平台对外输出,也欢迎大家体验。
多种框架支撑
正如刚才所说的,在支付宝内部会有多种框架支撑不同业务的并发开发和快速发布,大致可分为“Native 开发框架”、“Kylin H5 开发框架”以及“小程序开发框架”,具体的内容我们会在后续展开。
灵活的开发框架
我们认为在支付宝内部开发业务,就像搭积木一样轻松,具有很多特点:灵活性、扩展性等等。
总体来说,大家都是并行开发,互相不影响,谁的版本有问题,可以随时回滚到稳定版本:因此积木和积木之间可以做到很好的解耦,之间的交互就是通过前面讲到的定制的框架层来通信,同样你也很方便地增加一块新积木,自由扩展业务。
OSGI
OSGI 是 Java 做动态化模块化的一系列思想规范,支付宝的框架设计也是借鉴了这个思想。
总体来说,在支付宝内部的每个模块工程我们都称之为 bundle,在 Android 上的产物其实已经是一个完整的 APK 安装包了,只不过不能独立运行,需要依赖底层框架和其他模块,在 iOS 上的产物也是一个具体的二进制 Framework 包,这样打最终安装包的过程其实就是前面提到的把各个积木搭起来的过程,只是二进制级别的合并,比较耗时的编译的过程已经分散到各种积木的产生过程中了,这样做也能大大加快整个安装包的打包速度。
以支付宝为例,打完整的安装包包含几百个 bundle 的,在我这台 14 年版的 Mac 上耗时也在 1 分钟之内。
微应用与service
接下来我们来看看积木和积木之间,业务上是怎样做交互的。我们通过封装 MicroApplication 和 service 来实现。
MicroApplication:我们认为每一个独立的 bundle 其实就是一个小的 App,所以我们也赋予了和系统 SDK 类似的生命周期代理方法,类似于 iOS 的应用 delegate 和 Android 的 application,通过 AppId 标识,可以随意跳转到不同业务的 App,MicroApplication 相关的生命周期事件也会有相应的回调,不同的 bundle 之间完全不用知道你有什么 Activity 或者 viewController,只需要告诉我你的 AppId 标识,就可以跳转过去,就是说框架提供了全局的路由管理功能。
Service:这个不同于 Android 上原生的 service 组件,通过框架中接口包的概念思想,很方便的实现对外暴露功能接口,有点类似于单例类的感觉,区别是框架提供了完整的加载和调用管理,不用开发自己重复写单例类造轮子。
Nebula
和市面上流行的 phoneGap (cordova)类似,都是 H5 混合开发解决方案,特点如图所示:
除了提供基本的 H5 页面的加载管理、和 Native 做通信的 JSAPI 机制,还具备一些他们可能不具备的特点:
离线包机制,解决 H5 加载的性能问题。
统一的 UC 内核,解决 Android 上恶心的兼容性问题。
体验改善
首先,我们来看H5加载,传统意义上的H5,在进入的时候上面会有进度条或者转菊花,体验会不太好,我们的容器是怎么解决这个问题的呢?
离线包
离线包是将 HTML、JavaScript、CSS 等页面内的静态资源打包到一个压缩包内,Nebula 使用一套基于 AppId 维度的本地文件管理方式,对离线包进行管理。这和前面提到的框架「积木的概念」如出一辙,每一个离线包都是一个小积木,这个小积木可以很方便的做到热插拔,实现动态更新。
小程序
接下来让我们来看看小程序,看看标题还是很唬人的,面向未来的研发方式。
大家有没有想过这样一个问题,为什么 H5 技术已经发展的相对来说比较成熟了,我们还要推出小程序技术?
因为小程序可以完美解决现在 H5 存在的一些问题:安全、性能、开发效率等各个方面。
拿性能举例,虽然已经有了离线包技术可以大大提升 H5 的加载性能,但是始终渲染出来的还是 H5 页面,受限于 webView,而小程序就完全不一样了,最终渲染的页面,可以是 H5,也可以是 Native 页面,可以集成 RN、weex 类似的技术,实现原生渲染,而且小程序有自己的框架,可以实现报活、资源预加载等各种优化手段,这些都是 H5 很难办到的。
大家可以看现在支付宝里的蚂蚁森林,抢能量种树那个,大家应该都玩过吧,当前的版本就是小程序实现,可以体验一下页面的加载速度和滑动的效率等等,这已经是一个比较复杂的带动画的业务了,都可以做到很好的用户体验。
小程序 IDE
同时小程序还有自己的 IDE,帮助开发者能够实现「编码实时预览、自动补全、语法提示」等,从而大大提升了开发效率:
研发流程
因此,基于前面介绍的各种开发框架,这里可以分享一下支付宝的研发流程,分为「开发、测试、集成发布」这些过程:
开发:创建自己的小积木。
测试:验证,通过和不通过。
发布:会有发布经理这个角色,简单的理解就是最终搭积木的那个人,会审批每个积木到底能不能进最终的大架子,然后再进行各种灰度和发布流程。
高效交付:并行研发流程 + 动态更新。
从大版本集中发布到每个小产品迭代开发,每个小产品线维护自己的小版本,可以控制自己的研发和发布流程。
打包平台
内部也会有 CI/CD 打包平台的支撑,支撑着内部完成「多模块并行开发、业务功能动态部署、线上问题热修复」。
对于发布平台,我们是怎么做的呢?
不同的业务,可以创建不同的发布任务,可以发布到不同的版本。
发布产物:支持原生的升级包、热修复包、离线包、小程序。
发布类型:内部灰度、外部灰度、正式发布的维度展开灰度测试?
人群过滤:支持不同维度的人群过滤,按白名单、机型、rom 版本等。
这里还可以说一下的是,我们对于离线包这种发布产物是支持差分机制。举个例子,我们有一个业务原先是 200K,改个背景逻辑变 210K 了,没必要因为这 210K 去完整下发覆盖,通过差分得到补丁。当然,这里的补丁大小不是 210K-200K 这样简单,但至少我们可以通过补丁机制从而达到最大程度地减少数据冗余,提高整体覆盖率。
总结:技术架构升级驱动研发方式转变
总结来说,技术升级驱动研发方式产生转变,从 Native 为主的研发方式向动态化的研发方式进行转变:
技术选型:原先我们以 Native 为主,少量独立页面使用 H5;现在我们更推荐核心组件使用 Native(用户高频使用的场景),二级业务尽量使用 H5 或者小程序;
发布方式:目前基于“小步迭代”的选择,不依赖客户端发布点,从而达到随时发布的能力;
研发效率:目前使用 Web 技术能够达到更开放的效果,一套 Web 代码即可实现跨平台的能力;
安装包大小:相较于 Native,H5 能够有效地控制安装包的大小。
敏捷发布、保障稳定性
那么总结一下,支付宝是怎么敏捷发布,并保障稳定性的呢?
开发测试:通过接口解耦与业务解耦,开发者只需关心自己的业务做好业务迭代和测试,集成之后验证跑通即可。
灰度发布:提供多方位的灰度策略:白名单、时间窗、应用版本号、系统版本号、手机型号等。
监控:监控主要聚焦稳定性的问题,包括“闪退、卡顿、卡死、业务异常”等情况,当问题产生后我们会基于动态修复的手段进行快速修复。相关的埋点监控模块近期也在支付宝开放平台开放出来,欢迎体验。
动态修复:进行 Native 热修复和配置下发。具体内容见后续展开。
超级App运维体系
因此我们通过发布、监控、诊断协同作战,支持体系化运维,形成了所谓的超级 App 运维体系。
接下来我们针对「诊断」展开,前面我们提到的「监控」更多的是发现问题,而如何定位问题发生的原因,是需要通过诊断来进行核验的。
诊断定位
参考这张图,我们能够清晰地了解支付宝内部是如何进行问题诊断与定位:从“端到端的信息打通”到“全链路辅助到人”,“详细信息拉取”后在进行相应的“诊断分析”,同时会配备具体的诊断策略。
因此,我们可以实现一键诊断用户 App 日志,具体界面如下:
AndFix
发现问题后,怎么去修复问题,就要用到一些热修复的手段了,比如这里提到的 AndFix。
在 Android 上,AndFix 完全是支付宝同学自研的一套 Android 热修复技术,15 年的时候已经在 GitHub 上开源。现在 star 数大概有 6000 多个,相信应该有同学也接触了解过,不过开源的版本略老,但是原理不变。
AndFix 可以认为是开创了 Android 热修复 2 个流派之一的 Native 修复,原理是通过在 Native 端方法指针替换实现,修复的粒度是针对于方法,这样从原理上来说至少有 2 大好处:
1 是补丁包比较小,因为是方法粒度;
2 是可以做到实时生效,比较适合修复紧急 bug 这种热修复场景;
另一种比较流行的技术是通过类加载的机制,因为粒度是类级别,所以补丁包会相对来说大一点,且可能存在 dex 合并的性能损耗,而且因为 Android 虚拟机没有类卸载机制,所以无法做到实时生效,一定要重启。
当然,没有一种技术是万能的,我们内部也会存在着 dexPatch、instantRun 这种原理的修复技术,应对不同的场景。
在 iOS 上,从最早的 lua 脚本到大名鼎鼎的 JSPatch,我们内部都会有类似的方案,这个在 iOS 上其实最重要的我觉得不是技术问题,而是苹果爸爸的政策问题,这里就不多说了,你懂的。
多层次的修复技术
最后总结一下,一定要有多层次的修复技术,适应不同的业务场景。如图所示:
移动开发平台mPaaS:对外输出
最后,到了 One More Thing 的时候。前面我们分享所涉及的所有技术手段目前已通过 mPaaS 平台对外输出:
「移动分析、消息推送、热修复」三款组件近期在支付宝开放平台上已独立放出。如果你是移动开发者,且对 mPaaS 感兴趣,赶紧上手试用吧:http://t.cn/ExXJGkP