Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

APM 与线上监控

☆ APM 把 “性能优化” 从本地经验升级成线上体系. 你的风控 SDK 背景可以重点讲 native crash, 采样, 灰度和宿主影响控制. 方法论, 指标口径与跨域取舍见 性能优化总览.

一, APM 监控什么

类型指标关键证据
CrashJava crash, native crash, 崩溃率堆栈, 版本, 机型, ABI
ANR主线程阻塞, 输入超时, 广播 / Service 超时traces, 主线程栈, 锁等待
卡顿慢帧, 冻结帧, 帧率Choreographer/FrameMetrics/Perfetto
启动冷启动, 首帧, 可交互时间launch trace, 业务埋点
网络成功率, 耗时, 错误码, 弱网interceptor, DNS/TLS/connect/read 分段

二, Crash 监控: Java 与 Native

Java crash 常通过 Thread.setDefaultUncaughtExceptionHandler 捕获; native crash 需要 signal handler 或 Breakpad/Crashpad 这类方案.

面试边界: 不要说 “所有 native crash 都能优雅恢复”.多数情况下只能采集现场, 下次启动上报, 灰度回滚.

三, ANR 与卡顿监控

  • ANR: 系统判定, 重点是拿到 traces 和主线程阻塞证据.
  • 卡顿: 应用侧可用主线程 watchdog, Choreographer 帧回调, FrameMetrics 监控.
  • 线上采样必须控制开销, 避免监控本身制造卡顿.

四, 启动与网络监控

启动监控要区分进程创建, Application, 首 Activity, 首帧, 业务首页可交互. 网络监控要拆 DNS, TCP, TLS, 请求, 响应, 解析, 不要只报一个总耗时.

五, 上报链路, 采样与隐私

  • 本地缓存: 避免 crash 当场丢失日志.
  • 批量上报: 减少电量和流量开销.
  • 采样: 高频事件不能全量.
  • 隐私: 不上传明文 token, 手机号, 身份证, 设备敏感字段.

六, 怎么把 SDK 经历讲成亮点

可以这样组织:“SDK 嵌入宿主 App 后, 我关注的不只是功能成功, 还要保证不拖累宿主稳定性. 我们会监控 native crash, 初始化耗时, 线程/网络开销, 灰度阶段看指标, 异常时能按版本/ABI/机型聚合定位.”

七, 线上定位闭环: 符号化, 聚类, 告警与回归检测

APM 面试的加分点是讲清 “采集之后怎么用”.只说捕获 crash 不够, 还要能把问题聚类, 定位, 告警, 灰度拦截.

Crash 符号化流水线

环节关键数据作用
构建归档versionCode, git sha, mapping, native symbols, build id确保线上堆栈能还原
崩溃采集Java stack, signal, 寄存器, 线程栈, ABI, 机型保留现场
符号化R8 mapping, so debug symbols还原混淆方法和 native 函数
聚类崩溃栈 fingerprint (稳定归类键: 规范化后的相同故障栈使用同一键), 版本, 设备维度找 Top N 问题而不是看单条日志

Native crash 尤其要强调 build id / 符号文件匹配. 没有对应版本的 symbols, 即使采集到了 tombstone 也很难定位.

ANR 与卡顿聚类

  • ANR 不只看主线程栈, 还要看锁等待, Binder 调用, IO, CPU 占用和发生场景.
  • 卡顿指标要用慢帧/冻结帧比例, P90/P99, 不要只报平均 FPS.
  • traces 需要按主线程栈 fingerprint 聚类, 否则线上会被大量重复样本淹没.

Dashboard 与告警

指标常用维度典型用途
crash-free users/sessions版本, 渠道, 系统, 机型, ABI判断能否继续灰度
ANR 率页面, 进程, 系统版本发现主线程 / 厂商 ROM 问题
启动 P50/P90/P99冷/温/热启动, 渠道, 机型档位识别长尾体验
网络成功率 / 耗时域名, 接口, 地区, 网络类型区分端侧和服务端问题

告警不要只设固定阈值, 还要看环比 / 同比和灰度版本对照. 小流量灰度时, 一个新增 Top crash 比整体 crash 率更敏感.

客户端可维护轻量环形日志, 记录页面跳转, 关键按钮, 网络错误, 配置版本等 breadcrumb. 注意只记录定位所需上下文, 不要写入 token, 手机号, 身份证, 精确位置等敏感数据.

