数据库同步实践指南:四类做法原理、失效场景与选型决策

举报
数据库小学妹 发表于 2026/09/22 16:12:21 2026/09/22
【摘要】 本文把四类数据库同步做法挨个拆开,触发器、时间戳、全表比对、日志解析(CDC),每类都讲机制、对源库的影响、什么时候会失效,配三张对比表和一套五个问题的选型决策,最后复盘一次 ODS 汇聚里列数与行数同时不一致的真实案例。

大家好,我是数据库小学妹👋我踩过的坑,你别再踩。

上周同事丢给我一个需求。要把交易库的数据,实时同步到分析平台去。老板只问了我一句话,数据库同步你打算怎么做。我当时的第一反应很朴素,建个触发器不就行了。三天后我就为这个念头买了单。

触发器把主库的写入拖慢了。批量导入的那批数据,还整个漏掉了。也是从那次开始,我把数据库同步的几种做法梳理了一遍。四类做法,各自的原理、代价和失效场景。我会按三段来讲:机制是什么,对源库什么影响,什么时候它会失效。你看完能自己判断,手上的项目该走哪条路。

数据库同步在解决什么问题,为什么它比想象中难

数据库同步,是把数据变更持续复制到另一个库。听起来像搬运。做起来更像一直追一个不停移动的靶子。推动它出现的场景,我觉得主要就三类。

第一类是要数据,但不想压生产库。报表、风控、大屏都直接查主库的话,OLTP 会被拖垮。第二类是要迁移,但不能停机。业务 7×24 在跑,窗口期几乎给不出来。第三类是要容灾。主库出问题,备库得顶上去,数据还不能缺。

源库在写,目标库也在写。网络会抖,表结构还会突然被改。一个能跑通的方案很容易找。能稳定跑三年的方案很少。后面这四类做法,本质都在回答同一个问题。怎么用尽可能小的代价,稳定拿到"到底变了什么"。

四类同步做法,先看一张对比表

我把常见的数据库同步方式整理成了一张表。判断一个方案好不好,我主要看几件事。怎么拿到变更,对源库影响多大。延迟高不高,抓不抓得到物理删除。接下来我逐条讲。

做法 怎么拿到变更 对源库影响 延迟量级 抓得到物理删除吗 异构友好度 落地复杂度
触发器 源表挂触发器,变更时直写同步表 高,写入放大 秒级 差,语法各不同
时间戳 表加更新列,轮询捞增量 中,看轮询频率 分钟级 不能
全表比对 定期全量扫描,比对差异 高,全表扫描 看比对周期 能,比对得出
日志解析(CDC) 读事务日志,解析已提交事务 亚秒级 中高

数据库同步四类做法对比

触发器方式:改哪写哪最直观,代价藏在源库上

比较直觉的方案,就是在源表上挂触发器。数据一变,顺手把变更写进同步表。MySQL 里的大致写法是这样。这段代码很短,看起来也没什么毛病。

DELIMITER $$
CREATE TRIGGER trg_user_ai
AFTER INSERT ON t_user
FOR EACH ROW
BEGIN
  INSERT INTO t_user_sync(id, name, op, sync_time)
  VALUES (NEW.id, NEW.name, 'I', NOW());
END$$
DELIMITER ;

写完当天就能跑通,这也是它容易骗人的地方。它有三笔代价,我挨个说。第一笔是写入放大。业务写一行,数据库实际要写两行。同步表还有索引要维护。写多读少的库上,这个放大很要命。

第二笔是 DDL。源表加个字段,触发器不会自动跟着变。你得记得同步改。漏一次,链路就开始错位,而且它不报错。

第三笔最隐蔽,批量导入会绕过触发器。有些批量加载路径为了性能,不走逐行触发。那批数据就静默丢了。我那次漏掉的正好是这一批。

那触发器适合什么场景?源表写入量不大,变更类型简单。DDL 你还盯得住。一旦超出这个范围,它就从帮手变成隐患。

时间戳方式:改动最小,却有躲不开的三个死角

时间戳的思路更朴素。表上加一个更新时间列,同步任务定期来捞增量。不用触发器,也不用改写入逻辑。它的好处是业务侧几乎不用动代码。

ALTER TABLE t_order
  ADD COLUMN last_updated DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3);

-- 同步侧每 30 秒拉一次
SELECT id, order_no, amount, last_updated
FROM   t_order
WHERE  last_updated > :last_max_time
ORDER  BY last_updated;

对源库的侵入看着最小。但它有三个死角,一个都躲不掉。死角一是物理删除抓不到。一行数据被 DELETE 了,时间戳列跟着没了。轮询根本看不见这条记录存在过,也就无从同步。这一条在选型时基本是一票否决。

