写点什么

快手开源自研 OOM 解决方案 KOOM

  • 2020-08-12
  • 本文字数:1700 字

    阅读完需:约 6 分钟

快手开源自研OOM解决方案KOOM

近日,快手宣布开源自研 OOM 解决方案KOOM。据了解,KOOM 是在客户端完成内存监控后,将解析报告上传到云端,传输文件大小仅为 KB 级,运行时用户无感知,对流量基本无影响,适合大规模普及应用,目前该方案已在快手全量业务中应用,OOM 率降低了 80%以上,效果显著。


OOM 是当前 Android 开发中的常见疑难问题,尤其是线上发生的 OOM 问题极难定位。业界当前最知名的方案 LeakCanary,通过监控 Activity/Fragment 泄漏优化 Java OOM 问题,多年来一直为广大 App 保驾护航,解决了 OOM 治理从 0 到 1 的问题。但面对行业不断复杂的业务环境和庞大用户流量,LeakCanary 仍有优化空间:受限于性能,无法在线上大规模部署,仅支持线下使用;只能定位 Activity&Fragment 泄漏,无法定位大对象、频繁分配等问题;需要人工一一分析,无法对问题聚类量化……为了彻底解决 OOM 问题,行业尝试了多种解决方案,通常是基于 LeakCanary 做优化,但至今没有能完全解决监控过程中的性能问题,普遍解决方法是通过采样的办法牺牲一小部分用户的体验来定位问题。


快手 OOM  Killer 沿用行业的研究思路,针对 LeakCanary 无法解决的难题进行自研改造,充分发挥 LeakCanary 原有优势的同时补足短板,打造了一套可以线上部署、兼顾线下、配置灵活、适用范围广泛、高度自动化,埋点、监控、解析、上报、分发、跟进、报警一站式服务的闭环监控系统,将绝大多数 OOM 问题拦截在灰度阶段,彻底解决了 OOM 问题。



KOOM 框架


快手 KOOM 核心流程包括:配置下发决策、监控内存状态、采集内存镜像、解析镜像文件(以下简称 hprof)生成报告并上传、问题聚合报警与分配跟进。

无主动触发 GC 不卡顿

之前行业的普遍做法是通过在 Activity.onDestroy()后连续触发两次 GC,并检查引用队列,判定 Activity 是否发生了泄漏,但频繁 GC 会造成用户可感知的卡顿,快手为实现无感触发设计了全新的监控模块,通过无性能损耗的内存阈值监控来触发镜像采集。将对象是否泄漏的判断延迟到了解析时,阈值监控只要在子线程定期获取关注的几个内存指标即可,性能损耗忽略不计。



内存监控流程图

高性能镜像 DUMP

采集内存镜像传统方案会造成应用完全冻结长达几秒,期间用户完全不能操作,严重损害用户体验。快手利用系统内核 COW(Copy-on-write,写时复制)机制,每次 dump 内存镜像前先暂停虚拟机,然后 fork 子进程来执行 dump 操作,父进程在 fork 成功后立刻恢复虚拟机运行,整个过程对于父进程来讲总耗时只有几毫秒,对用户完全没有影响。


暂停虚拟机需要调用虚拟机的 art::Dbg::SuspendVM 函数,谷歌从 Android 7.0 开始对调用系统库做了限制,快手自研了 kwai-linker 组件,通过 caller address 替换和 dl_iterate_phdr 解析绕过了这一限制。



Fork dump hprof 流程图

“不偷”用户流量的解决方案

传统方案得到的 hprof 文件通常比较大,占用用户大量磁盘空间,上传大文件浪费用户流量,且不利于问题聚类分析。快手采用了新的思路:采用边缘计算的思路,将内存镜像于闲时进行独立进程单线程本地分析,不过多占用系统运行时资源;分析完即删除,不占用磁盘空间;分析报告大小只有 KB 级别,不浪费用户流量。


分析报告生成流程总体分为三个环节,第一个环节扫描镜像构建索引,建立泄露查找分析的基础;第二个环节查找出泄露的对象,根据既有的 framework 知识以及人为设定的策略,执行对象泄露判定;第三个环节生成最终报告文件,将对象泄露路径、泄露数量、类统计、运行时信息添加至报告文件,辅助后续根据报告分析解决 OOM 问题。



解析镜像生成报告流程图


针对镜像回捞需求,对 hprof 进行运行时 hook 裁剪,只保留分析 OOM 必须的数据。裁剪还有数据脱敏的好处,只保留对分析问题有用的内存中类与对象的组织结构,并不上传真实的业务数据,充分保护用户隐私。

总结展望

快手 KOOM 计划做完整的客户端内存解决方案,开发者可以通过接入 KOOM,解决自己项目中的 OOM 问题。此次一期开源暂时只包括 Android Java OOM 解决方案,后续还将开源 Android 线程/文件描述符监控、Android Native OOM 监控、iOS OOM 监控等,最终实现帮助开发者解决各种场景下 OOM 的愿景。

项目地址:

https://github.com/KwaiAppTeam/KOOM


2020-08-12 15:265027

评论

发布
暂无评论
发现更多内容

食堂卡就餐卡系统

叶鹏

常用设计模式

叶鹏

两天,我把分布式事务搞完了

yes

分布式事务 seata

简述JVM垃圾回收

叶鹏

被我玩坏的git:除了之前的工作、当网盘用,还能这么玩

小Q

Java git 程序员 架构 开发

ECMAScript 6新特性简介

程序那些事

nodejs ES6 ECMAScript 6

18 张图,一文了解 8 种常见的数据结构

沉默王二

Java 数据结构

架构师训练营12周作业

叶鹏

架构师训练营第八周作业

叶鹏

Springboot 定时任务

hepingfly

定时任务 springboot 注解

Spring 5 中文解析数据存储篇-@Transactional使用

青年IT男

spring

微服务的框架(Dubbo)架构

叶鹏

用户密码验证函数

叶鹏

前端如何优雅处理类数组对象?

Geek_z9ygea

Java 大前端

oeasy 教您玩转linux 010304 图形界面 xfce

o

一个草根的日常杂碎(9月21日)

刘新吾

生活 现实纪录 随笔

Spring 5 中文解析数据存储篇-编程式事物管理

青年IT男

Spring5

小白理财先转变思维理念

boshi

理财 收入 财富自由

从零开始搭建完整的电影全栈系统(五)——WEB网站、Api以及爬虫的部署

刘强西

爬虫 网站搭建 部署与维护

【性能优化】面试官:Java中的对象都是在堆上分配的吗?

冰河

面试 性能优化 JVM 性能调优 逃逸分析

架构师训练营第7周作业

叶鹏

高难度对话读书笔记—情绪篇

wo是一棵草

anyRTC云端录制功能上线

anyRTC开发者

WebRTC 语音 直播 RTC 安卓

整合Elastic-Job(支持动态任务)

TaurusCode

springboot SpringCloud 分布式任务调度 Elastic-job

Python 中 \x00 和空字符串的区别,以及在 Django 中的坑

AlwaysBeta

Python django 编程

简述 CAP 原理

叶鹏

架构师训练营第四周作业

叶鹏

一文学懂递归和动态规划!

小齐本齐

算法 数据结构和算法

关于Java调用类的main方法

谷鱼

Java 包位置

年度开源盛会 ApacheCon 来临,Apache Pulsar 专场大咖齐聚

Apache Pulsar

开源 云原生 Apache Pulsar 消息中间件

实战中学习浏览器工作原理 — 排版与渲染

三钻

CSS 大前端 浏览器

快手开源自研OOM解决方案KOOM_架构_快手技术_InfoQ精选文章