写点什么

客户端稳定性优化实战,Crash 率最高下降 40%

  • 2020-08-10
  • 本文字数:3729 字

    阅读完需:约 12 分钟

客户端稳定性优化实战,Crash率最高下降40%

大促一直是技术和产品的练兵场,每到大促,各种丰富的富媒体,如直播,视频,3D,游戏互动,AR 等竞相上线,在淘宝的大航母战略下,都集中在万千宠爱于一身的淘宝 App 上,在这样的大促场景下,开始触碰到端侧系统资源上限的天花板。在 17 年双 11 大促期间,端侧的内存问题尤为突显,OOM 的高居所有问题的榜首。内存问题成为了这几年大促端侧稳定性最大的挑战。



17 年双 11 Crash 问题分类



17 年双 11 Crash 走势与业务上线关系

放飞业务

两年后的今天,通过我们持续的技术挖掘与治理,内存问题不再是影响大促稳定性的最主要的因素,本次 618 大促前所未有的支持了猜你喜欢无限坑位,支持了丰富的直播和小视频玩法,支持了会场上百个运营坑位,支持了互动业务的不降级策略,各种业务花式上线的同时,我们的端侧稳定性还进一步提升,crash 率远好于去年同期。



618 期间今年与去年对比 crash 走势

迎难而上,各显神通

面对内存带来的挑战,我们 2 年以来,一直在摸索中前行,沉淀一套内存治理的经验。



面向大促,当出现了问题后,我们要去思考当前的机制与规范,于是我们制定了内存标准与业务的上线验收。同时,提供了内存分析的一套工具,方便很快很准找到问题。同时,我们制定了三套内存优化策略:


  1. 精打细算,提升内存的使用率

  2. 兜底容灾,尽量让应用延长生命

  3. 提升内存上限,突破系统的天花板

验收标准-----一夫当关

由于内存天花板的存在,从稳定性角度综合考虑,引入了大促的验收标准。标准的制定过程中,我们统计了发生 OOM 时的水位内位,分析出了高危,危险,正常水位线,以此为内存标准的制定指引。


内存问题之所以复杂,是因为内存是一个全局共享池子,当出现溢出问题时,在没有明显问题时,很难去界定哪个业务存在问题,因此,在考虑标准的时候,我们定义了两种场景。单页面及链路。


单页面场景 主要是为了减少单个业务过多的占用内存引发的风险。前面提到内存池子是全局且有限的,当单页面占据内存过多,就会导致系统整体可用的内存大幅减少,在浏览相同页面次数的情况,增加整体内存风险。


链路场景 是对常见浏览链路的内存检测,比如从首页-会场-互动-店铺-详情-下单这样的常规玩法进行多页面叠加检测,判断用户正常场景下的内存风险。


同时,在制度内存标准时,也考虑了不同技术栈之间的差异。比如 H5,weex,native,包括多 tab 的会场形式及直播,3D 等。



测试同学研发的 TMQ 自动化测试工具

内存优化三板斧

前面提到内存优化主要有三种策略,这里分开详述。

精打细算-提升内存的利用率

在业务屡屡触及内存天花板的情况下,每 1KB 的内存,都显得非常珍贵。


在实际对内存占用的分析中,我们偶尔会发现有些场景加载的图片远大于视图的大小,造成内存的浪费。或者在某些场景下,图片在内存中持有过久,比如在后台或是压栈很久后,图片所持有的空间仍不能释放出来给当前界面使用,面对这样的场景,我们在高可用体系中引用了对应的功能,能够检测出这些 case,以便把内存交给用户正在使用的组件,以此来提升内存的利用率。


从图片库的数据流转以及 View 生命周期出发,来设计图片自动回收和恢复的实现,即当 View 不可见的时候,自动释放图片到图片库缓存,只保留图片的 key 值;当 View 可见的时候,又通过 key 恢复图片。图片片自带三级缓存策略,回收后的图片如果还在缓存,能立马恢复,对体验几乎无损。


同时,针对一些内存大户,也和各业务方约定一些实例数限制,比如详情页,有大图,还带视频,webview 等,内存使用相对较大,这种情况下会对实例数做要求。目前有限制包括详情页,播放器实例等。


为了更好的体验,在降级策略上我们也做了一些优化,不再一刀切,而是根据各设备自身的能力,有选择的进行降级。要更好的达成目标,我们首先对设备进行分级,依赖于创建的智能分级。



统一降级在设备评分的基础上,提供默认的高中低端机型的设备分级能力,增加了配置化能力,为每个核心业务分配一个 orange,支持业务对系统、品牌、机型、设备分、应用版本、生效时间等多个维度进行配置化降级。


