数据集成软件怎么选、怎么用:从 KFS 的建表、增删改查到一致性校验全流程

建议阅读对象:DBA、运维工程师、国产化迁移项目负责人、IT软件工程师


一、先把现场摆出来

去年冬天接了一个活儿,客户是省级的账务系统。老库是 Oracle 11g,跑在小型机上,单表最大的那张流水表 8 亿行。新库是金仓数据库 KingbaseES V9,两台物理机做同城双中心。

需求听起来不复杂:数据搬过去,业务切过去。

真正麻烦的是约束条件------停机窗口总共给了 4 个小时。历史数据 40TB 上下,光网络传输的物理下限就摆在那儿,靠"停机导出再导入"这条路根本走不通。客户 DBA 老张当时说了一句话我印象很深:这活儿要么别停业务,要么就别接。

后来方案定下来,用的是电科金仓的异构数据同步软件 Kingbase FlySync(下面简称 KFS)。全量搬迁和增量追平分开做,全量在业务跑着的时候搬,增量靠日志解析实时追,等两边位点追平了再切,切完如果发现问题还能切回来。

这套打法不是什么新鲜东西,金融和政务圈子里这几年已经很常见了。但真正落到操作层面,从我个人的经验看,坑比想象的多------尤其是表结构怎么建、增删改查跑下去之后两端到底一不一样这两件事,很多材料都讲得很轻。

这篇就把这条链路从头走一遍,配置、建表、增删改查、校验修复,代码和命令都贴出来。


二、KFS 是什么,以及它不是什么

先把最容易搞混的一点讲清楚:KFS 不是数据库。

它是一个数据集成软件,位置在数据库之上,干的事情是把数据从 A 搬到 B,同时保证 B 和 A 长得一样。它不存业务数据,不接管连接,也不需要你把应用改成连它。

原理上,KFS 走的是增量日志解析这条路:直接读源端数据库的物理日志,把里面的变更事件抓出来,解析成统一格式,再在目标端还原成原生的 SQL 语句执行。因为读的是日志文件而不是查表,所以对源端的侵入很小------不需要改应用、不需要加触发器、不需要在主键上挂额外字段。

几个能拿出来说的硬指标:

  • 资源要求低。官方给的参考是 1C2G 的最小配置下,同步能力大约 50GB/天。这个数字我第一次看到时也怀疑过,但考虑到它是日志解析而非全表扫描,逻辑上说得通。
  • 延迟。亚秒级。弱网环境下(比如跨地域专线)官方宣传能稳定在 50ms 以内。
  • 数据源覆盖。源端支持 Oracle、SQL Server、MySQL/MariaDB、KingbaseES、DB2、Informix、达梦、OceanBase、TDSQL、PolarDB、Vastbase、磐维 DB、AntDB 等主流库,以及 Kafka、RabbitMQ、RocketMQ 这类消息队列;目标端在这基础上再加 ClickHouse、GBase 8a、Greenplum、ElasticSearch、MongoDB、Hive、Hadoop 等分析型存储。算下来 30 余种,异构互转基本够用。
  • 拓扑。一对一、一对多、多对一、级联、双向,都能配。
  • 代码自主率 100%,产品已经发布到 V2.0 以上,配套的技术白皮书也迭代到 V3.7 了。

我特别想强调最后一条。在国内做国产化替换,这条比性能数字重要得多------它决定了这东西能不能进那些有安全审查要求的机房。


三、把同步链路拆开看

理解了内部结构,后面配参数和排错会轻松很多。KFS 的同步链路是流水线式的,四段:

bash 复制代码
┌────────────┐   ┌───────────┐   ┌─────────────┐   ┌──────────────┐
│ Extractor  │──▶│  Filter   │──▶│ Partitioner │──▶│ Applier × N  │
│  采集变更   │   │ 过滤·转换 │    │  路由到通道 │    │ 每通道独立    │
│  事件      │   │           │   │             │   │ 线程 + 连接   │
└────────────┘   └───────────┘   └─────────────┘   └───────────

Extractor 读日志抓变更。Oracle 走 Redo 解析,KingbaseES 走物理日志解析,MySQL 走 Binlog。抓出来的是一条条 DML 事件,不是整表快照。