死角二是同秒并发会漏单。如果只记到秒,同一秒里的多条变更会漏。得靠组合位点往上追。组合位点就是 (last_updated, id)。只取最大时间是不够的。

死角三强依赖业务加列。last_updated 得有人维护。业务代码忘了更新,链路就断。时区或者数据库时钟不一致,还会整段跳过。我不确定是不是每个团队都踩过第三条。但凡是上了年头的老系统,加列本身就是一场漫长的谈判。

全表比对:能做兜底校验,当不了同步主力

前面两类数据库同步做法都在记录变更。全表比对反着来,直接比两边现在长什么样。它的机制很简单。两张表按主键排序,逐行逐列比。找出差异,再补上。它不关心你是怎么改的,只看结果对不对。

代价也很直接。全表扫描要占大量 IO,基本只能放在业务低峰跑。表一大,一个比对周期可能横跨整个白天。业务就得一直等着。所以全表比对真正的定位不是同步,而是校验。它回答的是"现在两边一致吗"。而不是"刚才到底变了什么"。

校验真要落地,我后来还是交给了工具。手头用的是金仓的异构数据同步软件 Kingbase FlySync,简称 KFS。它的校验模块分了四种模式。差别主要落在"比什么"和"代价"上。

KFS 校验模式 比什么 代价
精简校验 只比两端表的条目数 快,但看不出字段差异
详细校验 逐行逐列比,差异可标出 慢,会占数据库资源
增量校验 只比指定事务号之后的增量 快,无需全量扫描
快照存量校验 基于快照比存量数据 用于存量数据兜底

官方最佳实践里还给了一条约束,我觉得挺实在。要校验的表,最好带主键或者唯一索引。没主键的话,全量校验性能会明显下降。表要是特别大,就开分片校验,把大表拆成多片并行比。

除了这四种,它还提供 MD5 模式。拿主键加其余列算摘要,再比对。性能比详细校验高,代价是不支持差异修复。校验出差异还能配邮件告警,不用一直盯着页面刷。同步和校验是两条独立的链路。校验跑起来,不该把同步本身拖慢。

日志解析(CDC):实时同步里,目前更稳的一条路

前三类数据库同步做法都在业务路径上加东西。日志解析反过来,去读数据库自己写的账本。所有主流数据库都会把变更写进事务日志。MySQL 是 binlog。Oracle 是 redo。PostgreSQL 是 WAL。

数据库写日志,本来是为了自己的崩溃恢复。同步工具只是顺手借读这份日志。它不改库,也不加表。所以它对源库的侵入,天然比触发器小得多。

但这里有个关键点很多人会踩,就是位点。数据库同步工具必须记住"我读到哪了"。这个位置就是位点,也是断点续传的地基。MySQL 看 binlog offset。Oracle 看 SCN。PostgreSQL 看 LSN。

位点记对了,断点才能成立。位点记错或者丢了,问题就大了。重启之后要么重复重放,要么静默跳过一截。这两种情况都很难查。

KFS 走的就是物理日志解析这条路线,架构分三段。采集、跟踪文件(KUFL)、加载,官方叫它一站式完成。采集模块守在源库侧,监控事务日志的变化。它只解析已提交的事务,中间活动和回滚操作自动忽略。这一步挡掉了不少脏数据,也减轻了基础架构的负载。

解析出来的变更,落成统一中间文件 KUFL。它采用加密数据格式,屏蔽了异构数据库之间的差异。源端或目标端中断时,KUFL 里还留着最新数据。系统恢复后接着加载,这就是断点续传的底子。

加载模块读 KUFL,再转成原生 SQL 应用过去。它按源库的提交顺序加载,保证事务一致性和引用完整性。位点这件事,它有个专门的换算工具。名字叫 replsntrans。能把断点信息翻成数据库里的日志序列号。还能告诉你日志点落在哪个文件。排查位点问题的时候,它比翻文档快。

# Oracle 环境
replsntrans ora:6913976033:6913976035

# Kingbase 环境
replsntrans kb:18044936568:18051565192

断点格式分两种。Oracle 侧是 ora:oldestSCN:commitSCN。Kingbase 侧是 kb:oldestLSN:commitLSN。前半段记的是最老位点,后半段记的是提交位点。排查"到底同步到哪了",比自己猜位点靠谱得多。这个工具在生产上救过我一次。

代价也得说清楚。日志解析要求源库开归档,还要开附加日志。这两项在 Oracle 上一般这么配。权限申请得走流程,建议提前准备。

-- 开启附加日志
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;

