[关闭]
@zyl06 2021-05-09T06:15:16.000000Z 字数 6395 阅读 666

闲鱼舆情治理建设

舆情 日志 监控


现状和问题

舆情治理前,闲鱼 APP 依托阿里集团的设施建设,已经有拥有以下能力:

以上得到了部分最重要的线上质量数据,也能处理少量舆情问题:

以上手段仍存在较多的问题:

舆情治理方案整体设计

基于现状问题,重新梳理和补充的舆情日志查询体系如下图:

舆情日志

线上舆情问题治理体系

补充内容如下:

本地日志定位能力

本地控制台日志补充

日志治理前期,大量业务日志进入了控制台日志,即便治理后将大量日志转入 tlog 日志,仍有部分日志流入控制台,如 Android Maven 引入独立模块和 Flutter 插件包模块。此外,部分未知异常问题,如视频绿屏、黑屏等,logcat 日志也提供了定位的可能性。

Android Log 模块提供了多种日志缓存类型,见 Android logging,可通过 logcat 命令获取对应类型的日志。这里,我们在用户反馈的时候,分别将 LOG_ID_MAINLOG_ID_EVENTSLOG_ID_CRASH 类型 logcat 读取并写入到本地文件,而后将 logcat 日志同 tlog 文件一起打包通过 AUS 上传至 OSS。

  1. // LOG_ID_MAIN 主应用程序log,-t 设置日志上限 20000
  2. adb logcat -d -v threadtime -t 20000
  3. // LOG_ID_EVENTS 系统事件信息
  4. adb logcat -d -b events -v threadtime -t 6666
  5. // LOG_ID_CRASH 应用程序 crash 日志
  6. adb logcat -d -b crash -v threadtime -t 6666

logcat日志

logcat日志文件

本地日志回捞能力

前面提到,由于在线命令推送成功率低且后台无命令缓存机制,所以闲鱼 App 本地日志回捞困难。为解决日志难以获取问题,舆情治理体系中设计了多种日志回捞策略,见下图所示。

本地日志回捞策略

本地日志回捞策略

本地日志下载查看流程

本地日志下载查看流程

线上卡顿/ANR检测能力

线上用户反馈 ANR 并给出截图证明,因为没有卡顿日志,难以定位问题。

用户反馈卡死

线上用户反馈黑屏,无有效日志难以定位问题

页面卡死的另一种表现

技术方案现状

在闲鱼 App 的混合工程场景,依托 Emas 平台已实现 iOS 端卡顿检测,Flutter 端卡顿检测方案查看 Flutter卡顿问题的监控与思考,这节主要讲述 Android 端线上卡顿/ANR 检测。

在线下场景,Android 端卡顿/ANR 检测手段已经很成熟,普通卡顿检测方案有 BlockCanary,ANR 检测可通过 adb bugreport 查看 traces.txt 文件得到。然而在线上环境,以上卡顿检测方案就存在一定问题。

traces.txt 文件权限问题

在线上场景,为了监听识别是否发生 ANR 以及读取 ANR 内容,APP 需要监听 traces.txt 文件变化,并尝试读取 traces.txt 文件内容。监听文件的方案,在 Android 6.0 及以后存在权限问题,大部分场景无法检测到 ANR

如以下代码执行在红米手机 Android 11 上运行,mSystemTraceFilePath 为 "",mSystemTraceFile 的路径为 "/"

  1. File mSystemTraceFile;
  2. ...
  3. this.mSystemTraceFilePath = "/data/anr/traces.txt";
  4. this.mSystemTraceFile = new File(this.mSystemTraceFilePath);
  5. if (!this.mSystemTraceFile.exists()) {
  6. String propSystemTraceFilePath = SystemPropertiesUtils.get("dalvik.vm.stack-trace-file");
  7. ...
  8. this.mSystemTraceFile = new File(propSystemTraceFilePath);
  9. ...
  10. }
  11. ...

BlockCanary 检测原理和性能问题

核心原理

BlockCanary

BlockCanary 检测 500ms 卡顿

BlockCanary 的核心原理是,设置 UI 线程的 Looper.mLogging 字段,主线程每次处理消息均会执行 print 方法。

  1. public void start() {
  2. if (!mMonitorStarted) {
  3. mMonitorStarted = true;
  4. Looper.getMainLooper().setMessageLogging(mBlockCanaryCore.monitor);
  5. }
  6. }

BlockCanary.java

  1. public void setMessageLogging(@Nullable Printer printer) {
  2. mLogging = printer;
  3. }
  4. public static void loop() {
  5. ...
  6. for (;;) {
  7. ...
  8. // This must be in a local variable, in case a UI event sets the logger
  9. final Printer logging = me.mLogging;
  10. if (logging != null) {
  11. logging.println(">>>>> Dispatching to " + msg.target + " " +
  12. msg.callback + ": " + msg.what);
  13. }
  14. ...
  15. }
  16. }

Looper.java