Filter 做过滤和转换。最常用的就是表级过滤------你只关心订单相关的几张表,就在这儿把别的过滤掉;它还支持正则表达式匹配对象名,比如 order_* 一行就搞定。

Partitioner 是个容易被忽略但很关键的角色。它把事件分配到多个通道里并行处理。这里有个必须守住的红线:同一张表的所有变更必须走同一个通道,不然同一行的 INSERT 和 UPDATE 被分到两个通道、UPDATE 先执行,数据就乱了。KFS 的最终方案是"表亲和性 + 事务拆分"------大事务按表拆成子事务分发到不同通道并行跑,但单张表内部保持有序。DDL 则被固定在通道 0 执行,避免和 DML 抢元数据。这个细节后面讲坑的时候还会遇到。

Applier 负责落到目标端。每个通道一条独立线程加一条独立连接,把统一格式的事件还原成目标端数据库自己的 SQL 语法再执行。

KUFL:那个统一的中间格式

Extractor 抓到的数据不会直接往目标端推,中间要经过一个落盘环节------KUFL(Kingbase Unified Format Log),金仓自己定义的一种统一日志格式,数据是加密存储的。

它的价值在于解耦。不管源端是 Oracle 的 Redo 还是 MySQL 的 Binlog,进了 KUFL 就是同一种东西,后面的 Filter、Partitioner、Applier 完全不用关心源端是什么库。而且这些文件在两端断掉的时候还留着中断时刻之前的所有数据,恢复之后直接从这里往下读,不用回头找源端要------这就是断点续传的物理基础。

bash 复制代码
$ ls -la /home/flysync/kfs/data/kufl/
-rw-r--r-- 1 flysync flysync  256M   8月 15 10:23  kufl_000001.log
-rw-r--r-- 1 flysync flysync  512M   8月 15 14:47  kufl_000002.log
-rw-r--r-- 1 flysync flysync  128M   8月 15 18:05  kufl_000003.log

kufl 是个命令行工具,可以直接查看里面的内容,调试的时候几乎是唯一的抓手:

bash 复制代码
# 查看当前服务解析出来的 KUFL 记录
kufl list

# 指定服务名查看(Oracle 源端服务名为 oracle11g 时)
kufl -service oracle11g 

目标端为什么"追得上"

经常有人问:源端几百个连接并发写,你一个同步工具在目标端逐条回放,怎么可能追得上?

答案是它没逐条回放。KFS 在入库这层做了不少优化,几个我觉得值得单独说:

批量提交。逐条执行 SQL,每条都是一次网络往返;跨地域链路 RTT 10ms 的话,6 条 SQL 就是 60ms,打包成一次提交就只要 10ms。不是什么高深技巧,但省下来的延迟实打实。

小事务合并。一个事务里跨 10 张表乱序 INSERT,如果按源端顺序执行,每切一次表就要重新 prepare 一次,而每次 prepare 数据库都要做词法分析、语法解析、生成执行计划,纯 CPU 浪费。KFS 先把同一个表的操作归到一起,按表排序再统一处理,每张表只 prepare 一次。有人实测过 30 个事务、每个事务 20 条记录、跨 10 张表的场景,prepare 次数从两百多次降到三十多次,回放耗时差不多减半。

SQL 模板缓存。Applier 层维护一个大小 500 的模板缓存,相同模板的语句只解析一次,后面直接复用编译好的 PreparedStatement。

再加上 Buffer Flush 策略------攒够 N 条或者每隔 T 毫秒必须刷一次,这两个参数就是吞吐和实时性之间的旋钮。追求吞吐就把 batch size 调大,追求实时就把 flush 间隔调短。没有万能值,得按业务容忍度试。

断点续传靠什么

目标端有一张内部位点表 trep_commit_seqno,每个通道一行,记录该通道处理到哪儿了:

bash 复制代码
task_id | seqno | fragno | last_frag | wait_seqnos
   0    |  100  |   2    |   true    | 10|100-2|98-0,99-1|97-3
   1    |   99  |   1    |   true    | 10|100-2|98-0,99-1|97-3
   2    |   97  |   3    |   true    | 10|100-2|98-0,99-1|9

