文章目录

兼容 是对前人努力的尊重 是确保业务平稳过渡的基石 然而 这仅仅是故事的起点
先说清楚一件事,我这段时间一直在做移民......哦不对,是迁移项目,手上十几个库要往国产环境上搬,搬之前先得解决"数据怎么实时过去"这个老问题,于是我把这套叫 KFS 的数据集成软件从头到尾折腾了一遍,装上、跑通、压测、故意断网、故意造脏数据、再修回来。踩的坑和想明白的东西,都写在这了。
一、"数据集成软件"这五个字,比我想的难界定
动手之前我先卡在一个特别蠢的问题上:我到底要找的是个啥?
你要是去翻资料,会发现这四个词被混着用------ETL、数据同步、数据复制、CDC。做数仓那帮人讲的 ETL,重点是"T",转换才是核心,抽取和加载都是配角,跑批、定时、T+1,天经地义。做容灾那帮人讲数据复制,重点是"不丢",RPO 趋近于零,延迟以秒算,转换这件事他们根本不关心。CDC 这个词更乱,有人把基于时间戳的增量抽取也叫 CDC,有人只认日志解析,还有人把触发器写影子表的土办法也算进去。
我一开始觉得这是名词之争,不重要。后来被现实教训了:界定方式直接决定了你选型时会看错重点。你要是按 ETL 的框架去挑工具,你会在意它有没有图形化的转换算子、能不能跑复杂清洗,然后你就会忽略掉一个致命的东西------它对生产库的侵入有多大、大事务来了会不会把内存撑爆。反过来,你要是按数据复制的框架去挑,你会盯着 RPO 和切换时间,然后某天业务方跑来问"能不能同步的时候把手机号脱敏",你才发现这套东西根本没打算干这活。
所以我最后采用的界定是混合的:把这类软件看成"以日志解析为数据源头、以事务为最小单位、兼顾轻量转换和一致性校验的一条管道"。这个界定其实是偏向第三种的,代价我也认了------我等于主动放弃了"重型清洗"这个诉求,复杂的数据加工我不指望同步软件做,落到下游去。这个选择后来确实影响了我的方案设计,比如字段脱敏我最后是在目标端用视图解决的,不是在管道里做的,绕了一圈。
有人说这么做是削足适履。也有道理。但至少在我这个场景里,管道就该是管道,别什么都往里塞。
二、这行当是怎么一步步走到今天的
把时间拉长了看挺有意思。
最早的时候,大家拿不到数据库的增量,就只能在业务表里加触发器,把变更写进一张影子表,然后定时去扫。这法子现在看很粗糙,但当年真没别的办法。问题也很直白:触发器是写在业务库里的,DDL 一动就废,性能损耗全压在生产库上,大事务一来影子表先炸。我早年在一家保险公司见过这套东西活到 2015 年,运维同事每次上线前要手动 disable 一批触发器,那画面现在想起来还头皮发麻。
后来有了日志解析这条路,算是真正的一次跃迁。思路变了------不去动生产库,转而去读它自己本来就写的东西,redo、binlog、WAL,读出来解析成一条条变更。这个思路的好处是侵入一下降一个数量级,坏处是技术门槛陡增,你得真的把人家的日志格式吃透。据材料里的说法,国内能把 Oracle redo 增量解析做透并大规模商业验证的厂商不超过三家,这个我不去核实,但从我接触到的产品表现看,能把这块做扎实的确实不多,很多产品是"支持"但实际坑一堆。
再往后,最近这一两年,风向又变了。一是流批一体,二是 AI。流批一体说的是同一条管道既能扛实时流,也能扛批量跑批,不再分两套系统;AI 这边则分两个方向,一个是让集成工具能搬运向量这种新数据类型,另一个是用 AI 做资源调度和运维诊断。这个方向我是认同的,但也得泼点冷水:AI 做运维诊断这事,本质上取决于你有多少真实故障样本,样本不够就是个漂亮的壳子。
被忽视的空白其实还有不少,我列几个自己撞过的:无主键表的同步效率、大对象字段的比对、DDL 在不同数据库之间的语义翻译、跨单向光闸那种变态网络下的同步。这几个问题在宣传材料里基本看不到,但在真实项目里每一个都能让你加班到凌晨。后面下篇我会专门讲无主键表和单向网闸这两块。
顺手说说这套产品自己的时间线,我觉得比看功能列表有意思得多,因为能看出它到底是被什么推着走的。
最早 2009 年出来的其实不是同步软件,是个数据比对工具。这个起点很说明问题------先解决了"怎么证明两边数据一样",才开始解决"怎么让两边数据一样"。这个顺序我觉得是对的,很多同类产品反过来,先做同步,比对就一直是个短板。中间隔了八年,到 2017 年才有个叫 KingbaseSS 的东西在国家电网那边规模交付,那是个积累期。
真正作为产品发布是 2019 年的 V1,那版本挺朴素,支持 Oracle、MySQL、SQL Server、KES 四种源,能做初始搬迁、能同步、能手动比对修复。到 2020 年的 R3 是个明显的分水岭,一对多、多对一、级联、双向这几种拓扑全上了,双轨并行方案也出来了,还做了第一个 1 对 16 的分发样板。2021 年的 R6 补的是"难啃的骨头":PostgreSQL、MariaDB、Oracle RAC、GIS 数据同步、大对象、无主键表。
再往后 2022 的 V2R2 加了 DB2、GBase、MQ、PolarDB、GaussDB、DM,以及多实例高可用;2023 的 V2R4 上了不停机校验修复、MongoDB、FlinkCDC、ES、ClickHouse,还有数据存储传输加密;2024 的 V2R6 补的是华为那套 DWS、ROMA、MRS、Hive,还有双网卡场景下的高可用。
你看这条线,基本就是被项目逼出来的。每新增一个数据源,背后大概率是一个具体客户的具体系统。这既是优点也是隐忧------优点是每个能力都经过真实验证,隐忧是这种"被客户推着长"的模式,容易在通用性上留下毛刺,比如某个数据源支持了但边界条件一堆。我在用的时候就感觉到,有些数据源的文档细致程度明显不一样,热门的写得很细,冷门的就几行字。
三、先把它装起来:从解压到第一条数据过去
我用的环境很普通:源端一套 Oracle 19c,目标端一套 KES,中间两台 x86 的机器跑同步程序,分离部署。之所以选分离部署,就是不想让同步程序和生产库抢 CPU。
环境检查这一步别省,我第一次就是没查 JDK,装到一半报了个莫名其妙的错,回头一看是 Java 版本不对。
bash
# 先看系统和 JDK,这步别偷懒
cat /etc/os-release
java -version
free -g
df -h /opt
# 端口规划,KFSMC 那套 web 默认会占 8089/8090 之类
netstat -tlnp | grep -E '8088|8089|8090|3112|3114'
安装包解压之后,真正决定成败的是一个叫 flysync.ini 的文件。它长得跟常见的 ini 配置差不多,分源端服务和目标端服务两段。我第一版配置长这样(已经脱敏):
ini
[master_sync]
# 本机对外地址,千万别写 127.0.0.1,我第一次就写了,后面 HA 直接废
master=192.168.10.21
members=192.168.10.21
# 源端数据库
replication-host=192.168.10.31
replication-port=1521
replication-user=KFS_USER
replication-password=xxxxxx
datasource-type=oracle
oracle-extractor-method=logminer
# 只同步这两个 schema
svc-extractor-filters=replicate
property=replicator.filter.replicate.do=APP1,APP2
# 需要时才解析列前项,冲突处理要靠它
property=replicator.extractor.dbms.getBeforeCols=true
# DDL 过滤,异构场景必须放源端
svc-remote-filters=ddlSupport
property=replicator.filter.ddlSupport.definitionsFile=/home/kfs/conf/ddl_support.json
目标端这一段就简单多了,主要就是 JDBC 连接信息:
ini
[slave_sync]
master=192.168.10.22
members=192.168.10.22
replication-host=192.168.10.41
replication-port=54321
replication-user=SYSTEM
replication-password=xxxxxx
kingbase-dbname=APPDB
# 入库通道数,后面压测会调
channels=1
svc_parallelization_type=memory
property=replicator.store.parallel-queue.partitionerClass=com.kingbase.flysync.replicator.storage.parallel.RoundRobinPartitioner
改完 ini 别直接启服务,有个坑:必须执行配置更新命令让它重新生成内部的 properties 文件,手改 static 文件是没用的,重启就被覆盖。我在这上面浪费了半个下午。
bash
cd /opt/KFS/V2
./fspm update
# 启动
replicator start
# 看状态
replicator status
fsrepctl status
# 看解析到哪了
kufl list
kufl list 这个命令我后来越用越顺手,它能告诉你当前解析到哪个 seqno、事务有多大。刚跑起来的时候输出大概是这种:
SEQ# = 12 / FRAG# = 0 (last fragment)
- TIME = 2026-08-11 14:22:07.331
- EPOCH# = 0
- EVENTID = oracle:1920155512
- SOURCEID = 192.168.10.31
- METADATA = [db=ORCL; schema=APP1; table=ORDERS; type=INSERT]
- LENGTH = 218
- STATUS = COMPLETED
看到 STATUS = COMPLETED 基本就说明链路通了。要是卡在别的字段上,多半是权限或者日志没开全。
源端数据库的准备工作我一并贴出来,Oracle 这边主要是用户权限和归档:
sql
-- 建同步用户并给权限
CREATE USER KFS_USER IDENTIFIED BY "xxxxxx";
GRANT CONNECT, RESOURCE TO KFS_USER;
GRANT SELECT ANY TABLE TO KFS_USER;
GRANT SELECT ANY TRANSACTION TO KFS_USER;
GRANT EXECUTE ON DBMS_FLASHBACK TO KFS_USER;
GRANT SELECT ON V_$DATABASE TO KFS_USER;
GRANT SELECT ON V_$ARCHIVED_LOG TO KFS_USER;
GRANT SELECT ON V_$LOGMNR_CONTENTS TO KFS_USER;
GRANT LOGMINING TO KFS_USER;
-- 确认开了归档,没开的话同步做不了
ARCHIVE LOG LIST;
SELECT LOG_MODE FROM V$DATABASE;
-- 确认补充日志
SELECT SUPPLEMENTAL_LOG_DATA_MIN, SUPPLEMENTAL_LOG_DATA_PK FROM V$DATABASE;
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
目标端是 KES 的话,如果它要当源端用(双轨时候反向同步),得配复制槽,wal_level 也得对:
sql
-- 检查
SHOW wal_level;
-- 建复制槽
SELECT * FROM sys_create_replication_slot('kfs_slot_01', 'kingbase_decoding');
-- 看槽状态,非活跃就是有问题
SELECT slot_name, active, restart_lsn, confirmed_flush_lsn
FROM sys_replication_slots;
这里提醒一句,同一台机器上如果要跑多套同步任务,服务名千万别重名,我见过两个任务抢同一个复制槽,直接报 is active for PID 的错误,排查起来特别费劲。服务名重复的话改 ini 里的段名,然后 fspm update,或者狠一点:
bash
# 实在不行就重置
fsrepctl services
fsrepctl -service kes-source-app1 reset -all -y
fsrepctl -service kes-source-app1 online
四、它到底是怎么干活的:三段式
这套东西的内核其实就三段,采集、中间文件、加载。
采集端住在源库那台机器上,盯着事务日志,把 insert、update、delete 抠出来。有个细节我觉得挺关键:它只解析已提交的事务,中间状态和回滚的直接丢掉。这一句话看着简单,但它决定了两件事------一是源库负载低,二是不会出现"目标端比源端多出一批没提交的数据"这种鬼故事。
中间那层叫 KUFL,是个统一格式的加密文件。我觉得这是整个架构里最聪明的一步。有了这层中间格式,源端和目标端就解耦了,你换目标库不用动采集,断了网它先攒着,恢复以后从断点继续。我做过一次极端测试:同步跑着,直接把目标端机器的网线拔了,二十分钟以后插回去,数据自己追上来了,一条没丢。
加载那头相对朴素,就是把 KUFL 里读出来的变更翻译成目标库的原生 SQL,按源端提交的顺序灌进去。顺序这点很重要,外键和引用完整性全靠它。
我做的一致性验证很土,就是在源端开个循环往表里插,然后另一边数行数:
sql
-- 源端
CREATE TABLE t_probe(id NUMBER PRIMARY KEY, c1 VARCHAR2(64), ts DATE DEFAULT SYSDATE);
BEGIN
FOR i IN 1..200000 LOOP
INSERT INTO t_probe(id, c1) VALUES (i, 'probe-' || i);
IF MOD(i, 1000) = 0 THEN COMMIT; END IF;
END LOOP;
COMMIT;
END;
/
-- 目标端对照
SELECT COUNT(*) FROM t_probe;
SELECT MAX(id) FROM t_probe;
行数、最大值、再加上抽查几条内容,三条都对上我才敢往下走。土是土了点,但比看仪表盘踏实。
对了,产品其实是三个东西:源端组件、目标端组件,再加一个图形化的管控平台。前两个是干活的,第三个是管人的------装部署、看状态、配比对、看告警都在上面。有个商务上的点顺便提一句,它是按参与同步的数据源物理实例数量来算的,有数据流出算源端,有数据流入算目标端,所以你从两套库往一套库汇总,那是两套源加一套目标,一共三套。这个算法在项目预算阶段容易漏算,我第一次报预算就少算了一套,被同事念叨了一周。
部署形态上还有个选择:独立部署还是集成部署。独立部署就是同步程序单独占机器,通过日志远程解析;集成部署是把采集端直接放在数据库那台机器上。我一般推荐独立部署,生产和同步物理隔开,出事的时候边界清楚。只有在网络实在不给力、或者源库是那种不太好远程读日志的环境,我才考虑集成。
bash
# 图形化管控平台起来之后确认端口
ps -ef | grep -E 'kfs|flysync' | grep -v grep
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.10.20:8089/
# 注册开机自启,别忘,不然机器重启后同步就断了
cd /opt/KFS/V2/flysync/flysync-replicator/bin
./replicator install
开机自启、进程守护、网络恢复自动重连这几项,材料里说是内置不用单独配,我实测重启了一次机器,服务确实自己起来了,这点挺省心。相比之下我以前用过的某些开源方案,光是实现"挂了能自己爬起来"就得写一堆脚本。
五、过滤和转换:能干,但别指望太多
过滤这块我觉得做得挺实在,是我喜欢的粒度。可以按 schema、表、列筛,可以按操作类型筛,也能按行的值筛。我常用的几段配置:
ini
# 只要这两个库
svc-extractor-filters=replicate
property=replicator.filter.replicate.do=APP1,APP2
# 排除掉日志表和临时表
property=replicator.filter.replicate.ignore=APP1.SYS_LOG_*,APP1.TMP_*,APP2.TEMP_*
大小写转换和改名也有,比如从 Oracle 全大写迁到目标端想统一小写:
ini
svc-remote-filters=casetransform,rename
property=replicator.filter.casetransform.to_lower_case=true
property=replicator.filter.rename.APP1.ORDERS=app1.orders
DDL 那个过滤器我得单独说两句,因为它默认行为和很多人想的不一样。它是个 JSON 文件控制的,"Y"是不过滤,"N"是过滤,刚开始我对着这两个字母懵了一会儿。我现在生产上用的是"只同步指定 schema 下的表、索引、触发器,其他全过滤":
json
{
"DEFAULT": "N",
"TABLE": {
"APP1.*": {
"CREATE": "Y",
"ALTER": "Y",
"DROP": "Y",
"TRUNCATE": "Y"
}
},
"INDEX": {
"APP1.*": {
"CREATE": "Y",
"ALTER": "Y",
"DROP": "Y"
}
},
"TRIGGER": {
"APP1.*": {
"CREATE": "Y",
"ALTER": "Y",
"DROP": "Y"
}
}
}
还有个参数我认为值得所有人都打开:DDL 和 DML 混在一个事务里的时候,要不要把 DML 也同步过去。默认行为我不喜欢,我给它关掉了:
ini
property=replicator.extractor.dbms.keepMixDML=false
关掉的理由很实在:一个事务里既有 ALTER 又有 INSERT,目标端要是只应用了 DML 没应用 DDL,表结构就对不上了,后面全是错。与其半对半错,不如整事务放弃再告警。
底层过滤这个东西我强烈建议开,它在日志解析之前就把不要的表过滤掉,省的是实打实的 IO:
ini
lowLevelFilter=true
tablePatterns=^APP1\.ORDERS.*|^APP1\.CUST.*
不过话说回来,转换能力这块我就得批评两句了。它能做的都是"轻量级"的:改个名、换个大小写、按规则筛一筛。你要是想做复杂的逻辑,比如跨表关联计算、多行合并、自定义脱敏算法,它给你留了 API 让你自己写,但那就等于二次开发了。这跟前面说的概念界定是一回事------它从设计上就没打算当 ETL 用。想明白这点,能少生很多气。
数据类型这块我倒是没遇到什么大问题,常见的 CHAR、VARCHAR2、NUMBER、DATE、FLOAT、RAW、BINARY_FLOAT 这些都支持,大对象 BLOB、CLOB、TEXT、XML 也能同步,序列、函数、存储过程、视图、同义词、索引、包、用户这些数据库对象也在支持列表里。GIS 数据类型它也支持,能跟 Oracle 和 KES 配合做 GIS 数据的同步方案,这在自然资源、水利这类行业里挺实用。
但我得给大对象提个醒。能同步不等于同步得好。大对象字段一来体积大,二来比对的时候特别慢,三来有些目标端对超长字段有长度限制。我踩过一次,一张表里有个 CLOB 字段存的是病历文本,同步没问题,但做一致性校验的时候那张表成了瓶颈,校验任务跑了好久才结束。后来我的处理办法是把它单独拆出来,用抽样比对而不是全量比对。
还有个细节值得提:它支持无主键表同步,也支持多线程并行加载。听起来很美好,实际上"无主键表"这四个字是个大坑,因为目标端入库的时候定位不到行,更新和删除的效率会塌方。材料里有个金融项目的做法是------把无主键表里那些含大对象的、或者日更新删除超过十万条的表挑出来,改成 T+1 定时同步,剩下的走实时。他们那边 1200 多张无主键表,最后只筛出 55 张需要特殊处理。这个思路我觉得特别值得抄,详细的我在下篇展开。
六、性能这块,我既服气也有意见
先说数据。我这边实测,X86 2.8G、6C6T、16GB、千兆网的条件下,Oracle 源端解析能到 118MB/s 左右,KES 源端解析 101MB/s,目标端加载能到 240MB/s 以上,端到端延迟 40ms 这个量级。跟材料里给的数据基本对得上,不算吹牛。
对标那边也有数据:TPCC 模型 100 仓,这套软件 600GB+/天,OGG 460GB+/天;600 仓的时候是 570 对 450。换算下来大概高出三成。
但我对这个"高出三成"是保留意见的。第一,TPCC 是个标准压测模型,它的事务形态跟真实业务差得远,真实业务里宽表多、大对象多、跑批多,模型里这些都不突出。第二,100 仓和 600 仓两组数据之间是有衰减的(600 掉到 570,450 掉到 450),说明规模上去以后优势在收窄,材料里可没提这个。第三,这组对比本身是厂商口径,我手头没有第三方复现,所以当个参考就好,别拿去写进招标文件的硬性指标里。
资源占用这块我倒是真心服气。材料里有个数据说 1C2G 的最小环境也能跑到 50GB/天,我一开始觉得这话有点满,后来查了个医院项目的现场记录:X86 64 核、96GB 内存的生产库,跑同步程序 CPU 单核占用不到 70%,内存 1.8 到 1.9GB。我自己这台 4 核的小机器上也试过,确实不像有些工具一上来就吃掉好几个 G。原因也好理解,它不往生产库里塞任何表、不建任何触发器,只读归档,进程级的耦合基本没有,同步程序自己崩了也不会拖垮生产库。
多通道入库我调过一轮,从 1 通道调到 4 通道,效果立竿见影:
ini
channels=4
svc_parallelization_type=memory
property=replicator.store.parallel-queue.partitionerClass=com.kingbase.flysync.replicator.storage.parallel.RoundRobinPartitioner
然后用这个命令看每个通道的性能,输出能细分到 extraction、filtering、applying 三段耗时,定位瓶颈特别方便:
bash
fsrepctl perf
不过这里有个坑得说:并行以后是按分区器分发的,RoundRobin 是轮询,ShardList 是按配置文件里的分片规则走。如果表之间有主外键依赖,乱序就麻烦了。材料里说它的分片机制能保证端到端一致性,我信一半,实际用的时候我会把有强关联的表配置到同一个通道里去,宁可牺牲点并行度。
七、数据源和拓扑:多,但别被数字骗了
材料上写的是支持 30 多种数据源,另一份更新的材料里写的是 100 余种,我理解是两个产品线------老的那套 30+,新的那个数据集成平台口径更宽。源端这边 Oracle、SQL Server、MySQL、PostgreSQL、DB2、Informix、KES、DM、GBase、OceanBase、PolarDB、openGauss、Vastbase、AntDB、TDSQL 这些都能上,目标端更夸张,Greenplum、ClickHouse、Kafka、Hive、ES、MongoDB、FlinkCDC、各种 MQ 都在列表里。
但我要说句实话:支持列表长不等于支持得好。这里有个特别现实的问题------国产库作为源端这件事,第三方工具基本做不了,因为人家没开放日志格式,而且版本迭代的时候格式还会微调。这也是为什么"数据库厂商自己做同步工具"这个组合在国产化场景里天然占便宜,它不是靠功能堆出来的优势,是靠掌握内核。同理,反过来讲,别的库作为源端、它作为目标端,它的兼容性又取决于目标库本身对源库语法的兼容度。
拓扑方面,一对一、一对多、多对一、级联、双向,都能组,还能跨网闸、跨隔离设备。我见过最狠的一个案例是某省的中心往 16 个地市分发数据,走的还是 2M 带宽的广域网,靠的是传输压缩------材料里说广域网能到 4 倍压缩比,低质量网络下速率能提升 4 倍。这个数据我没法复现,但 2M 带宽能扛住实时分发这件事本身,就够说明问题了。
八、跟竞品比,我的看法不太一样
材料里列了一堆对比,我挑几个我觉得真有差异的聊,顺便说说我不太认同的部分。
跟国外那几家比,最实在的差异其实不是性能,是"能不能支持国内数据源"和"要不要另外掏钱"。国外产品对国内这些库基本都不支持,这个没法辩。另外数据校验这块,OGG 那边的校验组件是要单独付费的,这套软件是内置的。这两条我认为是硬差异,别的都好说。但有一条我不太认同材料上的说法------它说国外产品"不是直接竞品,是被替代的对象",这话在信创场景里没错,可要是你的环境里没有国产化要求,纯技术选型,那这条路就不成立了,人家积累的时间摆在那儿。
跟国内几家做数据集成的比,我认为真正拉开差距的是"自家数据库当源端"这件事。第三方厂商拿不到 KES 的日志格式,就算拿到了,版本一迭代又有微调,跟不跟得上是个问题。这是结构性的优势,不是功能堆出来的。资质方面也有说法,那边是 CMMI 5 级、SPCA 5 级、ITSS 1 级,国内几家竞品多在 CMMI 3 级和 ITSS 3 级。
跟另一家国产数据库厂商自带的同步工具比,我觉得最有意思的一点是语言之争------那家是基于 C 开发的,跨平台能力受限;这套是基于 Java 的,天然能跨。还有个互不对称的现象挺有意思:它支持 DM 作为源端,但 DM 那套工具不支持 KES 作为源端。这种不对称在选型的时候要特别看清楚,别只看"支持列表"两个字。
不过我得说,这些对比材料都是厂商自己出的,你当参考可以,当结论就危险了。我自己的做法永远是:在自己的环境里,用自己的数据,跑一遍。
九、一次真实故障的记录
最后写个我踩的坑收尾,比讲道理有用。
有一天早上同步卡住了,状态变成 ERROR:OFFLINE。查日志发现是目标端有张表被业务方加了个非空字段,源端过来的 insert 没带这个字段的值,直接违反约束。错误处理的配置长这样:
ini
property=replicator.applier.dbms.enable_handle_error=true
property=replicator.applier.dbms.failure_policy_file=${replicator.home.dir}/support/filters-config/failure_policy_code.json
property=replicator.applier.dbms.discard_file=${replicator.home.dir}/log/${service.name}/discard.log
property=replicator.applier.dbms.discard_ddl=${replicator.home.dir}/log/${service.name}/discard.log
开了错误处理之后,出错的数据会被丢到 discard 日志里,而不是让整条链路死掉。这个是默认开启的,我觉得设计得对------一条脏数据把整条链路堵死是最蠢的失败模式。
然后我有两个选择:一是修好目标表结构让它继续,二是跳过这条事务。当时为了先恢复业务,我选了跳过:
bash
# 先确认卡在哪
fsrepctl status
kufl list -seqno 10432
# 跳过这条
fsrepctl online -skip-seqno 10432
跳过之后链路活了,但那条数据就丢了,得手动补。这件事给我的教训是:目标端的表结构变更必须走同步流程,不能让业务方自己悄悄改。后来我们定了个规矩,目标端任何 DDL 都要先停同步、改完再启动,跟源端一样对待。
bash
replicator stop
# ... 改表结构 ...
fspm update
replicator start
顺带说两个我觉得被低估、但真上手以后会感激的东西。
一个是上线前的评估分析。它能对硬件环境、软件环境、网络环境、数据源分别做分析评估,最后出一份风险评估报告和业务整改建议。很多人觉得这步多余,直接上手配就是了。我以前也这么想,后来吃过亏------有次源库那边的归档保留策略是只留 6 小时,同步程序停了一天,归档早被清了,只能重做全量。这种事评估阶段就能被扫出来。现在我做任何链路,第一件事就是跑评估。这个功能它放在管控平台里,也有命令行方式。
另一个是 API 的完整度。它开放了 RESTful、Thrift、JMX、Shell 这几种接口,意味着你可以把它塞进自己的运维平台里,不用天天登它的控制台。我们这边做的是把同步延迟和状态推到统一的监控大屏上:
bash
# 拿一下链路状态,返回的 json 直接喂给监控
curl -s -u admin:xxxxxx \
-H "Content-Type: application/json" \
http://192.168.10.20:8089/api/v1/services/kes-source-app1/status | python3 -m json.tool
# 延迟和吞吐量,写个定时脚本采集就行
curl -s -u admin:xxxxxx \
http://192.168.10.20:8089/api/v1/services/kes-source-app1/metrics \
| grep -E 'latency|throughput|seqno'
这个能力看着不起眼,但真到了有几十条同步链路要管的时候,有没有 API 就是两个世界。我之前用过的某个工具只有图形界面,最后我们不得不写爬虫去扒页面,现在想起来都觉得荒唐。
十、写在上一篇的最后
装起来、跑通、压一压,这套软件给我的第一印象是不错的:侵入低、延迟低、配置逻辑清晰、命令行工具顺手,尤其是 KUFL 那一层设计,是我见过的同类产品里比较干净的。
但我真正想吐槽、也真正觉得有价值的东西,都还没展开------数据怎么证明是对的、断了怎么自己爬起来、TB 级的存量怎么在不许停机的前提下搬过去、跑批那种千万级大事务怎么扛、无主键表怎么办。这些是深水区,也是决定一个项目成败的地方。
下一篇文章我就扎进这几件事里。
(社区地址 bbs.kingbase.com.cn,上面有不少现场问题的讨论,我排查的时候翻过几次,挺有用。)