在 print 方法中时,触发 StackSampler 工作,即取消上一次异步线程延迟任务,重新触发一次延迟任务,延迟时间为 BlockThreshold * 0.8f (假设要检测 500ms 以上的卡顿堆栈,则延迟时间为 400ms)。若 UI Looper 任务发生卡顿(>BlockThreshold),则延迟任务被执行,且在卡顿期间的获取主线程堆栈信息,之后在下一次 print 方法被执行的时候,若确认发生卡顿,则可把主线程堆栈信息当做卡顿堆栈记录上报。

  1. @Override
  2. public void println(String x) {
  3. ...
  4. if (!mPrintingStarted) {
  5. mStartTimestamp = System.currentTimeMillis();
  6. mStartThreadTimestamp = SystemClock.currentThreadTimeMillis();
  7. mPrintingStarted = true;
  8. startDump();
  9. } else {
  10. final long endTime = System.currentTimeMillis();
  11. mPrintingStarted = false;
  12. if (isBlock(endTime)) {
  13. notifyBlockEvent(endTime);
  14. }
  15. stopDump();
  16. }
  17. }

LooperMonitor.java

性能问题

在线上环境,大部分场景下并不会发生卡顿,但卡顿检测 SDK 会一直执行。可以发现 app 每一帧时间(16.6ms),UI Looper 中的任务会执行多次,最终产生大量的无效字符串拼接操作大量小对象碎片。特别的,在线上低端机或者 cpu 负载较高的场景下,app 性能会因此降级,影响用户体感。

  1. logging.println(">>>>> Dispatching to " + msg.target + " " +
  2. msg.callback + ": " + msg.what);

卡顿检测方案

方案设计

针对 traces.txt 读取权限问题,可通过检测主线程 5s 卡顿当做 anr。针对 BlockCanary 线上使用的性能问题,为降低延迟任务取消和触发频率,同时避免字符串对象频繁创建问题,必须放弃 Looper.mLogging 的方案。重新思考为什么可以通过设置 Looper.mLogging 检测卡顿?其满足 2 个条件:

闲鱼线上使用 Android 帧回调代替 Looper Task 方案,同时满足以上 2 个条件:

此外,为避免 BlockCanary 方案延迟任务触发和取消的频率过高的问题,仅在帧回调处记录时间戳,不再取消延迟任务,但在延迟任务执行时判断是否发生卡顿,同时记录主线程堆栈。

假设 500ms 以上为卡顿,整体方案流程图如下:

定义 5s 以上卡顿为 ANR,为检测 ANR,同样通过 500ms 卡顿检测,并做卡顿堆栈聚合,当连续发生卡顿大于 5s 且堆栈信息不变,则认为发生 ANR。发生 ANR 时,记录当前设备 CPU 负载等信息。

检测效果

闲鱼首页卡片点击事件中故意制造 500ms 和 5s 卡顿查看卡顿检测结果。

  1. // CardView61801.java
  2. private void doOnClick(String redirectUrl, Map<String, String> trackParams) {
  3. if (null == mCardBean) return;
  4. try {
  5. Thread.sleep(500);
  6. // Thread.sleep(5000);
  7. } catch (Exception e) {
  8. e.printStackTrace();
  9. }
  10. ...
  11. }

查看检测结果

小结

以上是闲鱼 Android 线上卡顿检测方案,线上已经运行超过 3 个版本,通过日志可发现用户反馈卡死、无反应、闪退、黑屏等现象都有可能是 ANR 造成。整体方案有以下特点:

主动发现问题能力

由于闲鱼 App 反馈入口较深,因此相比上亿用户而言,每日技术舆情反馈量占比偏低,以此可知技术舆情反馈量并不能准确反应线上质量情况。为此,我们通过监控埋点构建线上关键舆情问题和基础性能大盘,同时通过监控大盘主动发现线上重点待解决问题,加速线上舆情收敛速度和质量提升,流程图如下所示。

主动发现问题设计图

主动发现问题流程图

监控大盘

主动发现问题监控大盘

主动发现问题大盘示例

监控问题定位

基于大盘发现了问题,需要获取对应日志来定位问题,但问题对应的用户很可能并不会反馈舆情或反馈内容不是该问题,为此我们构建了实时日志查询以及本地日志批量回捞能力。

实时日志查询平台

实时日志查询平台

自建舆情追踪平台

针对关键监控问题,客户端增加对应的 SLS 实时日志,在自建舆情追踪平台获取用户的在线日志。平台支持用户名和时间查询,同时支持用户行为、用户异常、舆情日志类型的组合查询。

本地日志批量回捞能力

在线日志难以避免存在日志内容不足的问题,如基础日志、其他关键模块日志等,然而单个用户的本地日志回捞成功很低(原因见上文内容),为此构建舆情日志回捞平台,通过批量回捞的方式确保能获取到舆情问题某个用户的本地全量日志。

总结和展望

以上初步建立了闲鱼舆情治理体系:

此外,未来仍有很多的演进空间如下:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注