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 埋点位置怎么选?
我一般会在以下四个位置埋点:
- 数据源端:记录 binlog 事件产生的时间戳。
- CDC 组件消费端:记录事件被拉取的时间。
- 转换/过滤环节:记录数据经过 ETL 处理的时间。
- 目标库写入端:记录数据成功写入的时间。
这四个点连起来,就能画出完整的延迟链路。哪一段慢了,一目了然。
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 链路中的位置和关系:
4.6 我的建议:组合使用,各有侧重
讲了这么多,到底该怎么选?我的建议是:
- 日常监控:用心跳表采集做基础监控,稳定可靠,不容易出幺蛾子。
- 问题排查:用日志采集回溯历史数据,看看延迟是什么时候开始恶化的。
- 性能优化:用埋点采集做精细化分析,定位具体是哪个环节慢了。