人大金仓KingbaseES逻辑备份工具sys_dump实战解析
库里的表被人误删物理备份只留下一份上周日的全量剩下两天的数据靠人肉翻日志补回来——这种场面我见过不止一次。每次事后复盘问题都不在“有没有备份”而在“备份的粒度对不对、能不能挑着恢复”。物理备份是整库快照恢复就得整库回到某个时间点而逻辑备份最大的价值就是它输出的是“重建对象所需的信息”可以只恢复一张表、一个模式甚至可以拿到另一个版本的库上重建。在人大金仓 KingbaseES 这套体系里承担这个职责的核心工具就是 sys_dump。sys_dump 是 KingbaseES 自带的逻辑备份工具和客户端交互终端 ksql、恢复工具 sys_restore、全库导出工具 sys_dumpall 属于同一套客户端工具集。它能把一个库里的结构定义、数据内容、权限、注释、大对象等信息导出成可读的 SQL 文本或者压成自定义归档供后续恢复、迁移、比对使用。这篇文章面向已经能连上库、会写基本 SQL 的读者包括刚接手人大金仓的运维、做数据迁移的后端开发以及需要在容器化环境里编排备份任务的工程同学。下面我按“怎么选、怎么用、怎么不翻车”的顺序把 sys_dump 从参数到实战讲透。1. sys_dump 在 KingbaseES 备份体系里的坐标1.1 逻辑备份与物理备份的分工KingbaseES 的备份大致分成两条线物理备份和逻辑备份。物理备份走的是块级复制思路比如基于基础备份加 WAL 归档的方式把数据文件按页拷走恢复时整库回到某个一致点逻辑备份走的是对象级导出思路把表、索引、约束、数据一行行读出来转成 SQL 语句或归档格式。这两条线的差异不是“谁更好”而是“解决什么问题”。物理备份解决的是“整库灾难恢复”RPO 可以做到很低但代价是恢复必须整库、版本和平台基本绑死逻辑备份解决的是“对象级恢复与跨环境搬运”可以只捞一张表、一个模式可以跨小版本升降级代价是慢、占空间、恢复时需要重放 SQL 和重建索引。我的经验是两者必须同时存在而且逻辑备份的定位要写死在运维规范里物理备份保底逻辑备份用来做误操作恢复、版本升级前的留档、以及跨环境的数据交付。只做物理备份的团队遇到“只删了一张表”的场景往往要付出整库回滚的代价。1.2 sys_dump 与 sys_dumpall 的边界这是新手最容易误解的一点sys_dump 只负责一个数据库。它导出的是你指定的那个库内部的对象——模式、表、视图、函数、序列、索引、约束、触发器、权限、注释以及数据。但它不会带走集群级别的全局对象比如角色、表空间定义、以及“集群里一共有哪些库”。全局对象归 sys_dumpall 管。所以一个完整的、可以在空集群上重建的逻辑备份方案标准做法是先用 sys_dumpall 导出全局对象角色、表空间等再对每个业务库分别执行 sys_dump。只做后者恢复时会撞上一堆“role 不存在”“tablespace 不存在”的报错然后手忙脚乱去补建。还有一个细节sys_dump 的导出结果里默认会带上对象的所有者OWNER和权限GRANT。这在“同构恢复”时很方便但在“导到另一个环境”时就是麻烦制造者。所以跨环境导出时--no-owner和--no-privileges几乎是我的默认选项。1.3 什么时候我坚决不用 sys_dump说句实在话逻辑备份工具不是万能的有几种场景我会直接换方案。第一种是数据量特别大的库。sys_dump 是单线程读、单连接导出目录格式可以用-j并行但仍然是同一个快照下的多连接读取TB 级别的库跑一次可能要好几个小时而且这期间长事务会一直挂着阻碍 vacuum 回收旧版本行容易把库撑胖。这种库我优先用物理备份逻辑备份只对核心小表做定向导出。第二种是要求精确到秒的恢复点。逻辑备份只能回到“执行那一刻的数据状态”做不到任意时间点。要做到这一点必须靠物理备份加归档日志。第三种是库里有海量二进制大对象、或者大量未记录表unlogged table的场景——前者会让导出文件膨胀得离谱后者的数据本身就不该被当作持久数据来备份。第四种是数据库要下线做版本升级。这种场景下我通常做一次 sys_dump 留档但真正的手改方案是“新集群建好、逻辑导出导入、业务切换”而不是靠 sys_dump 单打独斗。2. 决定成败的参数sys_dump 常用开关逐个拆2.1 连接参数与认证方式连接类参数是 sys_dump 最基础的一层和 ksql 的用法保持一致习惯上可以直接套用参数作用实操注意-h指定服务端地址容器环境写容器名或服务名不要写 localhost-p指定端口确认目标端口不是连接池端口-U指定连接用户需要有目标表的 SELECT 权限建议专用备份账号-d指定目标库必填别指望默认库-w从不提示密码自动化脚本必须加否则任务会卡在交互等待-W强制提示密码手工临时导出时用脚本里不要出现关于密码脚本里硬编码是最差的做法既容易泄露也会被审计盯上。我的习惯是给备份脚本单独准备一个权限收紧到 0600 的密码文件放在专用账号的家目录下并在脚本开头显式设置文件权限。不同小版本对密码文件的命名和查找路径可能略有差异上生产前一定用目标版本自带的说明确认一遍别照抄别人环境里的写法。权限方面有个坑值得强调sys_dump 不是“有连接权限就能导全”。如果备份账号没有某张表的 SELECT 权限导出的归档里就静默少表日志里往往只有一条不显眼的报错甚至因为用了--ignore-version之类的参数被忽略掉。所以我的做法是给备份账号授予目标库的读权限或者直接用具备足够权限的专用角色并且在导出后做一次对象数量比对。2.2 输出格式与压缩先定格式再谈其他格式是 sys_dump 的第一个重大决策因为它决定了后续用哪个工具恢复、能不能并行、能不能只恢复一部分对象。四种格式各有明确适用面plain-Fp纯 SQL 文本可以用 ksql 直接执行也可以用编辑器看内容。缺点是恢复速度慢、不能并行、不能选择性恢复除非手工裁剪文件。custom-Fc自定义压缩归档默认就带压缩必须用 sys_restore 恢复。这是我最常用的格式支持并行恢复、支持只恢复指定表、支持查看归档清单。tar-Ft打包格式兼容性一般实际项目里用得最少我基本不用。directory-Fd目录格式每个表一个文件是唯一支持并行导出的格式配合-j能把导出时间显著压下来缺点是文件数量多传输和归档要整目录打包。压缩这块custom 格式默认就压缩-Z 0到-Z 9控制级别。我的经验值数据以文本为主的库用-Z 5到-Z 6压缩比和 CPU 开销比较平衡如果备份窗口很紧张、CPU 又富裕可以用-Z 1甚至不压把时间让给导出本身如果瓶颈是磁盘空间就直接上-Z 9代价是导出时 CPU 单核跑满。并行参数-j只对 directory 格式生效这点必须记住。很多人写了-Fc -j 4结果工具根本不并行还以为是磁盘慢。另外并行度不是越大越好每个 worker 都是一条独立连接、独立读取设置成 CPU 核数的一半到核数之间通常比较合理超过 IO 承载能力只会让整体更慢。2.3 对象范围过滤把“整库”缩到“我要的”真实工作里整库导出的比例其实没那么高更多时候是定向导出。sys_dump 的过滤能力相当够用-n 模式名/-N 模式名只导某些模式 / 排除某些模式。多租户环境下按租户模式拆分导出非常实用。-t 表名/-T 表名只导某些表 / 排除某些表。表名支持通配符比如-t log_2024*。--exclude-table-data表名导出这张表的定义但不导数据。日志表、历史大表用这招能把备份体积压下来一大截。-s只导结构不导数据做环境初始化和结构比对时用。-a只导数据不导结构适用于目标表已经建好的场景。--where条件配合-t使用只导满足条件的行做部分数据搬迁时非常高效。有一个细节很容易被忽略-t指定的表如果依赖某个序列作为默认值序列的当前值默认是会被导出的但如果只导数据到一张已存在的表序列状态不会自动同步恢复后可能出现主键冲突。所以做“只导数据”的操作后我会顺手核对一下目标库序列的当前值必要时手工修正。2.4 内容裁剪哪些东西该带、哪些该丢跨环境导出时下面这几个开关决定了恢复现场是顺畅还是鸡飞狗跳--no-owner不写所有者信息恢复时对象归执行恢复的用户所有。目标环境没有原角色时必须加。--no-privileges简写-x不导授权语句。目标环境角色体系不同时加。--no-tablespaces不写表空间。目标环境表空间名不一致时加能省掉一堆“表空间不存在”。--no-comments不导注释减少文件体积纯数据搬迁可以用。-b/-B包含 / 排除大对象。数据的 blob 用大对象存储时-B会直接丢数据这个开关一定要看清默认行为再决定。另外还有一对参数需要配合使用--clean会生成删除对象的语句--if-exists让删除语句带存在判断。单独用--clean恢复到一个有数据的库上会把原有对象删掉——这是有风险的务必确认清空是你要的效果。恢复前的库如果非空我更倾向手工确认后执行而不是让脚本带着--clean自动跑。2.5 锁与等待两个能救命的小参数--lock-wait-timeout时长是我强烈建议加的参数。sys_dump 在导出每张表之前要拿一次共享锁如果此时正好有个长事务持有该表的排他锁sys_dump 就会一直等下去。生产环境的备份任务卡住几小时往往就是这个原因。加上超时后工具会直接报错退出任务失败总比静默挂起好。--serializable-deferrable的作用是让导出等一个“安全快照”确保导出数据与后续的流复制或从库状态完全自洽。代价是可能等待更久甚至因为无法获得安全快照而直接失败。如果没有从库一致性方面的硬性要求我不会默认打开它。3. 一致性快照备份期间到底会不会锁表3.1 ACCESS SHARE 锁和 DDL 的对抗关系这是被问得最多的问题“跑 sys_dump 会不会锁表业务会不会被堵”准确答案分两半。sys_dump 在导出每张表时会申请 ACCESS SHARE 级别的共享锁这个锁和普通的增删改INSERT/UPDATE/DELETE完全兼容也就是说常规业务读写不会被它挡住读一致性靠的是一个可重复读快照不会读到半成品数据。但另一半要说清楚ACCESS SHARE 和 DDL 的排他锁互相冲突。备份期间如果有人执行 ALTER TABLE、DROP TABLE、TRUNCATE双方会互相等。结果是两种可能DDL 先执行成功sys_dump 拿到锁后发现表结构变了而报错退出或者 sys_dump 先拿到锁DDL 一直排队等等得久了可能连带把后面的业务查询一起拖住因为锁队列是严格顺序的。所以我的实际建议是把备份时间安排到业务低峰期同时在备份窗口内冻结该库的结构变更。如果变更流程必须随时可执行那就在备份脚本里加--lock-wait-timeout让备份宁可失败也不要变成雪崩的引信。3.2 长事务与膨胀备份自身带来的副作用不少人只关注“备份会不会挡住别人”忽略了“备份会不会伤害自己”。sys_dump 在导出全程保持一个可重复读快照这在数据库眼里就是一个超长事务。后果是这期间产生的所有死元组都不能被回收表的物理空间只增不减如果备份窗口长达数小时、业务写入又很密集库会出现明显的膨胀。处理思路有三条。第一尽量缩短导出时间能用 directory 格式加并行就用能把--exclude-table-data排掉的大表排掉就排掉。第二备份任务不要和自动清理任务错峰竞速两者抢 IO 反而都慢。第三对写入量巨大的核心库把备份拆成“低频全量 高频小表定向导出”的组合而不是每天雷打不动全库跑一遍。3.3 用数据说话量化备份对生产的冲击评估冲击最实在的办法不是拍脑袋而是留下证据。我做性能摸底时会关注三组指标备份任务自身的耗时和读速率数据库侧的活跃会话数和等待事件分布以及宿主机层面的磁盘读写延迟和队列深度。具体来说备份前记一次基线备份期间再采一次对比“平均读延迟”“IO 等待占比”“慢查询数量”这几个量。如果 IO 等待占比在备份期间明显抬头说明需要限速或挪窗口如果基本无变化那这套备份策略就可以放心跑。限速方面KingbaseES 客户端工具本身没有内置的带宽限制参数实操里我一般用操作系统的资源控制手段给备份进程降优先级——比如降低 CPU 调度优先级、限制磁盘 IO 权重或者用控制组把备份进程圈在一个资源配额里。这些手段不影响备份的正确性只是让它对在线业务更“客气”。4. 恢复链路sys_restore 与 ksql 的配合4.1 plain 格式只能走 ksqlplain 格式导出的是 SQL 文本恢复就是把这段文本喂给 ksql 执行。标准姿势是# 先建好目标库注意编码和排序规则要和源库一致 ksql -h 127.0.0.1 -p 54321 -U system -d target_db \ -v ON_ERROR_STOP1 \ -f /backup/target_db_20240601.sql这里的ON_ERROR_STOP1是关键不加的话 ksql 遇到错误只会打印一条消息继续往下跑最后你拿到一个“看起来执行完了”的库实际上少了一堆对象。加上它遇到第一个错误就中断便于定位。如果归档是用-C带 CREATE DATABASE 语句导出的可以省掉手工建库这一步但仍然要确认目标实例上没有同名库否则脚本会在建库那一步就报错。4.2 custom 与 directory 格式走 sys_restorecustom 和 directory 格式必须用 sys_restore 恢复常用参数组合如下-d 数据库名指定恢复目标库这个库必须已经存在。-j 并发数并行恢复能显著缩短时间前提是归档由多个表组成且 IO 撑得住。-L 清单文件只恢复清单里列出的对象做选择性恢复时用。--sectionpre-data|data|post-data分阶段恢复见下一节。-e遇到错误就退出脚本里建议加上。-v输出详细信息排错时打开平时关掉以免日志爆炸。sys_restore 有个特别实用的能力它能直接读取归档的目录清单。执行sys_restore -l /backup/xxx.dump会列出归档里所有对象和它们的编号。排错时我几乎第一步都是跑这个命令先确认“我想恢复的那张表到底在不在归档里”能省掉大量猜测。4.3 分阶段恢复为什么先灌数据后建索引能快一倍sys_restore 支持把恢复过程拆成三段这是性能优化的关键技巧pre-data 阶段建表、建序列、建函数等基础结构不建索引和约束。data 阶段批量灌入数据。post-data 阶段创建索引、主键、外键、触发器等。顺序调整的意义在于先把数据灌进去、再一次性建索引比“建好索引再逐行插入”快得多因为后者每插一行都要维护 B 树结构随机 IO 和 CPU 开销极大。数据量大、索引多的库用这种方式恢复时间差经常是成倍的。具体操作就是分三次执行每次带不同的--section参数中间不做别的干扰。要注意的是中间阶段库里处于“结构不全”的状态不要把业务连上来恢复完成、确认索引都建好之后再放流量。5. 恢复现场翻车实录几个真实报错与排查路径5.1 “role 不存在”和“必须是所有者”这两个连环坑最常见的报错是恢复过程中跳出一堆role xxx does not exist。根因很直白归档里带着所有者信息和授权语句目标环境没有这些角色。处理方式有两个方向任选其一。要么导出时加--no-owner --no-privileges从源头不带这些信息要么恢复前先把角色建好让脚本能顺利执行。另一种报错是权限相关的拒绝通常发生在用非超级用户恢复、而归档里包含需要高权限才能创建的对象时。这种场景我会先搞清对象的归属再用具备对应权限的账号恢复而不是一路加参数绕过去——绕过去的结果就是部分对象静默丢失。5.2 编码与表空间不一致引发的失败编码问题表现得很直接invalid byte sequence for encoding UTF8或者一堆乱码。根因通常是导出库和目标库的字符集不一致或者恢复时客户端的编码设置不对。我的做法是导出前先确认源库的编码建目标库时显式指定一致的编码和排序规则恢复会话里也把客户端编码对齐。表空间问题更容易踩归档里带着TABLESPACE xxx语句目标环境没有这个名字的表空间恢复直接中断。跨环境导出时加--no-tablespaces就能把这类麻烦挡在门外。如果确实需要保留表空间规划那就在恢复前把目标环境的表空间按同名建好。5.3 版本不匹配工具和服务的“代沟”sys_dump 有个硬性规则导出工具版本要大于等于被导出库的服务端版本。反过来的组合也就是用低版本工具去导高版本服务端通常会在连接或导出初期就失败。而归档文件也有版本标记用低版本 sys_restore 去读高版本生成的归档会报文件头不支持。所以跨版本恢复的正确路径是在目标环境里使用目标版本的客户端工具先做一次逻辑导入再通过数据库自身的升级流程处理不兼容的语法差异。生产环境里我见过有人直接拿旧客户端工具去导新库报错后加了一堆强制忽略参数最后拿到的归档根本不可用——这种节省最后都要加倍还回去。5.4 序列值和二进制大对象被漏掉这两个问题最阴险因为它们不报错只是“结果不对”。序列问题的表现是恢复后插入第一条数据就主键冲突一查发现序列当前值还是初始值。原因通常是恢复时用了-a或做了部分恢复序列状态没跟着数据一起走。我的复查手段很简单恢复完成后抽查几张核心表的序列当前值和源库对比。大对象问题的表现是表里有内容但存储二进制的字段是空的。原因通常是导出时用了-B或者没启用大对象导出。所以只要库里存在大对象列导出后我一定会检查归档的大小是否合理必要时用sys_restore -l看看有没有大对象条目。5.5 一套我常用的排错顺序被叫去救火时我不会看到报错就直接改命令而是按固定顺序走一遍用sys_restore -l列出归档清单确认目标对象在不在归档里以及归档是否完整。对照报错信息里的对象名和行号定位到具体是哪条语句失败。单独执行这条语句看真实错误是什么——很多报错信息里第一个错误只是最外层的表象。核对三件事目标环境的角色和权限、字符集和表空间、工具与服务的版本。确认是导出侧问题还是恢复侧问题再决定是重导还是补建环境。这套顺序的价值在于它把“猜”替换成了“验证”。我踩过的绝大多数恢复坑都在这五步里被定位出来真正需要重做导出任务的次数并不多。6. 把 sys_dump 做成能交付的备份任务6.1 脚本骨架与命名规范手工敲命令只能算验证能不能长期跑得住才叫方案。我的备份脚本一般包含这几块环境变量与密码文件设置、日志重定向、导出命令、退出码判断、结果校验、清理旧文件。导出命令本身我会固定成类似这样的形态sys_dump -h db_host -p 54321 -U backup_user -w \ -Fc -Z 6 \ --no-owner --no-privileges \ --lock-wait-timeout120s \ -d app_db \ -f /backup/app_db_$(date %Y%m%d%H%M).dump几个选择理由custom 格式方便后续选择性恢复中等压缩级别兼顾体积和时间不带所有者和权限让归档可以跨环境使用锁等待超时避免任务无限挂起。命名规范上我坚持把“库名 时间戳 格式后缀”写全绝不使用backup.dump这种名字。原因很现实出事的时候你需要在几秒钟内确认哪个文件是哪个库、哪个时间点的名字里不写清楚就得逐个打开看。6.2 校验与演练备份不做恢复验证等于没做我见过太多“每天都在备份、真要用时发现是空文件”的案例。所以脚本里必须加校验环节至少做到三件事第一检查退出码和文件大小。退出码非零直接告警文件大小和上次相比突然掉一半也要告警这往往意味着权限丢失导致少导了对象。第二检查归档可读性。用sys_restore -l读一遍归档清单能读出来、对象数量在合理区间才算这次备份基本可用。第三定期做恢复演练。这是唯一能真正验证备份有效性的手段。我的做法是每隔一段时间把最近一次备份恢复到一个临时库然后比对核心表的行数和关键字段校验值跑通之后再清理临时库。演练这件事做一次你就会发现不少隐藏问题——比如某个账号权限不够、某个对象依赖缺失、某个参数在生产环境有副作用。这些问题在真出事的时候暴露代价可就不一样了。6.3 保留策略与监控口径保留策略要结合数据重要性和存储成本来定。我的常规配置是日备保留两周周备保留两个月月备保留一年关键节点版本升级前、大变更前额外打一次永久标记。容量估算方式很简单单次归档大小乘以保留份数再留出 30% 的余量。监控口径上我盯四个指标备份任务是否按时启动、退出码是否为零、归档文件大小是否在正常波动范围、执行耗时是否突然拉长。耗时突然翻倍通常意味着数据量涨了或者出现了锁等待这是很值得提前介入的信号。7. 容器化环境下的 sys_dump 与 KWR 观测7.1 先找到镜像里的 sys_dump现在不少团队把 KingbaseES 跑在容器里备份脚本自然也要在容器环境执行。第一个问题就是工具在哪。不同镜像的安装路径不完全一样别凭记忆写路径进去找一次最省事docker exec -it kingbase_container bash find / -name sys_dump -type f 2/dev/null常见位置在安装目录的Server/bin下面。找到之后建议记下来或者直接把它加到 PATH 里脚本里就不用写死长路径了。另外要注意镜像里可能同时存在多个版本的工具用sys_dump --version确认一下避免出现前面说的版本不匹配问题。7.2 容器场景专属的几个坑容器化跑备份有几个坑和传统环境完全不同我逐个说。输出路径必须落在挂载卷上。直接在容器内把备份写到临时目录容器一重建备份就跟着没了。正确做法是把宿主机的备份目录挂载进容器或者用docker cp把文件拷出来然后立刻校验。交互提示会卡住任务。容器里docker exec默认没有终端任何需要输入密码的提示都会让任务静默挂住。所以脚本里务必加-w并通过密码文件或环境变量提供凭据绝不依赖交互输入。资源和并行度要匹配。容器通常设置了 CPU 和内存上限这时候把-j开到很大是没有意义的反而会因为争夺有限的 CPU 配额导致整体变慢。我的做法是按容器实际可用的 CPU 数量来设并行度一般不超过可用核数。时区和本地化设置要和数据对齐。容器默认时区经常是协调世界时如果业务数据里带时间戳并按本地时区理解导出的内容和恢复后的表现可能会有偏差。这个坑排查起来很费时间因为数据本身没错错的是理解方式。容器内版本与外部客户端不要混用。有些团队习惯在宿主机装客户端工具去连容器里的库这在版本一致时没问题但版本不一致时就会踩前面的坑。能用容器里自带的工具就用自带的。7.3 用 KWR 给备份期间的生产影响留证据最后说一个我觉得特别有价值的组合把备份任务和 KWR 结合起来看。KWR 是 KingbaseES 里的性能采样与报告机制思路是通过定期采集数据库运行状态的快照在需要的时候生成报告用来分析某个时间段内负载、等待事件、SQL 执行情况的变化。不同小版本里触发快照和生成报告的具体函数、扩展名称略有差异用之前按目标版本的说明确认一遍即可。和备份结合的方法很直接备份开始前打一个快照备份结束后再打一个然后对比这两个时间点的报告。重点看两件事一是 IO 相关的等待事件有没有明显抬头二是慢 SQL 数量有没有增加。如果备份窗口内这两项都很平稳说明现在的备份策略对业务无感可以放心跑如果明显异常那就该调整备份时间、降低并行度或者把部分大表改成定向导出。这比拍脑袋判断靠谱得多。我以前调优备份策略时就是靠这种前后对比发现某张大日志表占了整个备份 40% 的体积改成了只导结构不导数据备份时间直接从两个多小时压到四十分钟。我个人在实际操作中的体会是sys_dump 这个工具本身不难难的是把它放进一套完整的方案里——什么库用逻辑备份、什么时候跑、用什么格式、怎么校验、出问题怎么查。把这些都想清楚并落到脚本和规范里它才真正算得上一个能用得住的逻辑备份工具而不是一串出事时才想起来翻的命令。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →