关于闲鱼的 ANR 治理,我有几条心得

标签: dev | 发表时间:2021-08-07 00:00 | 作者:
出处:http://itindex.net/relian

背景

闲鱼在业务的快速迭代过程中,面临着稳定性的考验,尤其是ANR(应用程序无响应)问题尤为突出,在舆情平台偶尔可以看到有用户反馈闲鱼App卡顿、卡死的的情况。发生ANR时系统会弹框引导用户关闭应用,或者直接杀死应用进程,非常影响使用体验,甚至造成用户流失。

ANR问题的难点在于线下极难复现,平时测试过程中几乎没有ANR问题的反馈,但是到了线上,面对Android碎片化机型、系统运行状态、用户操作习惯,导致出现ANR问题。所以必须依靠监控排查针对性地解决问题。本文主要从ANR监控、排查体系、优化案例几个方面阐述闲鱼对ANR问题治理的思路。

ANR引入的原因

要解决ANR问题首先需要了解ANR引入的原因。Android系统通过对应用进程的组件(Activity,Service,Receiver,Provider、input)的响应能力进行超时监控,如果超过预定时间应用进程还未完成任务,则会触发系统的ANR警告。所以ANR引入的原因可以分为两大类

1. 主线程繁忙,来不及处理关键消息:存在耗时消息、或者消息队列拥塞,关键消息得不到调度、或者发生死锁

2. 系统繁忙,主线程得不到调度:系统或应用内部其它线程或资源负载过高(高IO、内存频繁抖动),主线程调度被严重抢占

监控方案

监听anr目录的变化

使用FileProvider监听 /data/anr/traces.txt 文件的变化,并捕获现场进行上报。不过Android 6.0以上版本系统文件权限收紧后,没有读取这个文件的权限。之前我们采用这个监控方案导致大量高版本设备ANR问题漏报。

主线程超时监测

开启一个子线程定期post一个message到主线程,每隔一段时间(比如5秒)监测该message是否被消费掉,如果没有被处理,则说明主线程被卡住,可能发生了ANR,再通过系统服务获取当前进程的错误信息,判断是否有ANR发生。但这个会存在大量漏报的情况,并且轮询的方案性能不佳。

监听 SIGQUIT 信号

系统服务在触发ANR后,会发送一个SIGQUIT信号到应用进程来触发dump traces,在应用侧我们可以监听SIGQUIT信号来判断是否发生了ANR。为了排除其他进程的ANR导致的误报,需要再通过系统服务获取当前进程的错误信息,进一步过滤。第3种方案准确率高,性能损耗小,也是业界目前主流APP采用监控方案。

排查体系

选择了合适的监控方案之后,还需要完善的排查体系以便对ANR问题归因分析。

ANR traces信息

Crash sdk在监听SIGQUIT信号后,会调用art虚拟机内部dump堆栈的接口,获取ANR traces信息,包含ANR进程中所有线程的堆栈,据此可以分析出是否有主线程耗时、死锁、主线程等待锁、主线程sleep等问题。

下图为相册场景下卡死ANR,通过trace文件可以定位到原因为主线程在等待子线程。

下图为webview场景下ANR,通过trace文件可以定位到原因为主线程主动循环sleep,等待资源初始化完成。

主线程消息队列监控

在依靠ANR traces信息修复有明确堆栈的问题之后,剩下比较多的是nativePollOnce的问题,如下图堆栈

堆栈上都是系统消息队列的源码,没有业务代码,似乎不好定位分析。进入nativePollOnce场景可能的几种情况:

1.当前没有待处理的消息,线程进入睡眠状态,等待管道另一端有入队消息唤醒;

2.消息队列其实有消息待处理,但是被设置了同步屏障,遍历队列消息列表如果没有找到异步消息,则会进入nativePollOnce等待唤醒;

3.dump traces 过于耗时导致偏移,耗时消息在dump之前发生。

对于第2点情况,可以通过hook消息队列,检测是否有同步屏障泄露的情况,我们在线上小范围采样埋点并没有发现此类问题。对于第3点情况,可以对ANR发生前主线程消息队列历史消息做监控,在发生耗时消息时主动上报,在发生ANR时把历史消息、当前消息、等待队列的消息通过crash sdk上报云端。

实现方案