恢复时分三步走:取所有通道位点的最小值 (97)当安全重发起点,取最大值 (100)当已提交上界,然后从 97 开始逐事件重放,落在 97 到 100 之间的那些去 wait_seqnos 里比对------在里面的说明还没被所有通道处理完,重新回放;不在里面的说明已经提交过,跳过。

这套机制保证了多通道并行下崩溃恢复不重不漏。你在生产上遇到进程被 OOM Kill 或者网络抖断,重启之后不用做任何人工干预,这是它的底气。


四、动手之前的环境准备

安装之前有几件事必须先确认,不然装完跑不起来会浪费很多时间。

操作系统和依赖 。确认服务器时间同步(NTP 必须开,跨节点时间差会导致事务顺序判断出问题),glibc、openssl 这些基础库版本符合安装手册要求。

数据库侧的权限 。源端建一个专用账号给 KFS 用,授予日志解析需要的权限;目标端账号需要有 CREATE TABLE、INSERT、UPDATE、DELETE 以及对应表空间的读写权限。别图省事用 SYSDBA 或超级用户,出了权限问题不好定位是谁的。

源端日志配置。Oracle 要开归档并预留足够的空间;KingbaseES 要开启对应的日志解析级别。这一步漏了,装完 KFS 启动会直接报日志解析失败。

网络连通性 。源端、目标端数据库端口,加上 KFS 自己的端口,全部要双向放行。KFS 同步程序之间的通信默认走 kufl-port,管理和 RMI 默认 11000,管控台默认 8089/8443,防火墙按实际配置放行。

部署模式选分离还是集中。开发测试图省事,KFS 和数据库装一台机器上(集中部署)没问题。生产环境建议分离部署------把 KFS 拆到独立节点上,避免同步进程和数据库抢 I/O。核心系统上这一点尤其重要,我见过同机部署导致业务高峰期同步延迟飙升的案例。

另外推荐一个动作:正式实施前先跑一遍 KFS evaluate 评估工具。它会把源端和目标端的操作系统、数据库配置、数据类型、主键约束这些都收集起来生成报告,提前把"哪张表没有主键""归档模式不对"这类风险暴露出来。项目返工的成本远高于多花半天做评估。


五、安装与配置

安装包的命名规则一般是 V00XR00XC00XBYYYYMMDD 这种形式,里面是二进制加脚本,不需要编译。

5.1 建用户、解压

bash 复制代码
# 建专用用户(不要用 root 跑同步程序)
useradd flysync
echo flysync | passwd --stdin flysync

# 视需要把它加进数据库用户组
usermod -G kingbase flysync
su - flysync

# 解压同步程序
mkdir -p /opt/kfs_install && cd /opt/kfs_install
tar -zxvf KingbaseFlysync-V2.0-xxxxxxxx-replica

5.2 写 flysync.ini

这是整个部署里最需要仔细看的一步。同步程序安装时读的就是 $HOME/flysync.ini,源端和目标端各有一份,靠 role 区分。

源端(Oracle,master):

bash 复制代码
[defaults]
install-directory=/home/flysync/kfs
profile-script=~/.bash_profile
rmi-port=11000

[oracle11g_redo]
role=master
master=10.10.5.49
members=10.10.5.49
kufl-port=3112
replication-host=10.10.5.49
replication-port=1521
replication-user=FLYSYNC
replication-password=********
datasource-type=oracle
oracle-extractor-method=redo
datasource-oracle-service=orcl
property=replicator.extractor.dbms.tablePatterns=APP_ORDER.*,APP_USER.*
svc-extractor-filters

目标端(KingbaseES,slave):

bash 复制代码
[defaults]
install-directory=/home/flysync/kfs
profile-script=~/.bash_profile
rmi-port=11000

[oracle11g_redo]
role=slave
master=10.10.5.49
master-kufl-port=3112
members=10.10.3.200
kufl-port=3115
replication-host=10.10.3.200
replication-port=54321
replication-user=flysync
replication-password=********
datasource-type=kingbase

