KaiwuDB 集群复制
功能概述
KaiwuDB 集群复制是一种异步数据同步机制,支持将表或库的数据(包括时序数据和关系数据)从主库(源端)集群实时复制到备库(目标端)集群,实现主备部署和灾备能力。用户可通过启动/停止复制任务来管理数据同步,并基于复制状态监控实现主备切换和灾备恢复。
核心特性
- 灵活的复制粒度:支持表级别和库级别的数据复制。库级别复制定义后,表内数据、新增表及对应 DDL 操作均自动复制。
- 断点续传:支持从指定时间点开始历史数据复制和断点续传。复制中断后,系统会基于上次 checkpoint 恢复复制,无需从头开始。
- 高可用性:在多副本架构下,故障节点数小于副本数的一半时,复制仍可正常进行。主库节点故障时,RangeFeed 会自动切换到新的 leader 节点继续推送数据;备库节点故障时,复制协程会重新选举并从上次 checkpoint 恢复。网络中断时,系统会自动重试连接,通过 HAProxy 代理切换到可用节点,并基于断点继续复制。
应用场景
- 集群主备部署:在同一数据中心内部署主备集群,主库承担业务读写负载,备库实时同步数据。当主库发生故障时,可以快速将业务切换到备库,保障业务连续性。
- 跨数据中心灾备:在不同地理位置的数据中心间建立主备复制关系,实现异地容灾。当主数据中心发生重大故障、自然灾害或网络中断时,可将业务快速切换到备用数据中心,保障数据安全和业务连续性。
- 一主多备:一个主库同时向多个备库复制数据,实现多份数据备份。不同备库可服务于不同场景:生产环境备份、测试环境数据同步、报表查询负载分离等,提高资源利用率。
- 云边端协同:在云端、边缘节点和终端设备之间建立数据复制关系,支持边缘计算场景。边缘节点采集的数据可实时同步到云端进行集中分析,实现云边数据协同。
使用限制
- 复制约束:
- 已有复制存在时,不支持删表/库操作。如需删除表或库,需先停止相关复制任务
- 已有复制存在时,不支持跨库或跨表事务。单个事务中的所有操作必须全部在复制范围内或全部在复制范围外,不允许部分数据复制、部分数据非复制的情况
- 不支持同步复制(同步复制在复制中断时会阻塞主库业务)
- 对同一个表,库级复制和表级复制不能同时存在
- 目前暂不支持对权限、存储过程、触发器、发布订阅、数据推送、流计算、序列、视图(包括普通视图、物化视图和临时视图)、索引、数据分区、区域和注释操作的复制
- 库级复制限制:在开启库级别复制情况下,不支持删除库内最后一张表。在库内无表的情况下,不支持开启库级复制,需要先进行库内表创建后才能开启库级复制。
- 一致性约束:关系数据保证最终一致性,但不保证主库事务在备库的完整性。复制以已提交事务为单位进行,但不保证事务内多条记录的原子可见性。例如,主库执行
BEGIN; INSERT t1 VALUES (1), (2), (3); COMMIT;后,备库在复制过程中可能出现(1)、(1), (2)、(1), (3)等部分数据可见的中间状态,但最终保证(1), (2), (3)全部可见。
基础概念
| 术语 | 英文 | 说明 |
|---|---|---|
| 主库(源端) | Primary/Source | 数据复制的源头集群,提供数据给备库 |
| 备库(目标端) | Standby/Target | 数据复制的接收端集群,从主库接收数据 |
| 复制任务 ID | Replication Job ID | 系统分配的任务标识符,包括 replication_producer_id(主库任务 ID)和 replication_consumer_id(备库任务 ID) |
| 检查点 | Checkpoint | 记录复制进度的时间点,last_checkpoint 保证该时间点前的数据已复制完成,但因数据入库存在延迟,备库中可能存在入库时间晚于该时间点的数据 |
| 断点续传 | Resume from Checkpoint | 从中断点继续复制,避免从头开始,基于 last_checkpoint 恢复复制 |
| 复制状态 | Replication Status | 复制任务的执行状态,包括 running(运行中)、paused(已暂停)、succeeded(成功完成)、failed(失败) |
| RangeFeed | RangeFeed | KaiwuDB 的数据变更推送机制,用于实时推送数据变更到备库。集群复制功能依赖此机制,使用前必须在主库通过 SET CLUSTER SETTING kv.rangefeed.enabled = true 启用 |
| HAProxy | HAProxy | 高可用代理服务,用于负载均衡和故障切换,建议将复制连接配置为 HAProxy 地址 |
| GC | Garbage Collection | 垃圾回收,清理历史版本数据 |
| RTO | Recovery Time Objective | 系统从停机恢复到可提供服务的时间。例如,RTO = 0 表示业务不受影响;RTO = 1 分钟表示最长中断 1 分钟。 |
| RPO | Recovery Point Objective | 停机期间可能丢失的数据量(以秒为单位)。例如,RPO = 0 表示无数据丢失;RPO = 1 秒表示最多丢失 1 秒数据。 |
环境要求
硬件和网络要求
- 硬件资源:备库硬件资源建议和主库保持同等配置,硬件环境不一致可能影响高可用的正常运行以及 RTO、RPO 时间
- 网络延迟:建议网络延迟不超过 100ms
- 时钟同步:为保证主备复制的可用性需要对主备物理机进行时钟校时,要求主备物理机时间差不大于 500ms
配置要求
- 配置一致性:主备库启动命令及配置文件应保持一致,例如
--max-sql-cache、--cache等参数,以及压缩配置、GC 频率等设置应保持相同,配置不一致可能存在未知风险 - 权限要求:设置主备数据复制的用户必须拥有
admin权限。 - 证书认证:安全模式下需要主备库共享证书。提示:使用脚本部署时,在主库配置文件
[additional]中指定备库所有节点 IP,生成证书后拷贝到备库相同目录,然后用./deploy.sh install --multi-replica --use-certs <cert-path>命令安装备库即可实现证书共享。 - 用户名密码要求:主库和备库必须使用同名用户及密码。
- 历史数据保留:如需从指定时间点开始复制历史数据,需要在启动复制前配置 GC 时间以保留足够的历史版本。建议根据复制窗口设置
gc.ttlseconds,默认 25 小时可能不足以支持长时间的历史数据复制。ALTER RANGE default CONFIGURE ZONE USING gc.ttlseconds = 180000;
说明
- 当历史数据被 GC 回收后,可能会导致增量复制的主库和备库数据不一致
- 保留过多的历史版本数据会占用额外的存储空间,并在一定程度上影响查询性能,建议根据实际复制窗口合理设置 GC 时间
配置集群复制
启动数据复制
REPLICATE [DATABASE <database_name>| TABLE <table_name>]
FROM <source_url>
WITH <options>;
参数说明
database_name:要复制的库名。注意:库内无表的情况下,不支持开启库级复制,需要先进行库内表创建后才能开启库级复制。table_name:要复制的表名,格式为database_name.schema_name.table_name,未指定数据库和模式时,表示复制当前数据库默认模式下的表。source_url:主库集群地址,格式为 PostgreSQL 连接字符串。支持安全和非安全两种模式。建议配置为 HAProxy 地址而非直连节点 IP,以便在主库节点故障时自动切换。- 非安全模式:格式为
postgresql://user@host:port?sslmode=disable,例如:postgresql://root@192.168.111.128:26257?sslmode=disable - 安全模式:支持两种认证方式:
- 用户名密码认证,需要在主库和备库创建同名用户及密码,格式为
postgresql://user:password@host:port - 证书认证:需要主备库共享证书,格式为:
postgresql://user@host:port/database?sslmode=verify-ca&sslcert=<cert_path>&sslkey=<key_path>&sslrootcert=<ca_path>
- 用户名密码认证,需要在主库和备库创建同名用户及密码,格式为
- 非安全模式:格式为
options: 复制选项,支持以下参数组合:init: 仅复制表结构和未来新增数据data: 备库已有表结构,仅复制数据 (包括历史数据和未来新增数据)init, data: 备库为空,需要完整复制表结构和数据data, lastTime(<timestamp>): 备库已有表结构,仅复制指定时间点后的历史数据和未来新增数据init, data, lastTime(<timestamp>):复制表结构以及指定时间点后的历史数据和未来新增数据
返回字段说明
replication_producer_id: 主库复制任务 ID,用于在主库管理复制任务replication_consumer_id: 备库复制任务 ID,用于在备库管理复制任务start_time:用户指定的数据复制时间点,未指定时返回0
示例
非安全模式下,复制库结构和未来增量数据
REPLICATE DATABASE e1primary FROM 'postgresql://root@192.168.111.128:26260?sslmode=disable' WITH init;证书认证的安全模式下,复制库结构和所有数据
REPLICATE DATABASE e1primary FROM 'postgresql://root@localhost:26267/defaultdb?sslmode=verify-ca&sslcert=./certs/client.root.crt&sslkey=./certs/client.root.key&sslrootcert=./certs/ca.crt' WITH init, data;非安全模式下,目标表已存在,仅复制数据
REPLICATE TABLE defaultdb.public.t1 FROM 'postgresql://root@192.168.111.128:26257?sslmode=disable' WITH data;非安全模式下,复制表结构和指定时间点后的数据
REPLICATE TABLE defaultdb.public.t3 FROM 'postgresql://root@192.168.111.128:26257?sslmode=disable' WITH init, data, lastTime('2025-09-18 03:36:19.665970998+00:00');
停止数据复制
优雅停止
在备库执行以下命令:
REPLICATE STOP <replication_consumer_id> WITH TIMEOUT <duration>
参数说明
replication_consumer_id: 启动复制时返回的备库任务 IDduration: 超时时间,在指定时间内无新数据写入后停止复制
返回字段说明
replication_consumer_id: 启动复制时返回的备库任务 IDlast_checkpoint:最后一次检查点时间,该时间点之前的数据已全部复制完成。注意:数据入库时间可能晚于此时间点,在备库执行超过该时间点的操作可能因冲突而失败。status: 复制状态
示例
REPLICATE STOP 845690899499384833 WITH TIMEOUT 100ms;
replication_consumer_id | last_checkpoint | status
--------------------------+--------------------------------------+--------------
845689849649332225 | 2025-09-18 03:36:19.665970998+00:00 | succeeded
(1 row)
强制终止
说明:
强制终止方式会立即终止复制,不保证主库和备库数据一致性,因此建议仅在紧急情况下使用,推荐使用 REPLICATE STOP 优雅停止复制。
-- 在主库终止复制任务
CANCEL JOB <replication_producer_id>;
-- 在备库终止复制任务
CANCEL JOB <replication_consumer_id>;
验证复制状态
SELECT * FROM [SHOW JOBS] WHERE job_type = 'REPLICATION';
返回状态说明
- running:复制任务正在运行
- paused:复制任务已暂停
- succeeded:复制任务成功完成
- failed:复制任务失败
场景配置示例
正常运维场景
主备初始化
主备初始化适用于建立新的主备集群复制关系,实现数据的异步备份。
步骤:
登录主库任一节点,启用 RangeFeed 功能:
SET CLUSTER SETTING kv.rangefeed.enabled = true;登录备库任一节点,设置为只读模式:
SET CLUSTER SETTING default_transaction_read_only = true;在备库以数据库为单位启动数据复制:
REPLICATE DATABASE e1primary FROM 'postgresql://root@192.168.111.128:26260?sslmode=disable' WITH init, data;验证复制状态,状态变为
running后表示复制任务正常运行。SELECT * FROM [SHOW JOBS] WHERE job_type = 'REPLICATION';
计划性停机和恢复
计划性停机即用户需要对集群进行硬件维护或软件升级,需要暂停复制并在完成后恢复。
步骤:
登录主库任一节点,设置为只读模式,保证数据一致性:
SET CLUSTER SETTING default_transaction_read_only = true;登录备库任一节点,5 秒内无写入后停止所有复制:
REPLICATE STOP <replication_consumer_id> WITH TIMEOUT 5s;登录主库任一节点,取消只读模式:
SET CLUSTER SETTING default_transaction_read_only = false;在主库/备库进行停机/重启等计划性操作。
登录备库任一节点,启动所有复制,指定
last_checkpoint时间节点。说明:last_checkpoint可从REPLICATE STOP命令的返回结果中获取,也可通过查询系统表中已停止的 job 获取。REPLICATE TABLE defaultdb.public.b FROM 'postgresql://root@192.168.111.128:26257?sslmode=disable' WITH init, data, lastTime('2025-09-18T03:36:19.665970998Z');
计划性主备切换
步骤:
登录主库任一节点,设置为只读模式,保证数据一致性:
SET CLUSTER SETTING default_transaction_read_only = true;登录备库任一节点,5 秒内无写入后停止所有复制:
REPLICATE STOP <replication_consumer_id> WITH TIMEOUT 5s;在备库任一节点,启用 RangeFeed 功能:
SET CLUSTER SETTING kv.rangefeed.enabled = true;登录主库任一节点,启动到原备库(新主库)的复制,使用
REPLICATE STOP命令的返回结果中获取的last_checkpoint点:REPLICATE TABLE defaultdb.public.b FROM 'postgresql://root@备库地址:26257?sslmode=disable' WITH init, data, lastTime('2025-09-18T03:36:19.665970998Z');在原主库任一节点,取消只读模式:
SET CLUSTER SETTING default_transaction_read_only = false;登录新主库任一节点,取消只读模式,允许用户进行读写:
SET CLUSTER SETTING default_transaction_read_only = false;
故障处理场景
自动恢复场景
以下场景系统会自动处理,无需用户干预,用户可通过 KaiwuDB 监控平台或系统表确认复制状态:
- 主库部分节点故障:主库故障节点数少于副本数的一半时,RangeFeed 自动切换到新的主节点继续数据复制。
- 备库部分节点故障:备库故障节点数少于副本数的一半时,复制协程自动重新选举,并基于
last_checkpoint进行断点续传。 - 网络中断或波动:网络临时中断或波动时,系统自动重试连接,通过 HAProxy 代理切换到可用节点,并基于断点继续复制。
备库不可用
备库故障节点数等于或超过副本数的一半导致集群不可用时,用户可根据业务需求选择以下任一方式:
- 等待备库恢复:备库集群恢复后会自动基于断点进行复制,无需用户操作。
- 重建新备库:搭建新的备库,重建复制,
重建新备库的具体步骤如下:
登录主库任一节点,取消现有复制任务:
CANCEL JOB <replication_producer_id>;在新备库重建复制,具体步骤参考主备初始化。
主库不可用
主库故障节点数等于或超过副本数的一半导致集群不可用时,需要将备库提升为主库。
步骤:
修改 HAProxy 配置,将备库开放给应用访问。
登录备库任一节点,5 秒内无写入后停止复制:
REPLICATE STOP <replication_consumer_id> WITH TIMEOUT 5s;在备库任一节点,取消只读模式:
SET CLUSTER SETTING default_transaction_read_only = false;(可选)如果后续主库恢复正常,可通过以下步骤,恢复数据复制:
登录原备库(新主库)任一节点,启用 RangeFeed 功能:
SET CLUSTER SETTING kv.rangefeed.enabled = true;登录原主库任一节点,设置为只读模式:
SET CLUSTER SETTING default_transaction_read_only = true;在原主库任一节点,取消旧的复制任务:
CANCEL JOB <replication_producer_id>;在原主库任一节点,重建到原备库(新主库)的复制,使用
REPLICATE STOP命令返回的last_checkpoint点:REPLICATE TABLE defaultdb.public.b FROM 'postgresql://root@新主库地址:26257?sslmode=disable' WITH init, data, lastTime('2025-09-18T03:36:19.665970998Z');
故障排查
错误信息
| 错误信息 | 原因 | 解决方法 |
|---|---|---|
ERROR: database missing | 数据库不存在 | 检查主库数据库名称拼写,确认数据库已创建 |
ERROR: table missing | 表不存在 | 检查表名拼写,确认表已创建 |
ERROR: dial tcp ... connection refused | 无法连接主库 | 检查网络连通性和主库服务状态 |
ERROR: replication_consumer_id missing | 复制 ID 不存在 | 检查复制 ID 是否正确 |