第18章 性能监控平台:自定义性能监控SDK、埋点与上报、实时告警、APM工具对比

性能监控这件事,说白了就是给App装上一套"体检系统"。没有它,你根本不知道用户手机上的App到底卡不卡、崩不崩、耗不耗电。我见过太多团队,上线前测得好好的,一上线就崩得稀里哗啦——嗯,就是缺了这套东西。

18.1 自定义性能监控SDK:从零搭一套

为什么要自研?说白了,第三方SDK再牛,也做不到完全贴合你的业务场景。我习惯把监控SDK拆成三层:采集层、处理层、上报层。

核心设计原则:

  • 轻量——不能影响主线程性能,采集本身不能成为性能瓶颈
  • 可配置——不同模块、不同版本可以动态开关
  • 容错——SDK自己崩了不能拖垮App

先看一个最简单的采集器骨架:

public class MonitorSDK {
    private static volatile MonitorSDK instance;
    private ExecutorService ioExecutor;
    private Map<String, MetricCollector> collectors;

    private MonitorSDK() {
        ioExecutor = Executors.newSingleThreadExecutor(r -> {
            Thread t = new Thread(r, "monitor-io");
            t.setDaemon(true);
            return t;
        });
        collectors = new ConcurrentHashMap<>();
    }

    public void registerCollector(String name, MetricCollector collector) {
        collectors.put(name, collector);
    }

    public void start() {
        for (MetricCollector collector : collectors.values()) {
            ioExecutor.execute(collector::start);
        }
    }

    public interface MetricCollector {
        void start();
        void stop();
        MetricData snapshot();
    }
}

这里有个坑——线程模型。我曾经见过一个团队,直接在主线程做采集,结果监控SDK本身成了卡顿元凶。记住:采集、处理、上报,全部走异步。

18.2 埋点与上报:数据怎么来、怎么走

埋点分两种:自动埋点手动埋点。我个人更推荐"自动为主、手动为辅"的策略。

自动埋点:无侵入式采集

利用AOP(Aspect Oriented Programming)或者字节码插桩,自动拦截关键方法。比如Activity生命周期、网络请求、点击事件。

@Aspect
public class ActivityMonitorAspect {
    @Around("execution(* android.app.Activity.onCreate(..))")
    public void onActivityCreate(ProceedingJoinPoint joinPoint) {
        long start = System.nanoTime();
        try {
            joinPoint.proceed();
        } finally {
            long cost = (System.nanoTime() - start) / 1_000_000;
            // 上报Activity启动耗时
            MonitorReporter.report("activity_create", cost);
        }
    }
}

手动埋点呢?留给业务方自己调用。比如用户点击"下单"按钮,这种关键路径必须手动打点,因为自动埋点抓不到业务语义。

上报策略:别把服务器打崩了

上报不是"采集一条发一条"。我建议做三件事:

  • 聚合——相同类型的数据合并成一条,减少请求次数
  • 压缩——用Protobuf或者MessagePack,别用JSON裸传
  • 兜底——网络失败就存本地,下次启动再补发

避坑指南:我曾经遇到过上报数据量太大,直接把后端打挂了。后来加了"采样率"控制——线上只采集1%的用户全量数据,其余用户只采集异常数据。这样既保证了覆盖面,又不会把服务器压垮。

18.3 实时告警:别等用户骂了才知道

告警的核心就一句话:在用户感知之前发现问题

我习惯把告警分成三级:

级别 触发条件 响应方式
P0(致命) 崩溃率 > 0.5% 或 ANR率 > 0.3% 电话/短信通知值班工程师
P1(严重) 页面加载 > 5秒 或 网络错误率 > 10% 企业微信/钉钉群@所有人
P2(一般) 内存泄漏增长 或 卡顿帧率 > 20% 日报/周报汇总

告警阈值怎么定?别拍脑袋。我建议先跑两周"静默模式"——只采集不上报,拿到基线数据后再设阈值。比如崩溃率基线是0.1%,那告警阈值就设在0.3%,留点余量。

18.4 APM工具对比:Firebase vs 友盟 vs 自研

市面上APM工具不少,我挑三个最常用的对比一下。

维度 Firebase Crashlytics 友盟+ 自研
接入成本 低,几行代码 低,但需要申请权限 高,需要从零搭建
数据隐私 数据在Google服务器 数据在国内,合规性好 完全可控
自定义能力 有限,只能采集预设指标 中等,支持自定义事件 无限,想采什么采什么
实时性 分钟级延迟 分钟级延迟 秒级,可自定义
成本 免费(但需翻墙) 按量付费 开发+服务器成本

我的建议是:小团队先用Firebase或友盟,快速验证。等业务规模上来了,再逐步替换成自研。我自己带的项目就是"先友盟后自研"的路线——友盟帮我们度过了最缺人的阶段,自研帮我们解决了定制化需求。

注意:如果你做的是金融、医疗等强监管行业App,数据合规是第一位的。这种情况下,自研几乎是唯一选择。我曾经帮一个银行客户做监控,对方明确要求"数据不出国、不出机房"——那第三方工具基本全废了。

18.5 整体架构:一张图说清楚

下面这张图是我自己项目里用的监控架构,你可以参考:

性能监控SDK整体架构 采集层 CPU/内存/帧率 网络请求/页面加载 崩溃/ANR/异常 处理层 数据聚合/去重 采样率控制 本地缓存/压缩 上报层 批量上报/重试 Protobuf序列化 HTTPS加密传输 后端服务 数据清洗 → 存储 → 分析 → 告警 P0/P1告警 P2告警 日报/周报 采集 → 处理 → 上报 → 后端分析 → 分级告警

这张图其实就讲了三件事:采什么、怎么存、怎么报。采集层负责从App各个角落抓数据,处理层做聚合和压缩,上报层负责安全可靠地送到后端。后端拿到数据后,清洗、存储、分析,最后触发告警。

嗯,这套架构我用了三年,迭代了四个版本。从最初的"能跑就行"到现在的"毫秒级告警",踩过的坑不少,但效果也确实好——线上问题平均发现时间从2小时缩短到了5分钟。


公众号:蓝海资料掘金营,微信deep3321