几个参数解释一下:

  • role:源端 master,目标端 slave。写反了服务起不来。
  • kufl-port / master-kufl-port:两个同步程序之间传 KUFL 的端口,必须先放行。
  • property=replicator.extractor.dbms.tablePatterns:表过滤,格式是"模式名.表名",支持逗号分隔多个,也支持通配。这一行决定了你到底同步哪些表,配错了就是全库同步,性能和风险都不可控。
  • svc-extractor-filters=dropstatementdata:开启 DDL 语句过滤。要不要开取决于你的场景------双轨并行、业务还在迭代的情况下通常不开,让 DDL 也同步过去。

参数名在不同版本间略有差异,以随安装包发布的《安装部署手册》为准,别照抄网上的旧模板。

5.3 执行安装

bash 复制代码
# 进入解压目录下的 tools 目录执行
cd /opt/kfs_install/tools
fspm install

# 让环境变量生效
source ~/.bash_pr

然后把 license 文件放到安装目录($HOME/kfs/)下,这是一个容易漏的步骤,缺 license 服务能起来但同步不会工作。

5.4 启停与状态

bash 复制代码
# 同步程序整体启停
replicator start
replicator stop
replicator restart

# 查看所有服务状态
fsrepctl services

# 查看指定服务状态,state 显示 online 表示正常
fsrepctl -service oracle11g_redo status

# 单独上线/下线某个服务(常用于割接前后的开关)
fsrepctl -service oracle11g_redo offline
fsrepctl -service oracle11g_redo online

# 重置 KUFL 位点(慎用,会重新开始解析)
fsrepctl -service oracle11g_red

管理端(KFSMC 管控台)是另一套安装:

bash 复制代码
./install.sh --mode kfsmc --target /opt/kfs/mc

装完之后目录结构大致是这样:

bash 复制代码
/home/flysync/kfs/
├── bin/           # 命令行工具
├── conf/          # 配置文件
├── data/kufl/     # KUFL 跟踪文件
├── logs/          # 日志
└─

验证一下装没装好:

bash 复制代码
fsrepctl --version     # 能输出版本号且无报错,说明后端程序没问题

六、建表:这件事最容易被轻视

迁移项目里,表结构往往被认为"不就是把 DDL 复制过去"。真上手就知道不是。Oracle 的 NUMBER 到 KES 的映射、DATE 和 TIMESTAMP 的语义差别、主键和唯一约束在目标端要不要保留(保留会拖慢同步速度)、字符集和排序规则的差异......每一条都能在同步过程中变成事故。

先说一个基本事实:KFS 处理的是数据变更事件,不是表结构 。默认情况下(也就是你开了 dropstatementdata 过滤 DDL 的时候),DDL 不会自动同步。所以你必须在同步开始之前,保证目标端的表结构已经建好,而且和源端逻辑上兼容。

我一般建议这么建表:目标端先手动建一套干净的结构,字段类型按 KES 的原生类型给最贴合的,而不是机械照搬源端。同步工具负责填数据,你负责保证结构正确。

下面这套表是这次项目的核心业务表,源端是 KingbaseES,用的 ksql 客户端:

sql 复制代码
-- 订单主表
CREATE TABLE app_order.t_order (
    order_id        BIGINT          NOT NULL,
    order_no        VARCHAR(32)     NOT NULL,
    customer_id     BIGINT          NOT NULL,
    order_amount    NUMERIC(18,2)   DEFAULT 0 NOT NULL,
    order_status    SMALLINT        DEFAULT 10 NOT NULL,
    pay_time        TIMESTAMP       NULL,
    create_time     TIMESTAMP       DEFAULT CURRENT_TIMESTAMP NOT NULL,
    update_time     TIMESTAMP       DEFAULT CURRENT_TIMESTAMP NOT NULL,
    remark          VARCHAR(500)    NULL,
    CONSTRAINT pk_t_order PRIMARY KEY (order_id)
);

COMMENT ON TABLE  app_order.t_order               IS '订单主表';
COMMENT ON COLUMN app_order.t_order.order_status  IS '订单状态:10待支付 20已支付 30已发货 90已取消';

