【金仓数据库产品体验官】_坏得起_实测:备份恢复、PITR 时间穿越与主备切换——KingbaseES V9R3C18 深度体验(三)

一、评估数据库,不能只看"跑得对"

第一篇验证了 JSON 与函数的语法兼容,第二篇搞清了驱动与协议的边界、窗口函数和动态 SQL 的成色。但任何 DBA 都知道,选型评估真正的分水岭在另一条线上------坏得起吗?

手滑删了表,能不能精确救回来?主库突然宕机,业务能不能几秒内切到备库?这篇就在同一台鲲鹏服务器(Ubuntu 22.04 + KingbaseES V009R003C018)上把这两件事做穿:sys_rman 全量/增量备份 → 现场删表 → PITR 按时间点恢复 → 流复制备库 → 故障切换。全程 9 张实拍截图,中途踩到的 5 个坑一个不藏------说实话,这些坑比一路全绿值钱得多。

二、侦察装备:sys_rman 是 pgBackRest 的企业级血统

先看随安装包给了什么:

sys_basebackupsys_dump/sys_dumpallsys_restoresys_waldumpsys_rman 一应俱全。重点是 sys_rman help 打出的命令集------stanza-createarchive-pushbackuprestoreinfoexpire......用过 pgBackRest 的人会当场认出这个血统(版本号 2.27 也对得上)。这是个好消息:pgBackRest 是 PG 生态里生产验证最充分的备份工具之一,支持压缩、增量、并行、PITR,比裸 basebackup 的备份体系高一个档次。

三、搭归档链路:第一个坑就在出厂配置

pgBackRest 系的备份依赖 WAL 归档。看出厂状态:

SQL 复制代码
SHOW archive_mode;      -- always
SHOW archive_command;   -- exit 0(占位命令,WAL 直接"假装归档成功"后丢弃)

坑 1:出厂 archive_mode=always ,而 sys_rman 只认 on 我最初以为 always 已经开了归档、改个 command 就能用,结果 stanza-create 直接报 ERROR [067]: archive_mode=always not supported------自家工具不支持自家出厂默认值。而 archive_mode 是重启级参数,所以"零重启接入备份"是做不到的,老老实实改配置重启:

SQL 复制代码
ALTER SYSTEM SET archive_mode = 'on';
ALTER SYSTEM SET archive_command =
  '/opt/Kingbase/ES/V9/Server/bin/sys_rman --stanza=main
   --repo1-path=/home/kingbase/kbbak
   --kb1-path=/opt/Kingbase/ES/V9/data
   --log-path=/home/kingbase/kbbak archive-push %p';

坑 2:archive_command 里必须带 --kb1-path KES 的归档进程传给 %p 的是相对路径(sys_wal/000...),不带这个参数时 archive-push 报 relative wal paths are used,WAL 的 .ready 文件默默堆积、备份卡到超时。坑 3:参数名文档与实现不同步。 sys_rman help 里写的是 --kb-path/--repo-path,实际运行要求带索引的 --kb1-path/--repo1-path(报错 option 'kb-path' must have an index),照着帮助文档敲命令是跑不通的。

排完这三个坑,链路就顺了:

check 通过意味着归档往返(push 进仓库、get 得回来)被真实验证过------这是备份可信的前提。

四、全量 + 增量:84MB 的库备成 11.6MB,7 秒

Bash 复制代码
sys_rman ... backup --type=full

84MB 的数据目录(2371 个文件)压缩落库 11.6MB ,耗时 7.3 秒。接着模拟业务继续写入(新增 2 名会员,表里 4 → 6 人),再做增量:

增量备份只花 1.4 秒 ,仓库里只多了 1.8MB ------info 里能看到 incr 挂在 full 的引用链上。对每天几百 GB 变更量的生产库,这个"全量打底 + 增量滚动"的结构就是备份窗口的生命线。

五、灾难现场与时间穿越:一次失败教会我的 PITR 精度课

好戏开场。先记住"这一刻",然后手滑:

SQL 复制代码
SELECT current_timestamp(6);   -- 2026-07-13 20:57:45.371602,存档
DROP TABLE member;             -- 灾难
SELECT count(*) FROM member;   -- ERROR: relation "member" does not exist

然后停库、PITR 恢复到手滑前一刻、重启:

Bash 复制代码
sys_ctl stop
sys_rman ... restore --delta --type=time \
    --target="2026-07-13 20:57:45.371602" --target-action=promote
