单机版Kingbase放在生产环境里跑,很多团队一开始想得很简单:数据量不大、并发不高,一台服务器完全够用,不用上集群。但真正到了要恢复的时候才反应过来,平时备份都落在本机硬盘上,磁盘一坏,备份和业务数据一起没了。异机备份和恢复这件事,我建议你在数据库上线第一天就想清楚怎么做,而不是等故障发生之后再去翻文档。
这篇文章是我实际运维金仓单机库过程中沉淀下来的方法,覆盖逻辑备份、物理冷备、归档增量恢复三类方案,每类都会给出可以照抄的命令、路径规划和恢复步骤。接手了Kingbase单机环境、正在准备备份方案,或者已经出了故障需要紧急恢复的DBA、运维工程师,可以直接拿这里的思路去落地,有些坑我已经替你踩过了。
1. 异机备份的思路与适用范围
1.1 为什么必须是“异机”
单机数据库最大的风险其实不是软件本身,而是它所在的物理环境。服务器断电导致文件系统异常、磁盘出现坏道、机房进水、机器被盗、恶意程序把数据目录加密,任何一个场景都会把本机备份一起带走。我见过最典型的事故是:某台数据库服务器硬盘损坏,运维人员自信地说“不用怕,有定时备份”,结果备份文件就放在同一块磁盘的另一个分区里,数据恢复成了无米之炊。
所以“异机”这两个字的重点是:备份数据必须存放在另一台物理设备上,最好和源库不在同一台机器、同一个磁阵、同一个机柜。你可以理解成“不要把鸡蛋放在同一个篮子里”,虽然俗套,但确实是无数事故换来的教训。至少做到异地服务器上的独立磁盘目录;条件允许,可以再加一块移动硬盘或者对象存储做第二份离线副本。我不建议只依赖云上的对象存储,因为大目录冷备份上传耗时,恢复时要花大量时间下载,做不了分钟级的RTO。
1.2 单机场景下的备份选型逻辑
单机库没有备节点,所以备份方案本质上是在“数据完整度”和“操作复杂度”之间取舍。我习惯把方案分成三类:
| 方案 | 备份粒度 | 恢复速度 | 适用场景 |
|---|---|---|---|
| 逻辑备份 sys_dump | 库/表数据 | 慢 | 误删数据、迁移部分表、跨版本迁移 |
| 物理冷备份 | 整个数据目录 | 快 | 服务器整体损坏、需要完整还原 |
| 归档+全量备份 | 数据+WAL | 中等 | 需要恢复到任意时间点 |
逻辑备份适合保“内容”,物理备份适合保“环境”。我的建议是两者都做:每周物理冷备,每天逻辑备份,如果业务对丢失数据的容忍度很低,再叠加WAL归档。后面三个章节会分别展开讲这些方案的做法。
选型的时候不要一上来就追求最复杂的方案,先看你手里的停机窗口和RPO要求。举个例子,一个内部管理系统,每天凌晨跑批结束后允许停库半小时,业务能接受丢一天数据,那每天凌晨做一次逻辑备份就足够了;但如果是订单交易类库,哪怕丢一小时的订单都会引发客诉,就必须考虑物理备份配合WAL归档的增量恢复方案。先量化需求,再选方案,比盲目堆工具靠谱得多。
2. 备份前要做好的几件事
2.1 确认版本与字符集基线
动手备份前,先登录源库确认三件事:版本号、字符集、数据目录位置。版本不匹配是异机恢复失败最常见的原因,恢复端至少要装同版本的小版本,最好是同一安装包。
确认命令如下:
# 查看金仓版本 ksql --version # 登录后查看数据库信息 ksql -U system -d testdb -p 54321 SELECT version(); SHOW server_encoding; SHOW data_directory;把输出结果写进维护文档,尤其是字符集。曾经遇到过源库是UTF8,目标端为了省事装了默认GBK库,逻辑恢复时中文全部变成乱码,白白浪费了一个晚上的窗口。字符集在数据库初始化时定下来,后面很难改,所以异机恢复的目标端建库时,必须和源库保持一致。
另外确认一下系统用户的属主。金仓安装后会创建专门的用户,一般是kingbase,数据目录属主也必须是这个用户。恢复前如果发现目录属主不对,后续步骤全部都会在权限上报错。举个排查例子,解压备份后直接启动库,日志里报could not open file,第一反应往往是文件缺失,实际上八成是属主不对,chown -R kingbase:kingbase下去立刻就好了。
2.2 规划备份目录与保留策略
备份文件要有固定的落盘位置,我习惯在源库服务器上建/backup/dump、/backup/base、/backup/archive三个目录,分别放逻辑备份、物理冷备、WAL归档,目标机的/backup/incoming用来接收传输过来的文件。
目录规划的意义在于方便写脚本和定清理策略。保留周期不要拍脑袋,按磁盘容量和业务要求来算。经验公式是:备份空间约为当前数据量的1.5倍,归档空间按每天产生的WAL量乘以保留天数估算。比如数据目录20GB,每天归档1GB,保留14天,那/backup至少有20*1.5 + 1*14 = 44GB空闲。
清理策略用find配合 crontab 是最省事的:
# 每天凌晨执行:删除7天前的逻辑备份 find /backup/dump -name "*.dmp" -mtime +7 -exec rm -f {} \;这条命令放到脚本里要加判断,生产环境我吃过亏,磁盘写满导致备份任务连续失败三天才发现。建议给/backup单独挂分区,并加上磁盘使用率告警,超过80%就通知人工介入。备份目录的写权限也要控制好,尽量只让kingbase用户可写,避免其他脚本误清。
2.3 启用WAL归档
如果你打算做增量恢复,WAL归档必须提前打开,否则恢复时最多只能回到上一次全备的时间点,之后的数据全丢。在kingbase.conf中找到归档相关配置:
archive_mode = on archive_command = 'cp %p /backup/archive/%f'改完重启数据库生效。这里注意一点:archive_command里的命令只有数据库启动用户有写权限。如果/backup/archive属主不是kingbase,归档会静默失败,日志里出现archive command failed,但数据库不会停止,容易漏掉。
验证归档是否生效,可以手动切换一个WAL:
SELECT pg_switch_wal();然后去/backup/archive看有没有新文件。这一步是纯收益,哪怕你暂时只做逻辑备份,我也建议把归档打开,万一日后要用,不用再回头改配置重启库。单机版的归档本来就是轻量操作,CPU、磁盘开销都很小,真正影响性能的是归档网络路径,所以本地盘归档即可,不需要跨网络。
3. 方案一:逻辑备份与恢复
3.1 sys_dump 备份的关键参数
逻辑备份用金仓自带的sys_dump,用法和 PostgreSQL 的pg_dump非常接近。我最常用的命令:
export PATH=/opt/Kingbase/ES/V8/bin:$PATH sys_dump -h 127.0.0.1 -p 54321 -U system -d testdb -F c -f /backup/dump/testdb_$(date +%Y%m%d).dmp-F c是自定义格式,解压后支持sys_restore做选择性恢复,还能开启并行恢复,比纯SQL文本格式灵活得多。生产环境一律用-F c,不要偷懒用默认的plain格式,不然一个大库恢复出错要从头再来,而自定义格式可以只恢复出问题的那个对象。
如果库比较大,想加快备份速度,可以使用目录格式加并行:
sys_dump -h 127.0.0.1 -p 54321 -U system -d testdb -F d -j 4 -f /backup/dump/testdb_dir注意-j并行参数只能在-F d目录格式下使用,否则会报错。并行度不建议超过CPU核心数,否则备份过程中CPU被打满,影响业务查询。我遇到过并行开8,生产库的OLTP查询延迟直接飙了三倍,后来老老实实改成4。备份窗口再紧,也别拿业务响应速度去赌。
3.2 把备份传到异机
备份文件生成后,第一时间传到异机。传输工具我用rsync多于scp,因为支持断点续传和增量同步,网络抖动时不会整个文件重传:
rsync -avP /backup/dump/testdb_20250601.dmp kingbase@192.168.1.20:/backup/incoming/-P参数很关键,等于--partial --progress,传了大半断网的话,下次重跑会自动续传。传完不要直接信rsync,先做一次校验:
md5sum /backup/dump/testdb_20250601.dmp ssh kingbase@192.168.1.20 "md5sum /backup/incoming/testdb_20250601.dmp"生产上我吃过一次亏,当时机器负载高,rsync 报告传输成功但目标文件其实不完整,恢复执行到一半报错。从那以后,传输校验写进了备份脚本,宁可多花几秒钟,也不拿恢复演练赌运气。如果是超大文件,建议在传输期间避开业务高峰,否则网卡被打满,前端应用会跟着遭殃。
3.3 sys_restore 恢复与常见坑
恢复的第一步是准备目标数据库。逻辑备份不会帮你创建数据库本身,所以先建一个空库:
ksql -U system -p 54321 -c "CREATE DATABASE testdb_restore ENCODING='UTF8';"然后执行恢复:
sys_restore -h 127.0.0.1 -p 54321 -U system -d testdb_restore -j 4 /backup/incoming/testdb_20250601.dmp这里有几个常见的坑。第一次恢复时如果目标库里已经存在同名表,默认会报错,需要加--clean在恢复前先drop掉目标对象,但--clean要谨慎使用,确认当前库是专门恢复用的空库,不要在业务库上直接跑。
另一个坑是角色依赖。备份文件里记录了对象的属主,如果目标机上没有这个角色,恢复时会出现role "xxx" does not exist,解决方法是在恢复前用create role建好相同的角色,或者用sys_restore的--no-owner参数忽略属主,恢复完再统一授权。权限问题在逻辑恢复里非常高频,建议把常用账号清单和角色定义也纳入备份文件,跟着 dump 一起带走。
恢复完成后别忘了更新统计信息:
ksql -U system -p 54321 -d testdb_restore -c "ANALYZE;"逻辑恢复的数据文件是全新写入的,没有统计信息的话,查询计划会乱选,明明有索引却走全表扫描,这是恢复后“变慢”的最大原因,没有之一。
4. 方案二:物理冷备份与异机恢复
4.1 冷备份为什么最省心
如果业务允许停机,物理冷备份是单机场景下最简单、恢复成功率最高的方案。原理就是先把数据库正常停掉,确保数据目录里所有文件处于一致状态,然后把整个data目录复制走。
正常停库的方式:
# 方式一:命令行 /opt/Kingbase/ES/V8/bin/ksql -U system -p 54321 -c "CHECKPOINT;" /opt/Kingbase/ES/V8/bin/ksql -U system -p 54321 -c "SHUTDOWN;"有些版本不支持 SQL 方式停库,可以用sys_ctl:
/opt/Kingbase/ES/V8/bin/sys_ctl -D /opt/Kingbase/ES/V8/data stop -m fast停库后确认进程真的退出再打包,用ps -ef | grep kingbase检查,别急着手。我见过同事停库命令下去,服务进程还在做微秒级别的收尾,结果冷备了一半文件,恢复出来数据库起不来。冷备的“一致性”是整个方案的生命线,停干净再复制,这句话值得写在所有备份文档的第一行。
4.2 用 tar+rsync 做全量同步
小数据目录我建议直接打包压缩,再传异机,省网络带宽;大数据目录直接rsync,省解压时间。
# 方式一:tar打包后传输 cd /opt/Kingbase/ES/V8 tar -czf /backup/base/kb_data_20250601.tar.gz data # 方式二:rsync全量同步到异机 rsync -avP --delete /opt/Kingbase/ES/V8/data/ kingbase@192.168.1.20:/backup/base/data_20250601/用--delete时务必小心,它会删除目标目录里源端不存在的内容,在异机恢复场景里目标目录一般只放这一份数据,没问题,但如果你把它指向了正在使用的数据目录,会酿成事故。另外,rsync 前必须确认源库已经停稳,否则文件还在变化,同步出来的目录是不一致的。
大目录同步时也可以排除日志目录,比如pg_log里积累了几个月的大日志文件,对数据库恢复没有帮助,却会拖慢传输速度。用--exclude参数排除即可,恢复时新库会重新生成日志。这个细节能省不少时间,尤其是跨机房传输的场景。
4.3 目标机恢复步骤
拿到物理备份后,在异机恢复的核心是“让新机器按原路径和原属主把数据目录用起来”。以tar包为例,完整步骤如下:
# 1. 安装好同版本金仓,使用系统默认初始化后的目录作为参照 # 2. 停掉目标机上的数据库服务 /opt/Kingbase/ES/V8/bin/sys_ctl -D /opt/Kingbase/ES/V8/data stop -m fast # 3. 解压备份覆盖数据目录 tar -xzf /backup/incoming/kb_data_20250601.tar.gz -C /opt/Kingbase/ES/V8/ # 4. 删除残留的进程文件,否则启动必失败 find /opt/Kingbase/ES/V8/data -name "postmaster.pid" -delete # 5. 修正属主 chown -R kingbase:kingbase /opt/Kingbase/ES/V8/data # 6. 启动数据库 /opt/Kingbase/ES/V8/bin/sys_ctl -D /opt/Kingbase/ES/V8/data start启动后验证端口、进程和业务表数据,然后马上再打一个当前的物理备份,作为恢复成功后的新基线。
补充一个细节:如果目标机路径和源机不一致,比如源机是/opt/Kingbase/ES/V8/data,目标机装在/home/kingbase/data,物理备份恢复后大概率会因为路径不一致启动失败。原因是数据目录里的部分配置文件会把绝对路径写死。这种情况优先考虑把目标机也整改成相同路径,而不是去改一堆配置文件,省时也稳妥。如果没法改安装路径,就检查kingbase.conf里的data_directory、hba_file等参数,把路径调整到实际位置。
5. 方案三:基于归档的增量恢复思路
5.1 全备加归档的组合
只恢复全备只能回到备份时刻,丢失备份之后所有的业务数据。若想做到接近实时的RPO,需要把WAL归档和全备结合起来。
逻辑上是这样:先做一次物理全备,之后持续保留WAL归档,恢复时先回放全备,再应用全备之后生成的所有归档日志,就能把数据推到故障发生前的最后一刻。
实际操作中,全备可以是第4节讲的冷备份,也可以是官方备份工具生成的备份集。官方工具功能更全,但部署配置成本也相对高,我在生产中至少保留一套“冷备+归档”的手动恢复方案作为兜底手段,即使哪天官方工具出了问题,依然能手工恢复。两条腿走路,才敢说恢复方案是可靠的。
5.2 恢复到任意时间点的思路
把冷备解压到目标机的数据目录后,在数据目录下准备归档恢复参数。金仓的恢复机制和PostgreSQL同源,旧版本习惯用recovery.conf,新版本支持把恢复参数合并进kingbase.conf。核心配置如下:
restore_command = 'cp /backup/archive/%f %p' recovery_target_time = '2025-06-01 14:30:00'restore_command负责把归档文件复制成待回放的WAL段;recovery_target_time告诉数据库回放到指定时间点后停止。没有recovery_target_time时,数据库会把归档全部应用完,恢复到最后一份归档对应的时间点。
配置完成后正常启动数据库,数据库进入恢复模式,结束后会自动生成recovery.done之类的标记文件。从运维视角看,这类恢复的关键在于:归档目录必须连续完整,中间缺失任何一个WAL段,恢复就会中断。归档文件的连续性要用脚本定期检查,比如记录每个段文件名,第二天核对数量和命名序列。这个检查脚本别省,归档断档往往不是个例,可能就是灾难的开始。
5.3 验证恢复结果
时间点恢复最容易犯的错误是恢复完直接看“能启动”就宣布成功。启动成功只能说明恢复过程没挂掉,不代表数据是对的。
我每回都做三件事:查日志文件里有没有recovery complete关键字,查关键业务表的最大时间戳,再抽查几条最近半小时写入的数据。比如订单表,恢复前最大订单时间是14:28,恢复后查出来应该是14:28之前的数据,14:28之后不存在,才说明时间点控制生效。
如果发现恢复出来的数据不对,基本都是recovery_target_time时区写错了,金仓默认按数据库时区解释这个时间,最好在时间后面明确标明时区,比如2025-06-01 14:30:00+08。这个坑我在演练的时候踩过,连续两次恢复结果都多出了半小时的数据,排查了很久才发现是时区理解偏差。
6. 一次完整的异机恢复演练
6.1 演练准备
备份方案写得再好,不演练等于白做。我会在测试机上搭一整套和生产相同版本的Kingbase,用生产权限的备份文件做一次完整的异机恢复。
演练前准备好三样东西:恢复文档、备份文件、目标机环境。文档里写清源库IP、数据目录、版本、字符集、备份文件位置、恢复步骤,每一步都给出命令。目标机要提前装好同版本数据库,测试端口不被占用。
如果你打算让新来的同事也能在紧急时刻上手恢复,演练文档最好做到“照着敲命令就能跑完”。我在文档里会标注每个步骤的预期输出,比如启动后应该看到什么日志、端口监听在哪里。这样新人第一次参与演练也不会慌,真出故障时团队才不至于围着一台机器干瞪眼。
6.2 模拟故障与执行恢复
演练场景通常是:源机数据目录损坏,假定磁盘不可用,直接开始恢复。我在测试环境的操作顺序如下:
# 1. 确认源机备份文件已经传到目标机 ls -l /backup/incoming/kb_data_20250601.tar.gz # 2. 停止目标机原有数据库服务 sys_ctl -D /opt/kbtest/data stop -m fast # 3. 备份目标机原有数据目录(防止演练失败无法回退) mv /opt/kbtest/data /opt/kbtest/data_bak_$(date +%Y%m%d) # 4. 解压生产备份到新数据目录 mkdir -p /opt/kbtest/data tar -xzf /backup/incoming/kb_data_20250601.tar.gz -C /opt/kbtest/ # 5. 清pid文件并修正属主 find /opt/kbtest/data -name "postmaster.pid" -delete chown -R kingbase:kingbase /opt/kbtest/data # 6. 启动数据库 sys_ctl -D /opt/kbtest/data start执行过程中我习惯把每一步耗时记录下来。比如解压15分钟、启动2分钟、数据校验10分钟,这些数字是后续评估RTO的真实依据,比拍脑袋估算靠谱得多。每次演练耗时最好只降不升,如果哪次环节出现了异常波动,说明环境或脚本有变化,要当场定位,否则实战时就可能卡在同一个地方。
6.3 演练后的检查
恢复成功不等于演练通过。我还会做应用连通性测试:用一个模拟的应用账号连到目标库,执行常用的增删改查,确认权限、序列和约束都正常。物理恢复经常在权限和配置文件上出小问题,SQL能跑通才算真的可用。
演练结尾我会给本次演练打一个结论:RTO是多少、RPO是多少、步骤里哪一步耗时最长、哪一步容易出错。这些记录积累三到四次以后,整个恢复操作会变成肌肉记忆,真出故障时根本不用翻文档,闭着眼都能按顺序执行完。把演练记录也归档保留,下次优化时拿新旧对比,才知道哪些改动真正提升了恢复效率。
7. 常见问题与排查实录
7.1 问题速查表
把异机备份恢复里我遇到的高频问题整理成一张表,放在维护文档首页,你会发现绝大多数故障都可以在半小时内定位。
| 现象 | 可能原因 | 处理办法 |
|---|---|---|
恢复后启动报postmaster.pid相关错误 | 数据目录还残留进程文件 | 删除所有postmaster.pid后启动 |
| 启动后端口被占用 | 目标机旧实例没停干净 | 用ss -lntp查端口,处理旧进程 |
| 逻辑恢复报角色不存在 | 备份文件中的对象属主缺失 | 恢复前建好角色,或恢复时加--no-owner |
| 备份文件校验不一致 | 传输中断、磁盘故障 | 删掉重传,用rsync的--partial续传后一定要校验 |
| 归档恢复时找不到WAL段 | 归档不连续或cleanup误删 | 检查归档目录,从备份介质找回缺失段 |
| WAL归档失败但库正常 | archive_command无写权限 | 检查归档目录属主和权限,手动执行归档命令 |
| 恢复后查询特别慢 | 统计信息缺失 | 执行ANALYZE; |
这张表里的问题,十个有八个都是“流程遗漏”而不是“技术难题”。比如不删进程文件、不校验传输、不更新统计信息,每一条都能在主流的恢复脚本里找到对应的步骤。如果你的恢复脚本也能保证这些动作自动执行,故障基本就提前消灭了一半。
7.2 我踩过的三个坑
第一个坑是恢复后不删postmaster.pid。当时刚从tar包解压完,直接启动目标库,日志报了“lock file already exists”,我第一反应是端口冲突,查了半天才发现是解压出来的数据目录里带着源机的进程文件,目标机进程ID对不上,删掉之后一次就起来了。现在我把这条写进了所有恢复脚本的固定步骤,再也没踩过第二次。
第二个坑是scp半夜断网。有一次凌晨跑备份传输,scp传到97%网络断了,脚本没有做完整性校验,第二天恢复测试怎么都报文件损坏。后来把传输全部改成rsync加md5sum校验,并且传输脚本检测到校验失败时自动重传3次,再失败就报警。从那以后,传输环节几乎没有再出过事。网络传输永远不要只看命令退出码,校验和才是终审。
第三个坑是恢复完忘了analyze。逻辑恢复了一整套业务库,看到数据行数对得上就宣布成功,结果业务方第二天反馈查询极慢,定位后发现优化器全在走全表扫描,因为恢复后的表没有任何统计信息。跑一遍ANALYZE之后查询立刻恢复正常。现在我把ANALYZE写在sys_restore后面,作为恢复流程的固定收尾动作。给恢复流程做“粘贴即执行”固定脚本,最大的价值就是把这类低级错误从流程里摘除。
8. 收尾:一点个人体会
备份方案的价值不在于备份文件有多大、脚本写得多花哨,而在于恢复操作能不能在预期时间内跑通。我见过太多团队把备份任务当成例行公事,crontab一挂就再也不管,直到真出事才发现备份是坏的。
我现在的习惯是:备份脚本不仅要在源机跑,还要在异机的恢复环境里每个月完整演练一次,每次演练都记录RTO和RPO。如果某次演练超过两小时,就说明恢复流程里还有可以优化的环节。金仓单机库本身不复杂,真正的复杂度都在异常处理和路径规划上,把演练做熟了,你的备份才真正有兜底的意义。