-- 订单明细表
CREATE TABLE app_order.t_order_item (
    item_id         BIGINT          NOT NULL,
    order_id        BIGINT          NOT NULL,
    sku_code        VARCHAR(64)     NOT NULL,
    sku_name        VARCHAR(200)    NOT NULL,
    quantity        INT             DEFAULT 1 NOT NULL,
    unit_price      NUMERIC(18,2)   NOT NULL,
    item_amount     NUMERIC(18,2)   NOT NULL,
    create_time     TIMESTAMP       DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT pk_t_order_item PRIMARY KEY (item_id),
    CONSTRAINT fk_item_order   FOREIGN KEY (order_id) REFERENCES app_order.t_order(order_id)
);

COMMENT ON TABLE app_order.t_order_item IS '订单明细表';

-- 订单号序列
CREATE SEQUENCE app_order.seq_order_no
    START WITH 1000000
    INCREMENT BY 1
    CACHE 20;

-- 常用查询索引
CREATE INDEX idx_order_customer ON app_order.t_order (customer_id, create_time DESC);  

几个细节值得说:

  • 一定要有主键。KFS 在做 UPDATE、DELETE 回放时需要主键(或唯一键)来定位行。无主键表虽然产品支持(会把整行当条件做全字段匹配),但那是性能和风险的交换,生产表尽量别这么干。
  • 外键约束在同步场景里是把双刃剑。目标端保留外键,回放大事务时可能因为顺序问题报约束冲突。很多项目的做法是目标端先不建外键,等割接完成后视需要再加。
  • NOT NULL 和默认值要和源端对齐。源端某列有默认值、目标端没有,就会出现源端不传值、目标端插入失败的情况。
  • 时间戳字段用数据库默认值而不是应用传值 ,能让两端的 create_time 语义一致,校验时少一类"假差异"。

如果源端是 Oracle,建表语句要做对应改造,比如 NUMBER(18,2) → NUMERIC(18,2),VARCHAR2(32) → VARCHAR(32),CLOB → TEXT。KFS 内置了类型转换引擎,会自动处理大部分映射,但特殊类型建议在管控台里手动确认一次映射规则 ------比如 Oracle 的 CLOB 到 KES 的 TEXT,长度和精度的处理策略要看清楚,别等同步报错了才发现。

至于 DDL 之后的变更(ALTER TABLE ADD COLUMN),如果开了 DDL 同步,KFS 会把它作为事件投递到目标端并固定在通道 0 执行。双轨并行阶段这个特性非常有用,业务还在迭代、表结构随时可能变,靠人工两端同步迟早出错。


七、增删改查:每一步都在两端验证

配置好了,接下来跑一遍完整的 CRUD。这部分我用的是双窗口对照:左边源端查,右边目标端查。

7.1 插入

sql 复制代码
-- 源端:插入订单主表
INSERT INTO app_order.t_order
    (order_id, order_no, customer_id, order_amount, order_status, remark)
VALUES
    (2001, 'SO202610120001', 88001, 1299.00, 10, '首单优惠');

-- 插入订单明细
INSERT INTO app_order.t_order_item
    (item_id, order_id, sku_code, sku_name, quantity, unit_price, item_amount)
VALUES
    (30001, 2001, 'SKU-A-001', '机械键盘 87 键', 1, 899.00, 899.00),
    (30002, 2001, 'SKU-B-002', '腕托 记忆棉',     2, 200.00, 400.00);

源端提交后,大概几百毫秒内目标端就能查到:

sql 复制代码
-- 目标端:验证
SELECT order_id, order_no, order_status, order_amount
FROM   app_order.t_order
WHERE  order_id = 2001;

这一步如果查不到,按这个顺序排查:kufl list 看源端有没有解析出事件 → fsrepctl -service <服务名> status 看服务和通道是不是 online → 看目标端 logs/ 下的 applier 日志有没有报权限或类型错误。

7.2 查询

目标端不只是"接收方",它同时也是可读的业务库。校验期间最常用的就是这类对账查询:

sql 复制代码
-- 统计某客户近 7 天订单数
SELECT   customer_id,
         COUNT(*)              AS order_cnt,
         SUM(order_amount)     AS total_amount
FROM     app_order.t_order
WHERE    customer_id = 88001
  AND    create_time >= CURRENT_TIMESTAMP - INTERVAL '7 days'
  AND    order_status <> 90
GROUP BY customer_id;

7.3 更新

