本文作者:周伟 夏银竹 李昂 武鹏
支付链路整体承载了云音乐业务的主要交易流量。随着营收业务的快速增长,链路整体的复杂性持续提升的同时,也带来稳定性与支付效率的压力。2023年,我们以专项的方式对支付链路的各个环节尝试了不同方式的优化方案,并取得了一些核心指标增长的优化结果。本文主要介绍云音乐会员团队在支付链路优化上所做的一些解决方案和思路。
业务背景
支付链路,从用户进入支付触点开始到订单支付完成、履约结束,整体承载了云音乐业务的主要交易流量,涵盖会员、数专、商城等多种业务场景以及支付宝、微信、抖音等各类支付渠道与支付方式。随着营收业务的快速增长,链路整体的复杂性持续提升的同时,也带来稳定性与支付效率的压力。
2023年,我们以专项的方式对支付链路的各个环节尝试了不同方式的优化方案,并取得了一些核心指标增长的优化结果。本文主要介绍云音乐会员团队在支付链路优化上所做的一些解决方案和思路。
优化总览
完整的支付链路包含引导用户购买的支付触点、不同形态和意图的收银台、承载营销和商品信息的订单服务、三方支付的渠道以及支付结束后的履约和挽留。支付链路是个巨大的流量漏斗,每个环节都有一定的用户流失,如收银台的到达率影响用户流入,下单链路复杂的流量流失以及各类原因的支付失败等。
我们建立了全链路的支付漏斗监控,并针对重要环节的流失问题进行了精细化的分析。期间也选取了一些关键指标和扩展因子,如支付成功率、错误占比、支付应用安装情况、手机厂商信息、阶段性支付数据等共同组成了支付大盘。
最终,我们选取了支付链路的一些环节,并针对流失问题采取了不同的策略和工具集,如下图所示:
收银台性能优化
收银台页面是用户购买的核心场景,页面的曝光量与订单的成交量呈显著正相关。因此有必要优化页面加载体验,减少页面加载耗时,增加页面曝光量,从而提升最终转化的订单量。
页面性能分析
目前云音乐的核心收银台均为 RN 页面,完整的 RN 应用加载流程中如下图所示,可以划分成三个阶段:白屏阶段、页面首帧(FCP)阶段、页面内容可见(LCP)阶段。
性能优化的目的是尽可能地减少 LCP 的加载耗时,让用户可以尽早地看到完整的页面。
因此,可以根据 RN 应用的加载特性,逐个阶段进行优化,从而缩小整体的加载耗时。下图展示了一些通用的优化手段。
优化结果
技术指标
- FCP到达率:+1.37pt
- LCP到达率:+3.66pt
- FMP加载耗时:-800ms
业务指标
- 购买UV:+8.54%
- SKU曝光率:+8.26%
- 转化率:+0.08%
数据来源于多种手段优化后的收银台A
通用优化手段
主进程加载 - Android
默认的RN页面运行于按需加载的 broswer 进程,进程的 fork、初始化以及加载会额外带来约数百毫秒的开销,其中低端机耗时更明显。由于收银台页面的崩溃率以及内存控制较好,跨进程的优势不明显,因此将收银台容器切换至主进程更合适业务场景。
RN 离线包
RN 离线包是指将 Bundle 提前存储在客户端本地,从而免去运行时下载 Bundle 文件的时间。目前常见的有两种方式:
- 预下载 RN Bundle:APP 启动时预下载 Bundle 并离线存储在本地
- APP 内置兜底包:直接将应用的 Bundle 打包进 APP 内,保证用户端肯定有一份 Bundle 在本地
虽然离线包的优化效果很好,但是同时也会带来一定的资源浪费和 APP 体积增加。目前会控制仅对 P0 的业务应用开启配置。
RN拆包
RN 拆包是将应用拆分成基础包和业务包两部分,这样做有两方面的好处:
- 运行时只需要下载 / 加载业务包部分的 Bundle,大大减少了获取 Bundle 文件和 Bundle 解析的耗时
- 客户端会提前预热好基础包的容器,RN 加载时可以使用预热的容器加载,减少 Bundle 解析部分的耗时。
Hermes + Bytecode
RN 升级 0.70 后使用了 Hermes 引擎,Hermes 引擎的一大优势是预编译与字节码执行能力,下面是使用新架构 + Hermes 引擎 + 预编译后的对比数据:
Android 小米8 SE 首帧提升 71.5%,LCP 提升 40.1%;
红米 Note 9 pro 首帧提升 77.3%,LCP 提升 41.9%;
iPhone 6 首帧耗时提升 63%,iPhone 12 提升 42%;
LCP iPhone 6 提升 48.5%,iPhone 12 提升 18.3%。
相关链接可看前文 《网易云音乐 RN 新架构升级实践》
动态导入
随着 RN 应用越来越复杂, RN Bundle 的体积也会越来越大。为了避免加载巨大的代码文件,可以将代码拆分成多个小文件。首屏的代码可以打包成一个文件立即加载执行,而非首屏的代码可以在与页面交互后懒加载,从而提升页面加载性能。
接口预加载
预先声明需要预加载的接口以及参数,在RN容器初始化的同时,前置且并行进行接口的请求,从而减少接口加载阶段时间。
优化收益 = Math.min( 容器初始化耗时 , 接口加载耗时 )
深度优化定制
由于安卓中低端机性能太差,即使 RN 应用做了上述的通用优化措施,也无法彻底实现在中低端机型上的秒开体验。
因此,为了持续地提升核心页面性能,我们也针对业务场景定制化一些非普适性的优化措施;
RN 预渲染
RN 预渲染是指在客户端启动 / 空闲时,提前预渲染好 RN 页面。等到用户真正打开 RN 页面时,无需加载直接可见,实现真正意义上的秒开。
但是这种优化手段略显激进,会增加 APP 的内存压力。所以需要制定相应的优化策略,在合适的时机、合适的人群以及合适的应用开启 RN 预渲染,尽可能提高预渲染的利用率;
合适的时机
- 应用首页加载完毕
- 应用主线程空闲时: Looper.getMainLooper().queue.addIdleHandler
合适的人群
- 接口请求校验是否满足人群包:高付费意愿度
合适的应用
- P0级应用 + 主动型业务场景:页面收银台,用户主动触发会员充值收银台,流量流失与整体加载时间正相关。
RN 静默加载
在某些场景下,用户满足一定的触发条件、策略后(如播放付费片段、会员临期等),会弹出浮层 / 弹窗收银台引导用户付费。这种类型的收银台称为被动型收银台,具备用户非主动点击、出现时机无感知、加载过程可取消、用户取消率高等特点。
针对被动性收银台,可以后台静默加载页面,加载完成后再展示给用户,从而减少用户体感加载时间,进而降低用户在页面加载过程中的取消率,最终提高页面访问量。
用户体感加载时间:用户等待页面加载流程时间
主动型收银台:用户体感加载时间 = 页面LCP时间 - 用户点击开始时间
被动型收银台:用户体感加载时间 = 页面LCP时间 - 白屏 / 加载感知时间
视图静默加载
静默加载期间视图不显示,用户可正常交互原有界面视图。待收银台视图完整加载结束,RN通知Native直接显示完整视图:用户所见即所得,从而减少加载流失,提高页面曝光量。
接口前置请求
区别于接口预加载,预加载依赖于用户网络,如果用户网络加载时间超过容器加载时间,那么整体加载速度仍然受到网络加载影响。
接口前置请求则在上一业务场景/策略触发时请求网络,接口请求结束后加载对应页面。比如收听某一首会员歌曲时,需要弹出浮层收银台前,先请求相关SKU数据,待数据完全返回后直接带入RN容器。
数专收银台H5->RN迁移
受限于历史原因,数专收银台具备原生容器和H5容器,但两类方案均具备一定的劣势:
- Native方案受限于发版更新问题,无法满足业务增长的需求,且迭代开发成本高;
- H5方案受限于技术栈的问题,即使启用离线包等H5优化手段,仍然无法持续深入优化性能和达到率,AB实验数据显示具备一定的关键指标数据下降;
RN迁移统一是更为兼顾业务和性能的方案,一方面开发迁移成本低,另一方面可复用上文中的各类RN优化工具集,性能与到达率接近于原生;同时,H5迁移RN成本较低,可通过替代View层(CSS -> JSX)与平台API适配层完成迁移,整体逻辑具备通用性和一致性;
IAP体系及优化手段 - iOS
IAP数据预取
在常规的IAP支付流程中,整体流程是从请求苹果服务端获取当前交易商品的对象开始的。因为苹果服务端架设在海外,仅有香港等地有转接点,导致国内用户负责的网络环境请求苹果服务端时错误率较高,当商品信息获取失败时,用户本次支付流程也将会失败。该部分错误在云音乐App内占比不小,因此我们针对该流程进行了预取优化。
优化结果
缓存命中率率:0%->96.52%
-4错误量:降至0
消耗型商品支付成功率:+1.35pt
订阅型商品支付成功率:+0.46pt
IAP商品预取流程
- APP启动进入到首页云音乐服务端下发热门商品IAPID列表;
- 使用热门商品IAPID请求苹果服务端,获取对应的商品对象,并做内存级别的缓存;
- 在合适的时机以及频率对该部分缓存进行更新+维护;
IAP商品预取后的支付流程
- 用户在端内发起IAPID为X的商品支付;
- 查找端上缓存是否存在X商品的IAP商品对象缓存;若存在,则直接使用缓存对象进行后续支付流程;若不存在走原本的支付流程,从请求IAP商品对象开始;
该方案使IAP支付成功率有不显著正向提升,其中商品预取流程对消耗型商品的整体支付成功率提升大于对订阅型商品;对IAP支付整体的商品预取错误(errorCode = -4)几乎是完全解决。
Storekit2
StoreKit 2 是苹果公司在 iOS 15 和 macOS Monterey 中引入的一组更新和改进的框架,用于处理应用内购买和订阅相关的功能。StoreKit 2 提供了一些新的功能和改进,使开发者能够更方便地实现应用内购买和订阅的流程。
其中云音乐需要使用的新特性如下:
- 小票使用UUID编码附带OrderId
- 小票监听功能:跨设备订单同步
- 可以准确判断用户是否具有促销优惠资格isEligibleForIntroOffer等
StoreKit2的接入,应当把现有能力都包含在内,和StoreKit1的流程对齐;核心注意点如下:
- 为了避免一次性全量对营收造成较大不可预估的影响,StoreKit2需要逐步放量,通过AB实验控制放量节奏与随时降级回StoreKit
- StoreKit2苹果仅推出了Swift版本,因此部分StoreKit1的逻辑需要重新开发,例如商品预取逻辑StoreKit2与StoreKit1的商品对象是完全不同的两个类,StoreKit2的预取逻辑需要重新使用Swift开发
- StoreKit2针对未完成小票的处理和StoreKit1有较大的不同:云音乐端内在StoreKit1的验票流程中有做缓存小票+轮询重试的优化措施,在StoreKit2中的类似逻辑的处理方式需要用配套的API重新开发,并且StoreKit1和2存在同时监听到同一小票的情况,因此需要隔离两套未完成小票的监听逻辑
- SwiftOC混编问题,云音乐主站核心是使用OC进行开发的,因此为了避免影响工程整体且方便使用,StoreKit2的必要流程都使用Swift开发,对外暴露的接口使用OC再进行封装一层;业务层使用时仅需要使用上层OC接口无需使用Swift接口
具体预期提升
- 小票关联订单ID提升问题排查效率;
- 新的小票监听能力比StoreKit1能够获取更加全面的历史小票信息,能有效减少因验票问题导致的退单问题;
- StoreKit2部分接口性能按照苹果官方文档介绍有所提升,预期能够提升支付成功率;
- StoreKit2升级方案在端内拥有随时降级的能力,不会破坏原有的StoreKit1支付能力;
端侧能力同步更新 - Android
Android支付唤起依赖于三方渠道,目前云音乐App集成支付宝、微信支付、银联支付、抖音支付、网易支付等多种三方支付渠道。
云音乐App对于三方支付SDK更新频率较低,但部分三方支付SDK新版本引入了新功能以及稳定性提升,同步更新升级这类SDK可带来一些支付成功率的提升。如支付宝新SDK引入淘宝登录等能力,可以减少未安装支付宝App用户更便捷使用H5页面支付等。
优化结果
支付成功率(升级渠道单次支付):+3.29%
更新与验证
SDK升级较简单,只需按照三方官网升级版本号以及更改兼容方法即可,但升级SDK也具备一定的难点:
- 价值测算:一个App中仅可依赖一份SDK,难以通过AB实验验证价值;
- 问题回滚:若升级SDK对支付成功率有负向影响,实时回滚成本高;
我们基于上述问题采用了下述支付SDK升级发布流程,在分流 / 灰度 / 渠道分阶段去验证不同问题。
三方支付SDK升级验证流程
- 分流:同时打出两个版本包C与T(仅支付SDK版本差异)替代AB实验进行少量且等量分发,在此阶段初步验证崩溃问题以及支付成功率数据;
- 灰度:分流验证无问题后,合入灰度分支,并跟随灰度扩量分发继续观测相关数据;
- 渠道:版本扩量,同时对比多个线上版本,通过实时监控验证与分析支付成功率等数据;
支付挽留措施
IAP支付挽留短信 - iOS
因iOS系统中IAP的支付成功率较低,且这部分有意愿购买用户的错误支付很容易造成订单流失,给云音乐整体营收带来不小的影响,因此我们在IAP支付失败后,通过短信挽留的方式,提醒用户支付失败,引导用户重新支付。
优化结果
主动购买UV:+0.28%
具体方案
云音乐并未采用前端在用户支付失败后,主动调用短信接口的方案,因为部分前端页面可能会在支付接口返回前就已经被关闭,覆盖量有限。
期望覆盖的所有的IAP未支付成功的订单,就需要在IAP支付未成功时一定延迟后发送延迟消息,并由服务端内部判定订单状态。根据业务定制的延迟时间复核订单是否支付,如未支付则通知到业务侧,触发后续挽留动作。
相较于无挽留动作时,针对流失订单的挽回还是有很好的效果的,该方案投入产出比极佳。
总结
在过去的一年,我们建立了交易链路领域相关的漏斗,并基于分析落地了链路不同切面上的优化,如核心收银台的性能优化、三方渠道支付稳定性保障与改善以及支付挽留等。事实证明,作为营收业务的核心模块,针对支付链路的优化不仅能提升支付效率与用户体验,还能有效赋能业务,带动业务关键指标的提升。
未来我们会持续聚焦于交易链路领域进行技术漏斗及策略的优化,探索端侧智能与营收策略的结合;
最后
更多岗位,可进入网易招聘官网查看 https://hr.163.com/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。