APM SDK 自身开销

APM SDK 也要被监控: 初始化耗时, 线程数, 磁盘占用, 上报流量, 采样命中率, 丢弃原因. 面试可以说 “监控系统本身不能成为性能问题”.

采样, 聚合与告警预算

APM 与本地专项的分工是线上发现, 分群和归因. 客户端采样要稳定且可解释, 敏感日志最小化并有保留/删除策略; Crash/native 符号, mapping 和 build-id 必须与制品可追溯. 指标按版本, 设备, OS, 地区和网络聚合, 告警定义窗口, 分母, 基线和错误预算, 避免少量异常样本触发全量回滚.

可执行闭环: 符号还原到灰度验证

以下命令在本机构建产物齐全时使用, 路径和 ABI 必须与线上制品精确匹配; 输出仅说明用途, 不代表已执行或真实 crash. 命令中的 mapping.txt, obfuscated-stack.txt, app/build/intermediates/..., libfeature.so, tombstone.txt 和 0xOFFSET 都是必须替换的输入占位符. 其中 mapping 和混淆栈必须来自同一 Java 构建; 符号目录, so, tombstone 必须匹配 ABI/build-id, so 必须是未 strip 符号文件; 0xOFFSET 必须是根据正确 load bias 计算的该 so 相对地址.

retrace mapping.txt obfuscated-stack.txt
ndk-stack -sym app/build/intermediates/.../arm64-v8a -dump tombstone.txt
addr2line -Cfpe libfeature.so 0xOFFSET

retrace 用同一构建的 R8 mapping.txt 将混淆 Java 栈还原; ndk-stack 用未 strip 符号处理 tombstone; addr2line 把与正确 so build-id 对应的地址定位到函数 / 行. 若 mapping, 符号, ABI, load bias 或 build-id 不匹配, 输出不可作为定位证据. 构建阶段应归档这些制品并为每个上传事件记录 versionCode, build-id 与符号版本.

卡顿采样应只在超过定义阈值或按稳定采样率时收集轻量主线程栈/页面上下文, 设置时间与大小上限, 禁止采集敏感输入. 将 Java/native crash, ANR 和卡顿按规范化栈的 fingerprint (指稳定归类键) 聚类, 再按新增版本, 影响用户数, 核心路径和设备集中度排序.

假设性闭环演练, 非线上事件: 灰度版本出现新增 fingerprint, 先核验符号化与分母, 比较同机型的对照版本; 若影响扩大, 暂停放量并用远程开关降级, 保留样本与 trace. 修复进入下一小批灰度后, 观察 crash-free users, ANR rate, 启动分位数和该 fingerprint 的趋势, 满足预设观察窗口才扩大; 异常反弹则回滚. 这样避免用单条日志或平均值宣布问题已解决.

高频面试题

Q1: 线上卡顿怎么监控? 答: 轻量方案是主线程 watchdog 或 Choreographer 统计慢帧; 深入定位要结合 Perfetto/trace. 线上只采样关键指标, 本地复现再做完整 trace.

Q2: native crash 怎么定位? 答: 采集 signal, 寄存器, 线程栈, so build id/版本/ABI, 结合未 strip 符号或 symbol server 还原堆栈, 按版本和机型聚类.

Q3: APM SDK 会不会影响性能? 答: 会, 所以要采样, 异步, 批量, 延迟上报, 关键路径不做重 IO, 监控逻辑本身也要被监控.

Q4: 线上 crash 很多时怎么快速定位优先级? 答: 先按版本, 机型, ABI, 系统和堆栈 fingerprint 聚类, 看新增问题, 影响用户数, 是否阻断核心路径. Java crash 用 mapping 还原, native crash 用 build id 匹配 symbols. 灰度期如果出现新增 Top crash, 应暂停放量并用配置降级或热修复处理.

Q5: 为什么性能指标要看 P90/P99 而不只看平均值? 答: 平均值会掩盖长尾问题. 移动端用户体验常被低端机, 弱网, 特定 ROM 拉垮, 所以启动, 卡顿, 网络耗时都要看分位数和维度拆分.

易错点 / 追问

  • 不要把本地 Profiler 等同于线上 APM.
  • 不要上传敏感业务数据.
  • 不要只讲采集, 还要讲聚合, 告警, 灰度回滚和修复闭环.