sql 复制代码
-- 源端:支付成功,改状态并写支付时间
UPDATE app_order.t_order
SET    order_status = 20,
       pay_time     = CURRENT_TIMESTAMP,
       update_time  = CURRENT_TIMESTAMP
WHERE  order_id = 2001;
sql 复制代码
-- 目标端核对:状态和支付时间应完全一致
SELECT order_id, order_status, pay_time
FROM   app_order.t_order
WHERE  order_id = 2001;

这里有个新手最容易误判的现象:改完之后立刻去目标端查,可能还是老值。原因大概率是 Buffer Flush 没触发------KFS 攒批提交是有间隔的。等一两秒再看,或者把 flush 间隔调短。不要一看到延迟就去翻日志找 bug,先确认是不是正常攒批。

7.4 删除

sql 复制代码
-- 源端:取消并清理这条明细
DELETE FROM app_order.t_order_item WHERE item_id = 30002;

-- 目标端核对:应为 0 行
SELECT COUNT(*) FROM app_order.t_order_item WHERE item_id = 30002;

7.5 事务:真正见功力的地方

单条语句同步是基础,事务的原子性才是能不能用在生产上的分水岭。源端一个事务里跨两张表操作,KFS 必须在目标端把它们当作一个整体处理------要么都可见,要么都不可见,不能出现"订单有了明细没有"的中间状态。

sql 复制代码
-- 源端:一个显式事务,跨两张表
BEGIN;

INSERT INTO app_order.t_order
    (order_id, order_no, customer_id, order_amount, order_status)
VALUES
    (2002, 'SO202610120002', 88002, 599.00, 10);

INSERT INTO app_order.t_order_item
    (item_id, order_id, sku_code, sku_name, quantity, unit_price, item_amount)
VALUES
    (30003, 2002, 'SKU-C-003', '人体工学椅', 1, 599.00, 599.00);

UPDATE app_order.t_order
SET    order_status = 20,
       pay_time     = CURRENT_TIMESTAMP
WHERE  order_id = 2002;

COMMIT;

事务提交后,目标端必须同时看到订单和明细:

sql 复制代码
SELECT o.order_id, o.order_status, i.item_id, i.sku_name
FROM   app_order.t_order o
JOIN   app_order.t_order_item i ON i.order_id = o.order_id
WHERE  o.order_id = 2002;

这个测试建议在压测阶段反复做------用一个脚本循环跑几百个跨表事务,同时观察目标端有没有出现中间态。KFS 在目标端是通过多通道的位点协调来保证这一点的,前面 trep_commit_seqno 那张表就是它的实现基础。

还可以顺手验证一下大事务:源端一次性插入 50 万行,看目标端什么时候可见、耗时多久、通道队列有没有堆起来。这时候前面说的"按表拆分并行"就派上用场了------如果观察到某个通道队列一直很长而其他通道很闲,说明分区策略和你的事务形态不匹配,可以在管控台调整路由策略。

7.6 用 kufl 反向确认

数据对不上的时候,别急着猜。直接看 KUFL 里有没有那条记录,一次就能把问题定位到"没解析出来"还是"没写进去":

bash 复制代码
# 查看 KUFL 内容,搜索刚才的订单
kufl -service oracle11g_redo list | grep 2002

有记录 → 问题在 Applier 侧(权限、类型、约束)。 没记录 → 问题在 Extractor 侧(日志配置、表过滤、账号权限)。

这个判断顺序能省掉大量来回试错的时间。


八、数据校验与修复:别让"幽灵数据"过夜

同步工具最怕的不是延迟高,是悄悄少了一条数据而你不知道。

这种数据有人叫"幽灵数据"------它不在任何告警里,只有在某天业务对不上账的时候才浮出水面。所以 KFS 内置的校验修复模块,我认为是整个产品里价值最高的部分,比同步本身还重要。

它用的是所谓"三步校验法":

  1. 存量校验。历史数据智能分块并行比对,几亿行的表也不会卡死。
  2. 增量校验。同步过程中实时比对,事务级、行级、字段级都可以配。
  3. 应急回切。校验发现不一致时,可以按位点回退重放,或者直接以某端为准做定向修复。