sys_ctl start   # 回放 WAL 到目标时间点,自动提升上线

--delta 模式只比对差异文件,restore 本体 453 毫秒 ;启动后回放 WAL 精确停在目标时刻,验证查询:6 | 张伟,李娜,王强,赵敏,孙丽,周杰****------表连同 6 名会员完整穿越回来,删表操作如同没发生过。

但必须坦白:我第一次恢复失败了,表没回来。 排查数据库日志才看懂:

Plain 复制代码
starting point-in-time recovery to 2026-07-13 20:48:45+08
last completed transaction was at log time 2026-07-13 20:48:44.988160+08

那个 44.988 的"最后完成事务"就是 DROP TABLE 本身坑 4:MySQL 兼容模式下 now() 只有秒级精度且会四舍五入 ------我第一次用 now() 记录时刻,实际约 44.5 秒被记成了 45 秒,恢复目标落在了删表动作(44.988 秒)之后 12 毫秒,于是 WAL 回放把 DROP 也一起放了进来。换成微秒精度的 current_timestamp(6) 后一次成功(有趣的是 now(6) 依然只输出秒级,两个函数行为不一致)。PITR 场景下,恢复目标的时间精度必须高于事故操作的时间间隔,这一课在测试环境交学费,远好过在生产。

顺带一个小发现:--type=immediate(恢复到备份一致点)在这个版本会报 ASSERT: option 'target' is null,被强制要求带 --target------与上游 pgBackRest 行为不一致,用 --type=time 绕过即可。

六、主备搭建:license 边界与"克隆传染"

坑 5(本篇最重要的评估情报):开发版授权不含主备复制组件。 备库第一次启动直接 FATAL:

Plain 复制代码
FATAL: DataWatch is not supported by current license file,
       but primary_conninfo is set to not NULL
WARNING: max_connections should be less than or equal than 10 (restricted by license)

开发版 license(365 天那个)不支持 DataWatch(金仓的流复制/高可用组件),还限制最多 10 个连接。做 HA 评估请直接从官网下载"标准版/专业版/企业版-180 天"授权------我换上企业版授权后一切正常。这条信息在下载页上没有醒目提示,希望能帮后来者省半天排查。

第二个障碍是"克隆传染":sys_basebackup -R 会把主库的 kingbase.auto.conf 原样带到备库,里面躺着主库的 archive_command--kb1-path 指向主库目录,校验必炸)和之前 PITR 留下的 recovery_target_* 参数(备库会去找一条不存在的时间线,FATAL: recovery target timeline 3 does not exist)。解法是启动备库前追加覆盖这些继承参数:

Bash 复制代码
sys_basebackup -p 54321 -U system -D /opt/Kingbase/ES/V9/standby -R -X stream

cat >> /opt/Kingbase/ES/V9/standby/kingbase.auto.conf <<EOF
port = 54322
archive_mode = off
restore_command = ''
recovery_target_time = ''
recovery_target_timeline = 'latest'
EOF

(细节:recovery_target_action 是枚举参数,置空串会直接拒绝启动,跳过它即可。)

54321 主(is_standby = f)、54322 备(t),单机双实例主备就位------生产上把备库放到第二台机器,步骤完全相同。

七、复制验证与故障切换:0.7 毫秒延迟,一条命令接管

三连验证:主库写入 → 备库即查即得;备库写入 → 被只读保护拒绝;主库视角看复制状态:

Plain 复制代码
主库 INSERT 陈晨 → 备库立刻查到 143 | 陈晨 | 8800
备库 INSERT      → ERROR: cannot execute INSERT in a read-only transaction
sys_stat_replication → streaming | async | replay_lag 00:00:00.000731

回放延迟 0.7 毫秒 (同机零网络开销的理想值,跨机房会到毫秒~十毫秒级,但机制完全一致)。然后是最硬核的一幕------把主库 -m immediate 硬停(模拟掉电级故障),一条命令提升备库:

Plain 复制代码
sys_ctl -D .../standby promote
→ waiting for server to promote.... done / server promoted
→ is_standby: f
→ UPDATE member SET points = points + 100 ... RETURNING → 陈晨 | 8900

从主库死亡到新主接受写入,全程秒级。当然这是手动 promote;生产环境应部署金仓的集群管理组件做自动故障检测与切换(配合 VIP 或应用端多主机连接串),但底层机制正是这一套。