通过设置主线程Looper的Printer,监控每一个消息的调度,记录消息的target、callback、what,以及当前时间戳。同时开启一个子线程,如果有消息处理发生则会定时采集主线程的堆栈,并通过时间戳将堆栈与消息关联起来,从而可以了解每个消息在执行时主线程的堆栈。

   publicfinalclass Looper{    
public static void loop(){
......

for(;;) {
......
finalPrinter logging = me.mLogging;
if(logging !=null) {
logging.println(">>>>> Dispatching to "+ msg.target +" "+
msg.callback+ ": " +msg.what);
}
......
try{
msg.target.dispatchMessage(msg);
}finally{
...
}
......
if(logging !=null) {
logging.println("<<<<<Finishedto" +msg.target+ " " +msg.callback);
}
}
......
}
}
由于存在频繁的字符串拼接,对性能有一定损耗,只会对线上小范围采样开启。

方案效果

通过对消息队列的监控,可以看到有一个消息执行耗时155ms,挂钟耗时411ms,观察堆栈可知原因是在主线程调用较重的初始化操作,并且存在跨进程调用,一但阻塞了后面Receiver、Service等消息执行,则会触发系统服务ANR警告。

优化案例

在具备完善准确的监控排查能力之后,下面分享一些优化案例。

SharedPreference优化

从线上ANR的traces数据来看,关于sp导致的anr问题主要集中在3类:1.在特定消息处,主线程等待sp apply队列持久化完成2.主线程对sp commit3.主线程阻塞等待sp加载数据完成在线下测试mmkv与sp对比性能数据,发现mmkv可以比较完美的解决这三个问题。首次安装分别测试mmkv和sp的读写性能(循环1000次取总和,每个key、value均不相同):

第2次启动,只读取kv组件的一个值 我们在编译器通过切面的方式接管所有getSharedPreferences的接口调用,根据白名单配置返回mmkv实现或者原始系统的SharedPreferencesImpl实现,对业务层使用无感知。

网络广播监听耗时优化

从线上ANR的traces数据来看,关于getActiveNetworkInfo的ipc调用不少,通过埋点发现一方面是由于ipc跨进程通信本身耗时,另一方面监听网络状态的广播监听者实例过多,每一个都会重复调用一次查询网络状态,每个累加造成了耗时加剧,一旦阻塞了关键消息的调度执行,则会引发ANR优化方案为通过动态代理IConnectivityManager接口,拦截代理getActiveNetworkInfo方法,优先使用缓存, 由统一全局的网络广播监听器在异步线程IPC获取网络信息,更新缓存,后面可以直接使用缓存,避免多次IPC调用。

启动组件延迟注册

启动Application#onCreate阶段有串行任务会阻塞主线程执行,此时系统发送的关键消息得不到主线程调度就会发生ANR。修复的核心思想是尽量不要在启动阶段注册receiver、service等组件,或者延迟到onCreate全部执行完毕再注册。
   publicclass MyApplication extends Application{    

@Override
public void onCreate(){
//耗时串行任务...
isInitDone=true;
}

@Override
public Intent registerReceiver(final BroadcastReceiver receiver, final IntentFilter filter){
if(isInitDone) {
returnsuper.registerReceiver(receiver, filter);
}

mainHandler.post(newRunnable() {
@Override
public void run(){
MyApplication.super.registerReceiver(receiver,filter);
}
});

returnnull;
}
}

总结和展望

在对ANR问题的监控升级和排查能力的完善之后,通过解决一系列优化方案,ANR率下降一半以上,给用户带来更好的使用体验。希望本文的内容可以开发者治理ANR带来启发,把我们应用代码的性能做到极致。后续我们会思考以下两方面的内容:•继续加强对ANR问题优化治理,比如将关键消息切到异步线程执行,避免主线程队列拥塞得不到调度的情况;•加强防御机制防止数据劣化,比如线下自动化稳定性测试提前发现新增问题。


相关 [anr 治理] 推荐:

关于闲鱼的 ANR 治理,我有几条心得

- - IT瘾-dev
闲鱼在业务的快速迭代过程中,面临着稳定性的考验,尤其是ANR(应用程序无响应)问题尤为突出,在舆情平台偶尔可以看到有用户反馈闲鱼App卡顿、卡死的的情况. 发生ANR时系统会弹框引导用户关闭应用,或者直接杀死应用进程,非常影响使用体验,甚至造成用户流失. ANR问题的难点在于线下极难复现,平时测试过程中几乎没有ANR问题的反馈,但是到了线上,面对Android碎片化机型、系统运行状态、用户操作习惯,导致出现ANR问题.

说说Android中的ANR

- - 技术小黑屋
有过Android开发经历的人都不会对ANR陌生,它和崩溃一样是程序设计的问题. 本文将以较为深入的视角来介绍什么是ANR,出现场景,如何避免以及如何定位分析ANR,希望可以帮助大家在编写程序时有所帮助. ANR全称 Application Not Responding,意思就是程序未响应. 如果一个应用无法响应用户的输入,系统就会弹出一个ANR对话框,如下图所示,用户可以自行选择继续等待亦或者是停止当前程序.