依赖于统一降级,可以做到精准的体验分级,高端机型,可以采用各种特效和高清图片,能保障最优体验。中端机型,降级掉一部分特效,可以获得较好效果,低端机型,保障稳定性和基础体验。实现 “高端设备最炫体验,低端设备流畅优先,紧急问题快速降级”



统一降级后的效果

兜底容灾–尽量延长生命周期

在应用内存最危险的时候,也许下一次的内存申请即面临崩溃,在这最危险的时候,我们是否有能力缓解一下,让用户多下一单呢,为此我们设计了内存容灾 SDK。


具体原理是基于 gc 和 lowmemorykiller 原理实现(Android 的 OOM 要区分 jvm heap 内存不足和 native 的内存不足),通过监听系统的 gc 和 lowmemorykiller,去计算系统当前所处的内存状态,当内存不足的时候,销毁掉优先级较低的 Activity,从而保障用户可见面 Activity 能尽可能多的使用内存而不出现稳定性问题。



内存容灾基本原理

扩充上限-突破系统天花板

手淘的战略一直是航母战略,前面的打法只能缓解当前的稳定性问题,只能治标,不能治本。业务技术对内存的需求有增无减,无限坑位,会场上的直播视频等,都带来进一步的压力。只有提升端内的内存容量,才是解决内存问题的最终解法。


多进程


多进程的使用是突破系统天花板的方法之一。由于大促态的变化新增以 H5 的页面居多,所以我们重点希望在 webview 上能有一些突破。这时苹果的 WKWebivew 被纳入到研究范围,关于 WKWebview 在内存的优势,经过我们的分析结论如下:


WKWebView 的内存并不计算在主应用的内存中,而是作为独立进程单独进行计算,因此对于应用来说使用 WKWebView 相比 UIWebView,应用整体可以使用更多的内存,因为 Web 的内存都在 WKWewbView 的 Web 进程中,并不影响主应用的内存上限。


对于 Android 来说,平台本身则支持的多进程方式,因此,我们最初的设计中,是依赖于 Activity 的独立进程方式,即使 BrowserActivity 独立出来。


在 99 大促的 AB 实验中,对比对照组,在访问过淘金币/互动的用户中,主进程 native crash 率下降 15%-18%,Crash 计数(主+子) 下降 1 万次以上。在所有用户中,下降 3%-5%,对内存的优化效果还是比较明显。


但是考虑到很多基础 SDK 在设计之初并没有考虑到多进程的方式,且多进程下应用的生命周期也有一些变化,整体方案不确认的风险较大。最终采用的是 UC 内核的多进程方案,它将整个 H5 页面的解析、排版、js 执行等实现抽离封装到一个独立的进程中,分担了主进程一部分内存压力,从而实现突破单进程内存容量天花板的目标。



UC 多进程示意图



uc 多进程对 crash 率的影响


根据严格 AB 实验的结果评估,手淘开启 UC 多进程之后,Crash 率能有 30-40%的下降收益。


64 位升级


一般说来,现在使用的程序,都是在 32 位的指令集下编译出来的结果,在 32 位子系统下,内存地址的大小只有 4 个字节,理论上的最大寻址空间只有 4G。前面提到,在当前手淘的业务容量下,4G 的内存地址已经不能满足,在今年开始力推手淘 andorid 架构从 32 位升级到 64 位。


说到 64 位,在硬件上,arm v8 及以后的 cpu 都升级到了 64 位的架构,在软件上,android 5.0 以后的系统开始支持了 64 位子系统。我们做过比较准确统计埋点,在市面上的手机,约有 95%是支持 64 位运算的,也就是说 64 位升级带来的收益可以覆盖到绝大多数的用户。另一方面,我们也要看到 64 位升级带来的风险,所有的 C/C++代码都需要重新编译到 64 位指令集,可能的风险点包括:


  • 指针长度是从 32 位升到 64 位,对一些 HardCode 的写法可能计算出错,产生稳定性问题。

  • 自定义 so 的加载逻辑(如服务端远程下载)可能没有考虑多 cpu abi 的情况,加载错误 so,产生稳定性问题。

  • 储存的数据,看看有没有因为 64 位和 32 位不同导致不兼容,特别是一些二进制数据,导致覆盖安装或升级后原数据不可用


为了应对这些风险,自 3 月份起就开始针对手淘中的 120 多个 so 进行回归,包括看 32 位与 64 位相互覆盖的升级场景,另一方面,针对 so 的加载逻辑,进行全手淘代码扫描,分析和查看自定义加载 so 的场景确认是否支持多 cpuabi。经过几个月的灰度和迭代,最终在 618 版本前,完成了 64 位的上线。