八、本篇结论:能力矩阵与踩坑清单

能力矩阵(均为实测):

能力 实测结果
全量备份 ✅ 84MB→11.6MB 压缩,7.3s
增量备份 ✅ 552KB、1.4s,链式引用
归档链路体检(check) ✅ push/get 往返验证
PITR 按时间点恢复 ✅ 微秒级 target,精确停在删表前,数据零丢失
流复制备库 ✅ replay_lag 0.7ms(同机)
备库只读保护 ✅ 写入被拒
手动故障切换 ✅ promote 秒级完成,新主立即可写

踩坑清单(现象 → 根因 → 解法):

# 解法
1 archive_mode=always not supported------出厂值自家工具不认 on 并重启
2 archive-push 报相对路径错误,WAL 堆积 archive_command 里加 --kb1-path
3 帮助文档写 --kb-path,实际要 --kb1-path 按带索引形式传参
4 PITR 目标用 now() 记录,恢复把 DROP 一起回放 MySQL 模式 now() 秒级四舍五入,用 current_timestamp(6)
5 备库 FATAL:license 不含 DataWatch / 连接数限 10 开发版授权不支持 HA,换官网企业版 180 天授权
5.1 备库继承主库 auto.conf 导致启动失败 启动前覆盖 restore_command/recovery_target_*/archive_mode

九、给金仓的建议(本篇干货浓度最高的部分)

  1. 出厂 archive_mode=always 与 sys_rman 不兼容,等于默认配置和自家备份工具打架------要么让 sys_rman 支持 always,要么出厂改 on,要么在文档里加显著警示。

  2. sys_rman help ** 的参数名与实现对齐**(--kb-path vs --kb1-path),照文档敲命令跑不通对新用户是硬伤。

  3. 下载页为各版本授权标注能力边界:开发版不含 DataWatch、限 10 连接,这两条信息值得放在授权文件下载按钮旁边,而不是让用户从备库的 FATAL 日志里发现。

  4. MySQL 兼容模式 now() 的秒级精度 在 PITR/审计场景是隐蔽风险,建议文档警示,或让 now(6) 真正输出微秒(当前 now(6)current_timestamp(6) 行为不一致)。

  5. sys_basebackup -R 可考虑自动清理/注释掉克隆自主库的 recovery 与归档参数,或在启动报错时给出指向性提示。

  6. restore --type=immediate 不应强制要求 --target(与上游 pgBackRest 语义不一致)。

十、系列总结

三篇走完,"从兼容到进阶"的完整评估路径闭环:

  • 第一篇(语法层) :JSON 与函数 12 项测 9 项全绿,INSERT()/FORMAT() 两个函数级差异,均有一行级替代方案;

  • 第二篇(协议层) :兼容在语法不在协议,迁移 = 换驱动 jar + 改 URL + 占位符 ?$N;窗口函数全绿;

  • 第三篇(运维层):备份/PITR/主备/切换能力完整且工程化(pgBackRest 血统),但默认配置、文档精度、授权说明这些"外围体验"还有明显打磨空间。

相关推荐
笃行3503 小时前
从兼容到进阶:驱动直连、窗口函数与动态 SQL 实测——KingbaseES V9R3C18 深度体验(二)
数据库
笃行3503 小时前
MySQL 的 JSON 字段迁到金仓还能用吗?——KingbaseES V9R3C18 JSON 操作符与函数兼容实测
数据库
IpdataCloud5 小时前
跨境AI金融风险怎么防?IP风险画像的实战应用指南
数据库·tcp/ip·金融·ip
Alan_756 小时前
API 接口慢调用根因定位:从 TCP 建连到数据库 IO 的全栈排查实战
数据库
多巴胺梦想家7 小时前
事务与并发控制:当多人同时操作数据库
服务器·数据库·oracle
howard20058 小时前
PostgreSQL起步
数据库·postgresql
秋田君9 小时前
QT_QT布局详解
开发语言·数据库·qt
可乐ea9 小时前
【Redis八股|第8篇】Redis 分布式锁原理与 Redisson 使用
数据库·redis·分布式·面试题·redis八股
李燚9 小时前
Eino devops 调试系统源码:GraphCompileCallback 怎么工作(第50篇-E36)
数据库·golang·agent·devops·graphql·aiagent·eino