官方给的实测数据是差异率控制在 0.001% 以内,修复效率提升 80% 以上。这个数字在西藏"智慧市场监管"那类超大存量项目上有验证------40TB 以上历史数据加每秒千条的增量,割接停机压缩到分钟级。

8.1 图形化做校验

管控台(KFSMC)里走一遍就行:新建校验任务 → 选表 → 设校验范围(全量/增量)→ 开始校验 → 看差异。

建议把全量校验安排在业务低峰期。校验本身是资源消耗大户,跟业务抢 I/O 不划算。增量校验可以一直挂着,它对业务基本无感知。

8.2 命令行做校验和修复

有些机房不让部署图形界面,或者要把校验塞进自动化流程里。KFS 给了命令行工具 cmdcompare,位于管控台安装目录下:

bash 复制代码
# 工具路径
<KFS安装路径>/console/bin/cmdcompare

修复某个校验任务下所有表的差异:

bash 复制代码
./cmdcompare replicate \
  -port 8089 \
  -username admin \
  -password '********' \
  -task.id 1

只修复指定表(比如只处理那张差异最大的流水表):

bash 复制代码
./cmdcompare replicate \
  -port 8089 \
  -username admin \
  -password '********' \
  -table.id 101

执行时控制台会输出进度:

bash 复制代码
[INFO] Task ID: 1, Status: RUNNING
[INFO] Repairing table: T_ORDER...
[INFO] Repaired 15 records.
[INFO] Task completed successfully.

结果文件落在管控台安装目录的 /compare/cluster-home/result/ 下,文件名形如 {校验任务名}_{校验类型}_{校验任务执行时间},里面记录了具体的修复条目数,做割接报告的时候这就是证据链。

一个必须提醒的坑 :命令行比对目前不支持无缝模式 ,而且它会动图形化界面维护的数据。绝对不要 在管控台正在维护同一个同步任务的时候混用命令行工具,否则两边的状态会打架。要么全走界面,要么全走命令行。另外推荐在没有增量写入的窗口期做命令行比对,或者至少选在业务低峰。

8.3 自动修复怎么配才安全

详细校验模式下有三种自动修复机制,可以组合用:

  • 阈值自动修复:差异条数超过设定阈值才触发修复,低于阈值只告警。适合过滤掉网络抖动造成的瞬时差异。
  • 指定表自动修复:只对白名单里的表自动修,其他表标记"待人工处理"。核心账务类表建议走这条路,别全自动。
  • 延迟自动修复:校验完成后等一个设定时间(比如 5 分钟),期间没有新差异产生才执行修复。这个能有效避免"把还在路上的正常数据当成差异修掉"。

我的经验是:非核心表配阈值+延迟组合,核心表一律人工确认。全自动修复在数据写入有冲突的场景下是危险的,上线前必须拿小表做验证。


九、几个真实的坑

这一节是纯经验,材料里基本不会写。

坑一:复制槽冲突。 服务启动报"复制槽已存在",而且删不掉。常见于反复重装或者异常中断之后。处理办法是在数据库里手工清理:

sql 复制代码
-- 查看槽状态
SELECT slot_name, active, restart_lsn FROM <对应槽视图>;

-- 停止同步服务后再清理
-- (具体函数名以目标库版本手册为准,不同版本差异较大)

清理顺序记住一点:先停 Replicator,清理完再启动。顺序反了槽会被重新占用。

坑二:无主键表。 表面上能同步,实际上每次 UPDATE/DELETE 都要做全字段匹配,大表上性能会塌方。迁移前跑 KFS evaluate 就是为了把这类表提前挖出来。能加主键的加,不能加的评估是否真的需要同步。

坑三:类型映射的隐性差异。 Oracle CLOB 到 KES TEXT、NUMBER 精度丢失、空字符串和 NULL 的语义差别。这些不会报错,但会让校验结果出现"明明看着一样却判为不一致"的情况。校验前先把映射规则核对一遍。

坑四:字符集。 两端编码不一致会直接表现为乱码或者插入失败。KFS 内置了字符集转换,但前提是源端账号的会话字符集设置正确。这个坑在跨厂商迁移里出现频率极高。