[原]IT安全治理

- - 阿朱=行业趋势+开发管理+架构
2、员工内鬼:IT部门人员、员工用户. 1、我不赞同在服务器上安装软件杀毒软件,往往存在应用软件文件被误杀或误阻拦的风险,使应用多莫名其妙报错. 2、及时更新系统安全类补丁,但不要什么补丁都不更新. 有些补丁的更新确实会引发遗留IT系统的报错,但安全类补丁的更新需要关注并尽量更新. 3、要从多层技术、组织/权责/流程/审批、定期检查多方面配套保证安全,单方面无法保证.

数据治理(Data Governance)

- - ITeye博客
数据治理是指从使用零散数据变为使用统一主数据、从具有很少或没有组织和流程治理到企业范围内的综合数据治理、从尝试处理主数据混乱状况到主数据井井有条的一个过程. 数据治理其实是一种体系,是一个关注于信息系统执行层面的体系,这一体系的目的是整合IT与业务部门的知识和意见,通过一个类似于监督委员会或项目小组的虚拟组织对企业的信息化建设进行全方位的监管,这一组织的基础是企业高层的授权和业务部门与IT部门的建设性合作.

企业治理的绩效之谜

- - 《商业价值》杂志
更强大的企业治理是否带来了更好的公司绩效. 2012年是企业治理领域具有重大意义的一年. 2012年正好是英国《凯德伯瑞报告》发布20周年和美国《萨班斯-奥克斯利法案》颁布10周年. 两起事件都体现了具有里程碑意义的发展. 《凯德伯瑞报告》指导公司与利益相关者尤其是股东之间的相互交往,是这一领域首次出版发行的重要法则.

[原]简单说说服务治理

- - yangfei的私房菜
一般在系统比较小或者业务初期,传统的系统就是一个单机的J2EE,分为DB层、业务层、接入层. 这种结构在较小项目或者初期能够满足绝大部分需求,但是随着业务量或者用户量的增加,发现这种原始结构以及无法满足,可能是业务层的业务逻辑过重,也可能是用户规模的扩大,导致单机已经无法满足. 因此需要进行分布式拆分,一般都会想到按照业务模型,将业务层拆分成各个模块,分别部署,各个模块之间通过RPC之类的协议调用.

如何成功实现数据治理

- - IT瘾-bigdata
如果你处理过大量数据,你也许听说过 “数据治理”一词,你可能会想, 它是什么. 简单来说, 数据治理就是处理数据的策略——如何存储、访问、验证、保护和使用数据. 数据治理包括制定获取方案:谁能访问、使用和共享你的数据. 这些问题正变得越来越重要, 因为企业依靠收集、存储和分析大量数据,来达成业务目标.

dubbo服务治理(一)降级

- - 企业架构 - ITeye博客
在线网站一般都会有服务器压力剧增的时候,比如说网上商城的促销,这个时候常用的手段就是服务降级,根据当前业务情况及流量对一些服务和页面有策略的降级,以此缓解了服务器资源压力,以保证核心任务的正常运行,同时也保证了部分甚至大部分客户得到正确响应. 页面拒绝服务:页面提示由于服务繁忙此服务暂停. 跳转到varnish或nginx的一个静态页面.

美团 HTTP 服务治理实践

- - IT瘾-dev
2019 年 7 月 6 日,OpenResty 社区联合又拍云,举办 OpenResty × Open Talk 全国巡回沙龙·上海站,美团基础架构部技术专家张志桐在活动上做了《美团 HTTP 服务治理实践》的分享. OpenResty x Open Talk 全国巡回沙龙是由 OpenResty 社区、又拍云发起,邀请业内资深的 OpenResty 技术专家,分享 OpenResty 实战经验,增进 OpenResty 使用者的交流与学习,推动 OpenResty 开源项目的发展.

数据治理理论 + 实践

- - IT瘾-dev
数据治理无论是在数仓建设过程中还是数仓建设完成之后都是及其重要的,是数据部门基础建设的必经之路,是降本提效,形成企业数据资产的关键一环. 数据质量管理(Data Quality Management),是指对数据从计划、获取、存储、共享、维护、应用、消亡生命周期的每个阶段里可能引发的各类数据质量问题,进行识别、度量、监控、预警等一系列管理活动,并通过改善和提高组织的管理水平使得数据质量获得进一步提高.