3、源头排查:数据库日志解析延迟

聊完了架构层面的延迟分类,咱们得把目光聚焦到最源头——数据库本身。很多 CDC 延迟,说白了就是数据库这边“卡住了”。日志没生成,或者生成了但解析不出来,下游再怎么优化也是白搭。

我个人习惯,排查延迟的第一步,永远是先看数据库。不看源头,后面全是瞎猜。这一节,咱们就掰开揉碎,讲讲数据库日志解析延迟、负载影响,还有那个让人头疼的大事务。

3.1 日志解析延迟:Binlog 与 Redo Log 的“翻译”瓶颈

CDC 工具读取数据库变更,本质上是在“读日志”。MySQL 是 Binlog,Oracle 是 Redo Log。但日志不是给人类看的,它是二进制格式。CDC 工具需要把它“翻译”成我们能理解的行变更。

这个翻译过程,就是解析延迟的根源之一。

核心观点: 日志解析不是免费的。它需要 CPU 资源,需要内存,还需要和数据库本身“抢” I/O。

为什么会解析慢?我总结了三个常见场景:

  • 日志格式不兼容: 比如 MySQL 的 Binlog 格式是 STATEMENT 或 MIXED,CDC 工具解析起来会比 ROW 格式更复杂,甚至可能出错。我在项目中遇到过,有人为了省空间用了 MIXED 格式,结果 Canal 解析时频繁报错,延迟直接飙到分钟级。
  • 解析器性能瓶颈: 老版本的 CDC 工具,或者单线程解析模式,面对高并发写入时,解析速度跟不上日志生成速度。说白了,就是“嘴小吃不下”。
  • 元数据频繁变更: 每次 DDL(比如加字段、改类型),CDC 工具都需要重新拉取表结构,和日志中的变更做映射。如果 DDL 很频繁,解析器会花大量时间在“对表结构”上,而不是真正解析数据。
日志类型 常见解析延迟原因 排查方向
MySQL Binlog 格式非 ROW、解析器单线程、DDL 频繁 检查 binlog_format、升级解析器版本、合并 DDL
Oracle Redo Log LogMiner 性能、归档日志切换、补全日志缺失 开启 supplemental logging、优化 LogMiner 配置

我的小技巧: 排查解析延迟时,我会先看 CDC 工具的“解析队列深度”。如果队列一直在增长,说明解析速度跟不上生产速度。这时候别急着加机器,先看看是不是日志格式或 DDL 的问题。

3.2 数据库负载:当“生产者”本身就很吃力

数据库不是专门为 CDC 服务的。它要处理业务查询、写入、索引维护、备份……如果数据库本身负载就很高,那日志生成的速度自然会受影响。

你想想看,一个 CPU 使用率长期 90% 以上的数据库,它还有多少余力去快速刷日志?

数据库负载对延迟的影响,主要体现在这几个方面:

  • CPU 争抢: 日志生成和解析都需要 CPU。如果业务查询把 CPU 吃满了,CDC 工具能分到的 CPU 时间片就少,解析自然变慢。
  • I/O 瓶颈: 日志是要写磁盘的。如果磁盘 I/O 已经被业务写入占满,日志刷盘就会排队。日志刷得慢,CDC 工具能读到的数据就少。
  • 锁竞争: 某些数据库在生成日志时,需要获取内部锁。如果业务有大查询长时间持有锁,日志生成也可能被阻塞。

曾经踩过的坑: 有一次,业务方在凌晨跑了一个全量报表,把数据库的 I/O 打满了。结果 Binlog 刷盘延迟从 1ms 涨到了 500ms,CDC 延迟直接爆表。从那以后,我建议所有核心业务库,都要给 CDC 工具预留独立的 I/O 带宽,或者至少做好限流。

怎么判断是不是数据库负载导致的延迟?我一般看三个指标:

  1. 数据库 CPU 使用率: 如果持续超过 80%,就要警惕了。
  2. 磁盘 I/O 等待时间(await): 如果超过 10ms,说明 I/O 有压力。
  3. 日志生成速率: 对比业务写入 TPS 和日志生成速率。如果 TPS 很高,但日志生成速率上不去,那大概率是数据库内部瓶颈。

3.3 大事务:延迟的“隐形杀手”

这是最容易被忽视,但影响最严重的问题。大事务,说白了就是一个事务里包含了大量数据变更。比如一次 UPDATE 影响 100 万行,或者一次 DELETE 删掉整个表。

为什么大事务会导致延迟?

因为日志是事务级别的。一个事务的所有变更,要么全部写入日志,要么全部不写。在事务提交之前,CDC 工具是看不到这些变更的。如果这个事务执行了 10 分钟,那这 10 分钟内的所有变更,对 CDC 来说就是“不可见”的。

一旦事务提交,CDC 工具会突然收到一个巨大的日志块。解析这个块需要大量 CPU 和内存,而且会阻塞后续日志的解析。结果就是:延迟瞬间飙升,然后慢慢恢复。

关键点: 大事务造成的延迟,不是线性的,而是“脉冲式”的。平时延迟很低,突然一下爆表,然后又降下来。这种波形,基本就是大事务的典型特征。

怎么排查大事务?我分享几个实战经验:

  • 看 Binlog 文件大小: 如果某个 Binlog 文件特别大(比如超过 1GB),而且生成时间很短,那里面很可能包含大事务。
  • 看 CDC 工具的“延迟曲线”: 如果延迟曲线是“尖刺状”,而不是“斜坡状”,优先怀疑大事务。
  • 查数据库当前事务: 在 MySQL 里,可以用 SELECT * FROM information_schema.INNODB_TRX 查看长时间未提交的事务。
-- 示例:查找执行时间超过 10 秒的事务
SELECT trx_id, trx_started, TIMESTAMPDIFF(SECOND, trx_started, NOW()) AS trx_duration
FROM information_schema.INNODB_TRX
WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 10;

避坑指南: 我曾经遇到一个案例,业务方在循环里逐条 INSERT,但没有开启批量提交。结果一个事务里插入了 50 万条数据,事务执行了 3 分钟。提交后,CDC 延迟直接涨了 5 分钟。解决方案很简单:开启批量提交,或者把大事务拆成多个小事务。

为了让你更直观地理解这三者的关系,我画了一张图:

源头延迟三大因素关联图 数据库 日志解析延迟 数据库负载 大事务 排查思路: 1. 先看延迟曲线:尖刺状 → 大事务;斜坡状 → 负载或解析瓶颈。 2. 再看数据库指标:CPU/I/O 高 → 负载问题;正常 → 检查日志格式和解析器。 3. 最后查大事务:用 SQL 查长时间未提交的事务,或分析 Binlog 文件大小。 解析队列堆积 CPU/I/O 飙升 延迟脉冲尖刺

嗯,源头排查这块,说白了就是盯紧数据库。日志解析慢,就优化解析器或改格式;数据库负载高,就限流或扩容;大事务,就拆小或改业务逻辑。这三板斧下去,大部分源头延迟都能解决。