坑五:大事务把单通道塞满。 前面讲过,一个大事务如果没被拆开,会整个堆在一个通道上,其他通道干看着。表现为总体吞吐上不去、延迟曲线周期性尖峰。解决方案是启用表亲和性加事务拆分,或者把大事务在业务侧拆成小批。

坑六:把反向同步开成环。 双向同步的配置一旦写错,A 的变更同步到 B,B 又同步回 A,会形成无限循环,两端数据疯狂翻倍。配置双向时务必确认变更来源识别(防止回环)的机制是打开状态。

坑七:NTP 没开。 分布式同步里两端时间偏差过大会影响事务顺序判断。这条最不起眼,但排查起来最费劲------因为它不报错,只是偶尔出现诡异的数据顺序问题。


十、拓扑怎么选,以及一些落地建议

拓扑这块不复杂,关键是先想清楚数据流向。

一对多 是数据分发,典型场景是省中心向地市分发------公开案例里安徽省发改委那个就是中心数据实时分发到 16 个地市。多对一 是数据汇聚,集团多工厂、多院区的数据往中心归集。双向 是双轨并行和双活,新老系统同时跑,随时能切回来,这也是我开头那个项目的选择。级联适合多层级分发,A → B → C 那种。

基础设施受限的场景也别忽略:KFS 支持跨网段、跨防火墙、跨正反向网络隔离设备、跨单向通信光闸同步。有些项目源端和目标端网络根本不通,是靠域名解析中转解决的------公开案例里湖南移动那个统一调度平台就是这种形态,400G 级存量加每天 400G 增量,延迟仍然在秒级。广域网链路还有压缩传输,2M 带宽跑实时容灾这类要求也能满足。

最后几条经验,是从返工里换来的。

评估千万别省。跳过 evaluate 和表结构梳理直接配同步,省下的那半天,最后往往要用几周补回来。写完方案先拿三五张表、一个完整业务闭环跑满一周,把校验、告警、修复的流程都走通,再往全库扩。

监控上真正需要盯的就三个数:同步延迟、通道队列深度、错误率。延迟看业务影响,队列深度看分区策略配得合不合适,错误率看有没有隐性失败。其他指标多数时候是噪音。

还有割接演练。模拟源端宕机,看目标端顶不顶得住,切完立刻跑全量校验。演练里暴露的问题,代价比生产上小一个数量级。以及那句听起来很废话但必须写进方案的话------回退方案要有。双轨并行的全部意义就在这儿,切过去不对,能切回来。


回到开头那个项目。4 小时窗口,最后实际用的停机时间是 11 分钟,剩下三个多小时全在跑校验和确认。老张那天没说话,就在旁边看着两个终端上的数据一行行对齐。

数据集成软件这类工具的价值大概就在这儿。它不产生新业务,也不让报表变好看,它只是让数据在两个不该说话的系统之间,安静、准确、持续地流动。真出事的时候,它是那个能证明"数据没错"的东西。

本文涉及的操作步骤和参数以随产品发布的《安装部署手册》《技术白皮书》为准,不同版本间存在差异,请以实际环境验证结果为准。

相关推荐
云贝贝贝2 小时前
Oracle 认证实战指南
数据库·oracle
达梦数据2 小时前
达梦数据复制软件DMDRS搭建部署示例:源数据库DMDPC到目标数据库DM8一对一数据同步
数据库·oracle
AlfredZhao2 小时前
SQLcl 用文件夹直观管理数据库连接
oracle
江湖有缘15 小时前
Docker实战 | 使用Docker部署rmoments社交平台
jvm·docker·oracle
for_ever_love__15 小时前
MySQL SELECT 与 WHERE 优化实战:可搜索条件、联合索引与执行计划
数据库·mysql·oracle·select·where·条件优化·查询优化技巧
路远的数据库笔记17 小时前
Oracle报ORA-00020连接打满?从专用进程模型到静态参数,一次生产排查全记录
数据库·oracle·国产数据库·ora-00020·dba实战·sharedserver
dishugj20 小时前
HANA监控、巡检与切换演练
数据库·oracle
oradh21 小时前
Oracle 索引维护操作总结
数据库·oracle
泡海椒1 天前
JQuickExcel 批量导入:用 importDataInBatch 控制大文件消费边界
数据库·oracle