4. 监控数据采集:日志采集、埋点采集、数据库心跳表采集

监控数据怎么来?这是个很实际的问题。你诊断链路、做优化,总得先有数据吧。我个人习惯把采集方式分成三类:日志采集、埋点采集、心跳表采集。每种都有它的适用场景,也有各自的坑。

说白了,这三者不是互斥的。一个成熟的 CDC 监控体系,往往是三种方式混着用。我见过不少团队只依赖一种,结果出了问题才发现数据不够用。

核心观点:日志采集是基础,埋点采集是补充,心跳表采集是兜底。三者配合,才能覆盖延迟监控的完整场景。

4.1 日志采集:最直接的原始数据源

日志采集,就是直接从 CDC 组件(比如 Debezium、Canal、Maxwell)的输出日志里提取监控指标。这是最原始、也是最可靠的方式。

我记得有一次排查一个诡异的延迟问题,埋点数据一切正常,但业务方就是反映数据更新慢。最后我翻了 Debezium 的 binlog 消费日志,才发现是某个大事务的 binlog 文件解析卡住了。埋点只记录了“已消费”的偏移量,但没记录“正在解析”的状态。

4.1.1 采集哪些日志字段?

日志里能提取的信息很多,但别什么都抓。我建议聚焦以下几个核心字段:

字段 说明 监控用途
timestamp 日志产生时间 计算端到端延迟的基础
source_ts_ms 数据库 binlog 中的事件时间 与当前时间对比,得到原始延迟
op_type 操作类型(c/u/d/r) 区分读写比例,辅助分析
table_name 变更发生的表 定位热点表
offset_position binlog 偏移量 追踪消费进度

小技巧:我习惯在日志采集时,额外记录一个 collector_ts 字段,就是采集程序收到日志的时间。这样能区分“日志产生延迟”和“日志传输延迟”,排查时很有用。

4.1.2 日志采集的常见坑

  • 日志量太大:CDC 组件每秒可能产生几千条日志,全量采集会压垮监控系统。我建议做采样,比如每 10 秒取一条,或者只采集延迟超过阈值的日志。
  • 时间戳精度问题:有些日志的时间戳只到毫秒,但 CDC 延迟往往在微秒级。你想想看,如果两个事件间隔 500 微秒,日志里根本看不出来。
  • 日志轮转丢失:我曾经遇到过日志文件被自动清理,导致历史数据断层。解决方案是把日志实时转发到消息队列(比如 Kafka),而不是依赖本地文件。

4.2 埋点采集:主动打点,精准监控

埋点采集,就是在 CDC 链路的各个关键节点主动插入监控代码,上报指标。这种方式比日志采集更灵活,能拿到日志里没有的信息。

举个例子,日志只能告诉你“这条数据被消费了”,但埋点可以告诉你“这条数据从消费到写入目标库花了 3 毫秒”。这就是埋点的价值。

4.2.1 埋点位置怎么选?

我一般会在以下四个位置埋点:

  1. 数据源端:记录 binlog 事件产生的时间戳。
  2. CDC 组件消费端:记录事件被拉取的时间。
  3. 转换/过滤环节:记录数据经过 ETL 处理的时间。
  4. 目标库写入端:记录数据成功写入的时间。

这四个点连起来,就能画出完整的延迟链路。哪一段慢了,一目了然。

4.2.2 埋点数据上报方式

埋点数据怎么上报?我推荐两种方式:

方式 优点 缺点 适用场景
直接写入时序数据库 实时性高,延迟低 对业务代码有侵入 对延迟敏感的核心链路
通过消息队列中转 解耦,削峰填谷 增加一跳,延迟略高 大规模集群,数据量大的场景

注意:埋点本身也会带来性能开销。我曾经在一个高吞吐的 CDC 链路上加了埋点,结果埋点上报占用了 5% 的 CPU。后来改成异步批量上报,才把开销降到 1% 以下。

4.3 数据库心跳表采集:最可靠的兜底方案

心跳表采集,是我个人最推崇的方式。为什么?因为它不依赖 CDC 组件的日志,也不需要在业务代码里埋点。它直接在源库和目标库各建一张心跳表,定期写入一条记录,然后对比时间戳。

说白了,心跳表就是模拟一条“假数据”在 CDC 链路里走一遍。如果这条假数据延迟了,那真数据大概率也延迟了。

4.3.1 心跳表的设计

心跳表的结构很简单,我一般这么设计:

CREATE TABLE cdc_heartbeat (
    id          BIGINT PRIMARY KEY,
    source_ts   TIMESTAMP(6),   -- 源库写入时间
    target_ts   TIMESTAMP(6),   -- 目标库写入时间
    status      VARCHAR(10),    -- 状态:PENDING / SUCCESS / FAILED
    create_time TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6)
);

采集程序每隔 1 秒(或 5 秒,看你的精度要求)向源库的心跳表写入一条记录。CDC 组件会同步这条记录到目标库。采集程序再对比 source_ts 和 target_ts,差值就是端到端延迟。

4.3.2 心跳表采集的优势

  • 独立性强:不依赖 CDC 组件的内部状态,即使组件挂了,心跳表也能告诉你“链路断了”。
  • 精度可控:写入频率越高,延迟监控的精度越高。我见过有人用 100 毫秒一次的心跳,精度相当高。
  • 易于对比:源库和目标库都有数据,可以交叉验证。

避坑指南:我曾经遇到过心跳表本身被 CDC 组件忽略的情况。原因是某些 CDC 组件有过滤规则,默认不同步系统表或特定模式的表。所以建心跳表时,一定要确认它被纳入了同步范围。

4.4 三种采集方式的对比

为了让你看得更清楚,我整理了一张对比表:

维度 日志采集 埋点采集 心跳表采集
数据来源 CDC 组件日志 业务代码/中间件 数据库心跳表
实时性 高 高 中(取决于写入频率)
精度 中(受日志精度限制) 高(可自定义) 高(可自定义)
侵入性 低 高 低
可靠性 中(日志可能丢失) 中(埋点代码可能出 bug) 高(独立于 CDC 组件)
适用场景 快速排查,历史回溯 精细化监控,链路分段 长期监控,兜底告警

4.5 整体架构图

下面这张图展示了三种采集方式在 CDC 链路中的位置和关系:

CDC 监控数据采集架构图 CDC 监控数据采集架构 源数据库 MySQL / PostgreSQL 心跳表写入 CDC 组件 Debezium / Canal 日志输出 目标数据库 Kafka / ClickHouse 心跳表对比 监控数据采集模块 日志采集 / 埋点采集 / 心跳表采集 时序数据库 / 监控平台 说明: 日志采集从 CDC 组件获取原始日志;埋点采集在链路关键节点插入监控代码;心跳表采集通过模拟数据对比源库和目标库的时间差。 三种方式互补,共同构成完整的监控数据采集体系。

4.6 我的建议:组合使用,各有侧重

讲了这么多,到底该怎么选?我的建议是:

  • 日常监控:用心跳表采集做基础监控,稳定可靠,不容易出幺蛾子。
  • 问题排查:用日志采集回溯历史数据,看看延迟是什么时候开始恶化的。
  • 性能优化:用埋点采集做精细化分析,定位具体是哪个环节慢了。