-- 建同步用户并授权
CREATE USER KFS_USER IDENTIFIED BY "******";
GRANT CREATE SESSION TO KFS_USER;
GRANT LOGMINING TO KFS_USER;
GRANT EXECUTE ON DBMS_LOGMNR TO KFS_USER;

一套权限申请流程要走下来,这算一次性时间成本。但换来的是业务侧几乎不用改代码。触发器那种活,每改一次表就得动一次。这个成本只付一次。所以我觉得值。

KFS 官方资料里给的能力口径是这样的。亚秒级同步延迟。1C2G 的最小环境能跑到 50GB/天。支持 30 余种数据源。广域网做 4 倍压缩,2M 带宽就能撑实时容灾。这些数字建议按你自己的环境实测,别直接照搬。

数据库同步方案怎么选,五个维度定路线

讲完四类,回到最初那个问题。手上的数据库同步项目到底该选哪条路。我一般会问五个问题。每个问题都卡着一类做法的软肋。

维度 如果答案是 结论
源库写入量大吗 直接排除触发器
需要抓到物理删除吗 需要 排除时间戳
延迟要求 亚秒级或秒级 只能走日志解析
能改业务代码吗 不能 排除触发器、时间戳
目标端是异构库吗 日志解析类产品值得进候选(KFS)

再补两条实践经验。数据量小、变更少、临时用一阵的场景,触发器和时间戳够用。要长期跑、要跨库异构、要对生产库友好,我选日志解析。全表比对不要单独当同步用,把它放到校验那个位置上。

在异构、实时、不停机这个格子里,KFS 值得进候选。它是对标 OGG 的国产异构数据同步软件。覆盖同城异地容灾、平滑迁移替换、数据集中共享分发。触发器要动源表,时间戳要加列,KFS 都不用碰。这也是我把它写进上面那张决策表的原因。

案例复盘:一次 ODS 汇聚,列数和行数同时不一致

我遇到过这样一个场景。数据要从源库汇聚到 ODS 中间层,再进数据中台。ODS 层做清洗的时候加了两列。一列是操作类型。一列是业务时间。操作类型那一列,是用来标记逻辑删除的。

问题就出在这里。源端的 DELETE,到目标端并没有真删。它只是把操作类型列改成了 Delete。那一行还在表里。于是两端同时对不上,列数不一致,行数也不一致。

传统的校验方案在这里直接失效。它的流程是全列读取、排序、逐行逐列比对。可两端表结构本身就不一样,比对从第一步就错位了。修复时按多、少、不一致分别处理。用 insert、delete、update 去补。可它接不上逻辑删除这条规则。

我一开始想的是手动写 SQL 推平。写到第二张表就放弃了。这类问题的正解,是让校验工具理解业务规则。而不是硬比。金仓那边的做法是标记列过滤,加上按条件修复。

先把逻辑删除列排除在比对范围外。再按条件决定补哪些行。从官方说明看,这种方式处理下的性能与正常校验修复持平。这个案例我想说的是,校验失败不一定是同步坏了。也可能是两端的业务规则本来就不对称。先把这个问清楚,再怀疑工具。不然容易误判。

数据库同步避坑清单:三条我交过学费的经验

坑一,先把"能不能抓到物理删除"确认清楚。用时间戳方案的话,这点半年后才会爆。那时候业务已经改了半年。再换方案,成本翻倍。

坑二,位点一定要能查、能换算。不要只信页面上那个"同步正常"的绿点。出事那一刻,你得能立刻答出"同步到哪个日志位置了"。答不出来,就只能靠猜。

坑三,批量导入的路径要单独验一遍。我那次漏数据,就是因为批量导入绕过了触发器。后来我们的做法很笨。凡是大批量写库,先停同步,导完再起。听着土,但从那以后再没丢过。

写在最后

回头看那句"建个触发器不就行了"。问题其实不在触发器身上。问题在我只看了能不能跑通,没看代价落在谁身上。这四类数据库同步做法里,日志解析的代价落在运维侧。业务侧几乎无感。

我选工具的时候会看三件事:对生产库的侵入有多大,断点续传靠不靠谱,校验能力完不完整。KFS 在这三块都有对应的能力,还配了可视化的统一管控平台。不想在业务代码里动刀的团队,省下的是长期维护成本。

数据库同步这件事,我现在的体会是没有通用解。有人要快,有人要稳。有人只是临时搬一次数据。先看清自己属于哪一种。

你们项目里的数据库同步是怎么做的?踩过触发器或者时间戳的坑吗?欢迎在评论区聊聊。你的经验,能让后面的人少走一段。

我是数据库小学妹,帮你少走弯路少踩坑,咱们下篇见👋

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。