在本次的 618 大促中,可以明显看到,以往大促中,OOM 的占比,最高的时候,可以占到近 40%,经过 64 位升级与多进程手段叠加后,可以看到看大促态的 OOM 占比,已经降到了 10%左右。这里面还包括了 5%的 32 位用户,对 OOM 的治理效果非常显著。

展望

  • 新技术形态的挑战

  • 内存问题一直是大促端侧稳定性最大的挑战,在今天已经得到比较好的解决,当然,系统资源终归是有限的,我们仍然需要有效合理的使用系统资源。更重要的是,面向未来,新的技术形态像 flutter 等入淘,多个虚似机的并存,对系统资源仍然会有较大的挑战。

  • 从稳定性到流畅体验

  • 对用户来说,稳定性只是最基础要求,后续我们会在体验上持续优化,带给手淘用户真正的如丝般顺滑的体验。


本文转载自公众号淘系技术(ID:AlibabaMTT)。


原文链接


https://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=2650409401&idx=1&sn=7eaff7213e397c24cea658173c0a45c8&chksm=8396c1a1b4e148b765c1a82503b4c713a58a93fe673371efd8d38f68952c21c154c54c2126d6&scene=27#wechat_redirect


2020-08-10 14:042959

评论 1 条评论

发布
用户头像
谢谢分享场景。
2020-08-11 13:07
回复
没有更多了
发现更多内容

云原生在京东丨云原生时代下的监控:如何基于云原生进行指标采集?

京东科技开发者

云原生

一个草根的日常杂碎(10月20日)

刘新吾

随笔杂谈 生活记录 社会百态

年纪轻轻怎么就卵巢早衰了?试管可帮忙!

Geek_65d32f

试管 三代试管

架构师训练营 1 期 -- 第五周作业

曾彪彪

极客大学架构师训练营

架构必修:领域边界划分方法--职责驱动设计(RDD)

马迪奥

架构 领域 架构师 RDD

1分钟带你入门 React 公共逻辑抽离HOC...

Leo

大前端 React Hooks HOC Render Props

Linux的上手命令

Linux 常用命令

甲方日常 35

句子

工作 随笔杂谈 日常

央行数字货币离我们还有多远?

CECBC

数字货币

java week1练习

闷骚程序员

数据结构与算法系列之链表操作全集(一)(GO)

书旅

数据结构 数据结构和算法 Go 语言

架构师必备的那些分布式事务解决方案!!

架构师修行之路

分布式 微服务 架构设计

【线上排查实战】AOP切面执行顺序你真的了解吗

Zhendong

spring aop

mongodb 源码实现、调优、最佳实践系列-百万级代码量mongodb内核源码阅读经验分享

杨亚洲(专注MongoDB及高性能中间件)

MySQL mongodb 源码 中间件 分布式数据库mongodb

聊聊技术人员如何学习成长

架构精进之路

职业成长

分布式下,我想要一致性

架构师修行之路

分布式 微服务

利用区块链等技术,加强对交通运输信用信息的归集共享和分析应用

CECBC

区块链 交通运输

算法分析关键

Geek_0b8195

算法和数据结构

架构训练营学习笔记之五技术选型(一)

于成龙

架构训练营

一个草根的日常杂碎(10月18日)

刘新吾

随笔杂谈 生活记录 社会百态

Go语言内存管理三部曲(三)图解GC算法和垃圾回收原理

网管

内存管理 垃圾回收 GC GC算法 Go 语言

透视HTTPS建造固若金汤的堡垒

码哥字节

https 加密解密 HTTP

Nginx 在运维领域中的应用,看这一篇就够了

华章IT

nginx Linux 运维工程师

二十、深入Python迭代器和生成器

刘润森

Python

深入java week1-01 字节码、内存、GC、调试工具

闷骚程序员

vivo 商城前端架构升级—前后端分离篇

vivo互联网技术

Java 大前端 前后端分离

一个草根的日常杂碎(10月19日)

刘新吾

随笔杂谈 生活记录 社会百态

Flink窗口算子-6-8

小知识点

scala 大数据 flink

第四周作业

dll

游戏数值策划之常用excel函数

吴优秀同学

Excel 游戏

万物互联的IoT时代,柔性电子会大行其道吗?

脑极体

客户端稳定性优化实战,Crash率最高下降40%_软件工程_邹迪飞(之羲)_InfoQ精选文章