点击蓝字 关注我们
1.背景起源
之前一直都没有考虑过的专项,为什么就突然有这个事儿了呢?印象里记得第一次做端上的性能测试还是在20年春节疫情期间,那时候的网校App更多的是应用功能的增加、玩儿法的拓展....,那时的我们还没有过多的去关注竞品性能,没有关注性能上的潜在问题所带来的用户体感,为了全力以赴支持各地“停课不停学”工作,学而思网校App的下载量也随之提升,但较之竞品却仍有差距,包大小问题就成了性能专项的起源。
2. 临阵磨枪
因需要尽快给出网校及竞品的相关性能数据,我们从以下几个维度着手进行,如下图所示:
接下来我们再从移动端通用性能、网络接口评测、pc端通用性能 共3个方面进一步分析有哪些维度的问题存在。
2.1 移动端性能竞品对比分析
退出直播后不会销毁直播进程,导致非直播内存占用远高于竞品
可能因日志上报、资源下载、冗余接口请求导致上传数据量远高于竞品
App冷启高于竞品
包大小远高于竞品
2.2 pc端性能竞品对比分析
直播/回放场景下,网校内存占用高出不少,后台处理的任务较多。
页面加载耗时,网校加载时间高于竞品
网校的包远大于竞品
2.3 网络接口评测
与竞品相比,潜在性能问题还是挺多的,如:
学而思网校的接口域名过于分散,收敛性弱(学而思域名10+,某竞品主要3个域名)
日志埋点上报接口过多,频率过快;某竞品统一接口,且采用protobuf压缩
接口性能某竞品普遍小于100ms,学而思一般大于100ms
前端探针上报次数过多,发往多个域名
网校进入首页tab时,请求的接口个数较多,其中图片资源的请求比较分散,未做归类;某竞品的图片下载接口比较集中。
网校下载资源接口有302重定向到http的ip接口,有域名劫持的风险和消耗服务端的资源;竞品未发现此问题。
开屏广告的接口对比中发现,我们的h5推广页加载的时间和内容过多过长
......
从上述几个评测维度的部分结果数据来看,无论是App、pc、还是接口,都存在这较多性能或安全性问题,此次的第一版性能数据也为后面如何更好的去做性能测试做了很好的方向指引和铺垫。
3. App 瘦身优化
3.1 App资源梳理
梳理App离线、内嵌的可删除、可压缩类资源
3.2 静态库大小统计
分析业务库、三方库的大小占比
3.3 Android减包技术方案总结以及持续优化思考
3.3.1 设计资源离线化下发方案
从大体的分类可以看到,如果我们把主要资源进行离线的话,包大小可以减少50M到90M,所以第一步优化的方向是把二级入口的资源进行离线处理;因此我们必须要设计出一套方案来解决资源按进入模块的时候下发,并且这套方案能满足以下的几点:
1、能够对所有的资源进行统一管理和下发;
2、能够在进入二级模块的时候进行统一下发,避免分场景的问题;
3、要进行模块拆分,不能所有资源一起下发,这样会导致一次性下发的资源过大;
4、最好能在打包的时候自动化完成资源的打包和上传,最大化减少人工导致的错误;
5、设计好重试机制,当用户下载失败的时候能够重试;
6、做好版本升级时资源包的diff下发方案,要让升级用户只下载增量资源,而不是都重新洗发一次;
7、对用户的资源下载成功率进行上报,指导后续的优化方案;
8、技术方案和框架需要最大化减少修改业务代码,比如6000多张图片访问调用等。
3.3.2 去掉Unity 3D与播放器合并
资源离线完之后还没有达到目标,去掉Unity 3D和播放器合并。Unity 3D截取转动画实现了,每个动作帧生成时间在4分钟左右。后续编写独立的动画组件把内存控制在15m以内,成功在两个项目中实际应用。本次瘦身方案采用这个策略,祛除掉了Unity 3D内核减掉15m体积,功能依然满足,成功达成目标!本次减包的主要方案就是资源分离下发,祛除Unity 3D,顺便删除少量冗余资源,媒体库合并等方式。
当前APP包体积成果图:
3.3.3 方案优缺点分析
总结方案优点如下:
1. 采用标准Android API,拒绝Hook方式比插件化更好,特别是后续系统兼容上
2. 发版阶段不需要各个业务方独立打附件包,而插件化的方式需要独自打附件包
3. 在资源下载更新上我们做到了存量用户增量更新,而插件化的方式无法做到
4. 除了技术本身我们做到了打包 发布 优化 增量等环节的自动化实现,节约迭代成本
5. 我们在图片资源替换显示上做到了无缝替换,最大程度的降低了业务代码修改量
6. 方案实施完毕后,后续的新增项目和需求不再导致APP持续增长,长期稳定。
7. 我们在构造下发框架做到抽象统一 针对Bug修改时也在底层完成兼容,降低成本
总结方案缺点如下:
1. 进入某个独立模块可能会显示一个loading,产品体验上不好
2. 直播模块太大,资源有些多,loading相对不够快。
虽然我们砍掉了一大半的体积,但是持续减包,持续减少资源体积,优化产品体验还需要坚持下去。
4. 从0到1着手建设移动端性能测试
4.1 性能测试流程
开篇前,咱们先简单了解一下QA的整个性能测试流程。预先善其事 必先利其器,性能测试的执行依赖于性能执行场景、性能测试方案等已明确的前置条件,然后QA老师会对新老版本的通过性能自动化脚本执行性能测试,执行完成后再由Python脚本进行原始性能数据结果的清洗后上传到性能评测平台进行可视化展示,同时会将报告周知研发老师,若有性能问题则进行定位修复,再由QA老师进行复测验证,确认解决后则合入分支。
4.2 性能测试方案
俗话说无规矩不成方圆,那么要做性能专项,就要梳理如何做、做什么等明确的研发和测试能达成一致的这么一个规范出来。我们分别从:测试场景、关注指标、对比维度、执行时机、测试方法、测试报告、性能分析等众多维度。
4.3 性能指标的定义标准
4.3.1 冷启耗时
规则定义
App的冷启动就是,当应用启动时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用, 这个启动方式就叫做冷启动(后台不存在该应用进程)。根据苹果官方文档给的应用的启动时序图可以看到冷启动是一个User taps app icon到Final initialization (applicationDidFinishLaunching: withOptions:)的过程,所以冷启动时间就是从用户唤醒App开始一直到App已启动所消耗的时间。
从技术视角出发,以iOS 的启动过程为例,主要分为两个阶段:
pre-main: main() 函数是程序执行入口,从进程创建到进入 main 函数称为 premain 阶段, 主要包括了环境准备、资源加载等操作;
post-main: main() 函数到-didFinishLaunchWithOptions:方法执行结束。该阶段已获得代码执行控制权,是我们治理的主要部分。
以Android 的启动过程为例,主要分为两个阶段:当用户点击app那一刻到系统调用Activity.onCreate()之间的时间段。Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()
从用户视角定义启动,主要以用户主观视觉为依据,以页面流程为标准。
T1:闪屏页
闪屏页是启动过程中的静态展示页。在冷启动的过程中,App 还没有运行起来,需要经历环境准备和初始化的过程。这个过渡阶段需要展示一些视图,供阻塞等待中的用户浏览。
iOS 系统 (SpringBoard) 根据 App Bundle 目录下的 Info.plist 中"Launch screen interface file base name"字段的值,找到所指定的 xib 文件,加载渲染展示该视图。
闪屏页的展示是系统行为,因此无法控制;加载的是 xib 描述文件,无法定制动态展示逻辑,因此是静态展示。
对应技术启动阶段的 pre-main 阶段
T2(可选):欢迎页(广告)
App 运行后根据特定的业务逻辑展示的第一个页面。常见的有广告页。
欢迎页是业务定制的,因此可根据业务需要优化展示策略,该阶段本身也是可选的。
T3:目标页 (落地页)
App 启动的目标页。可以是首页或特定的落地页
目标页的加载渲染渲染完成标志着 T3 阶段的结束,也标志着启动流程的结束。
在T3阶段,我们可以从“页面首元素渲染时间” 或 “页面所有元素加载时间” 标志冷启完成节点。
页面首元素渲染时间:测量的时间是从初始化请求到页面内第一个元素被绘制显示的时间。
以Android为例:Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>contentView的measure/layout/draw显示在界面上。应用的第一次启动才算完成,这时候我们看到的界面也就是所说的第一帧。
页面所有元素加载时间:测量的时间是从初始化请求到页面内所有元素被绘制的时间。App 是面向终端用户的产品,因此衡量启动的最终标准还是要从用户视角出发。
测试方式
1、录制冷启视频:从桌面点击App开始->闪屏页完全消失
2、使用FFmpeg 进行视频分帧
3、使用SSIM 进行相似度对比,使用SSIM指数衡量图片相似度
4.3.2 页面加载耗时
规则定义
native:在应用内点击任一元素控件,从native到native的页面跳转, 页面首元素渲染时间 / 页面所有元素加载时间 参考冷启耗时
h5:在应用内点击任一元素控件,从native到webview的页面跳转, 页面首元素渲染时间 / 页面所有元素加载时间 参考冷启耗时
测试方式:同冷启耗时
4.3.3 FPS
规则定义
Android App应用,平均帧率应保持在 55-60 FPS
iOS App应用,平均帧率应保持在 55-60 FPS
PC端,默认是25 FPS,网校压缩50%,默认为 13 FPS,在拉流过程中可能会因网络等各种因素有波动
测试方式
App端维度:使用perfdog service 采集场景性能。PS:腾讯出品,且Android 采集原理与 支付宝 soloπ 基本一致,数据准确性有保障
PC端维度:通过PC学生端本地日志收集性能指标
4.3.4 CPU & MEM
规则定义
CPU:性能场景执行过程统计应用进程维度的内存使用率,单位:%
MEM:性能场景执行过程统计应用进程维度的内存使用,单位:MB,非内存使用率
测试方式
1、App端同FPS
2、PC学生端使用Python psutil库采集
4.3.5 上下行流量
规则定义
应用使用期间数据上传下载所消耗的流量,单位:KB/S
测试方式
1、App端维度:使用perfdog service 可分别采集上行 和 下行流量
2、PC端维度:通过学生端本地日志中的“bytes”自动获取当前时刻的瞬时上下行总流量
4.3.6 包大小限制
Android:70M、iOS:110M
4.4 定义SLA
SLA是Service-Level Agreement的缩写,意思是服务等级协议。约定各场景下性能变化的一个可接受阈值范围,若超出阈值,则需要我们高优关注了。
5. 性能采集实现方案
我们先通过一张图简单了解下性能测试的技术方案
airtest:编写自动化脚本
gitlab:代码管理
Jenkins:持续集成
perfdog service:性能数据采集服务
Python脚本:数据清洗&上传等任务
性能评测平台:web端性能数据可视化展示分析
5.1 Android App冷启测试方法介绍
5.1.1 adb命令计算APP冷启动时间
WaitTime:返回从 startActivity 到应用第一帧完全显示这段时间. 就是总的耗时,包括前一个应用 Activity pause 的时间和新应用启动的时间;以WaitTime为准
ThisTime:表示一连串启动 Activity 的最后一个 Activity 的启动耗时;
TotalTime:表示新应用启动的耗时,包括新进程的启动和 Activity 的启动,但不包括前一个应用Activity pause的耗时。
总结:这种测试方法简单容易,并且可以准确的计算出系统启动这个Activity的时间。但是缺点是不包括点击icon到系统接收到消息的时间,也就是说这个时间并不能完整的模拟用户操作场景的启动时间。
5.1.2 录制启动视频,截取视频时间计算时间
视频录制的方法主要就是:
1、使用截屏、录屏、高速摄像机录像等方法;
2、使用Adb命令录制视频。
2.1、相机录制视频的方法我就不多说了。
2.2、adb录制视频方法如下:
(1)输入命令adb shell screenrecord --bugreport /sdcard/lanch.mp4 备注:bugreport 参数会使视频输出一些时间信息和帧信息便于我们分析启动时间。
(2)点击收集图标,app完全启动后,使用ctrl+c结束视频录制。
(3)使用命令adb pull 导出视频 adb pull /sdcard/DCIM/lanch-h5-1.mp4 /sdcard/DCIM/lanch-h5-2.mp4 /Users/awesome/Downloads
(4)导出视频到电脑后,使用可以按帧播放的视频软件打开(mac上quicktime就可以,win下可以用kmplayer),并按帧播放。这样就可以看出从点击图标到启动所花的时间。
总结:这种测试方法完全就是还原用户场景,这样的时间可能比较接近于实际用户感应的时间。但是测试方法麻烦,且每次测试的数据差距也许会很大。数据分析起来也会比较麻烦。
5.1.3 代码埋点,输出日志
在代码中打点,查看输出日志。这种方法需要开发过程中在代码里提前准备好专门的日志。然后通过日志打印时间计算启动时间。
总结:可以准确的输出整个启动需要执行的操作,遇到问题也可以准确的定位到具体的函数,比较有针对性。但是缺点是这个需要开发者支持,数据分析起来也或许会比较麻烦。
5.2、iOS 启动时长测试方法
5.2.1 Xcode Developer Tool
使用 Instruments 的 Time Profiler 插件,可以检测 App CPU 的使用情况。能看到 App 的启动时间和各个方法消耗的时间;
5.2.2 客户端计算统计
通过 hook 关键函数的调用,计算获得性能数据。类似的还有一些第三方的性能测试工具;
5.2.3 录屏分帧方式
录屏使用截屏、录屏、高速摄像机录像等方法,记录移动设备屏幕上的变化,分析启动的起止点,获取 app 启动的耗时。
方法 1) 可以精确获取各个方法调用的耗时,需要 App 是 developer 证书签名,否则无法执行测试;
方法 2) 可以精确获取各个启动项耗时,但和实际用户体验感受有一定出入,且需要拿到客户端源码,将工具嵌入客户端中;
方法 3 )和用户直观感受一致,但分析截屏、视频较麻烦,且发现问题时,无法定位到具体的启动耗时项。
目前对于竞品启动时长的对比测试,由于源码和签名的限制,方法 1 和 2 都不太合适。
5.3、录屏测试方案需要解决的问题
录屏测试方案通过记录移动设备屏幕的变化,分析用户从点击 App 图标到看到主体框架出现的时长,因此启动时长的判断必然会受到开屏广告的影响。而各 App 在展示开屏广告的过程中,可能会有其他启动项在执行。因此去掉开屏广告的启动时长测试,会更有参考价值。
在我们反复尝试各 App 后,总结出以下两个不展示开屏广告的规律。
1)开屏广告一般的逻辑是拉取到素材后,下一次启动开屏展示。可以尝试清理 App 缓存后,再启动 App;
2)部分 App 一天内多次启动后,不会再展示开屏广告。
5.4 录屏工具及视频分析
录屏工具我们选取了开源的工具 xrecord。设备连接上电脑后,通过 xrecord 工具将视频文件录制到本地。在每个设备每个 app 启动测试一次,产生视频一条。
视频内容包含:桌面 → 被测 App 图标变黑 → 展示学而思网校/开屏 → 展示主体框架 → 首页内容加载完成。由于首页内容加载完成是异步实现的,因此我们选取分析的关键节点,是「被测 App 图标变黑」和「展示主体框架」这两个点。通过 FFmpeg 将视频转换成分帧后的图像,再通过SSIM选取关键节点。
附相关开源工具ios-control/ios-deploy:https://github.com/ios-control/ios-deploy
WPO-Foundation/xrecord:https://github.com/WPO-Foundation/xrecord
6. 性能评测平台
性能场景自动化执行完成后会将原始性能数据进行清洗及格式转换,然后上传至性能评测平台进行可视化对比及数据分析。平台地址:http://10.90.71.149:8888/perfplat/#/dashboard
平台支持以下几大功能:日志上传、单条性能报告解析、多条性能对比分析、多版本性能指标维度对比、SLA配置、报告群通知、性能排期表等功能,接下来我们简单逐一介绍下。
6.1 日志上传
浏览器会缓存本次登录用户信息并自动带入到“上传人”文本框内,输入其他信息并选择性能报告文件后提交,则上传至服务器并进行数据解析和前端数据渲染。
上传完成后则会在“日志文件列表”页生成一条性能记录,如下图所示
点击解析可查看性能详情
6.2 日志分析列表
日志分析列表是多个版本性能报告的整合,基于新老版本、SLA两个阈值维度分析各场景性能指标的优劣趋势。
数据解析页面内绿色表示此版本性能数据优于上个版本或SLA、红色标识新版本某性能数据有异常,需要RD/QA关注。
6.3 历史数据列表
与日志分析列表不同的是,历史数据列表是将多个性能报告以SLA的维度进行趋势分析。
7. 后续规划
目前移动端的性能测试框架已初具雏形,也欢迎其他有移动端性能测试诉求的团队联系我们,一起探讨、共建。走过了从0到1,但从1到N,从有到优 还有很多事情可以做,比如:视频码流率、视频帧率、通过端打点精细化性能数据、性能问题的定位分析能力...等等。后续建设有了阶段性进展后,会再给大家带来更多的干货内容,敬请期待啦~
往期推荐
致力于互联网教育技术的
创新和推广
微信公众号 : @学而思网校技术团队