ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

达梦数据库备份与恢复实战:从物理备份到时间点恢复全指南

达梦数据库备份与恢复实战:从物理备份到时间点恢复全指南 凌晨两点被电话叫醒大多数人都会烦躁但电话那头的一句话让我瞬间清醒“核心业务表被误删了能恢复吗”那一刻幸好我负责的达梦数据库(DM)实例提前做了全量备份并开启了归档模式靠着备份集加归档日志最终恢复到了误操作之前的时间点。这次经历让我彻底认同一件事对数据库运维来说备份与恢复功能不是官方文档里的一个章节而是DBA在灾难面前最后一道防线。这篇文章我把达梦数据库备份与恢复的核心机制、常用工具、实操命令和踩坑经验完整梳理一遍。物理备份、逻辑备份、联机备份、离线恢复、时间点恢复都会讲到。不管你是刚接手国产数据库的开发、运维还是从Oracle转过来的老DBA这篇文章都值得收藏。1. 生产环境里备份恢复为什么永远排在第一位1.1 备份不是“做不做”的问题而是“怎么保证能恢复”的问题很多刚接触数据库的同事问我备份不就是执行一条命令吗确实备份命令不难难的是灾难真正发生时你能按照预想把那批数据拿回来。我见过太多“备份做了恢复时却翻车”的案例备份文件拷贝到一半以为成功了真到要用的时候才发现备份集里缺文件一周前做过全备但没人注意到增量备份因为磁盘空间不足早就失败了归档日志只保留了两天结果误删发生在五天前恢复点根本够不到。这里我想说一个观点备份不等于能恢复。备份动作只是第一步备份集的完整性、归档日志的连续性、恢复步骤的可行性这些都要经过验证。就好比你买了一份保险如果从来没读过保险条款真出事时才发现理赔范围和你想的不一样那这份保险等于白买。数据库备份也一样不演练、不校验你心里那根弦就始终是松的。1.2 RPO和RTO决定了你的备份策略怎么定做备份策略之前先想清楚两个指标RPORecovery Point Objective恢复点目标和RTORecovery Time Objective恢复时间目标。RPO回答的问题是“最多能丢多少数据”RTO回答的问题是“多久能恢复上线”。这两个数字不是技术人员拍脑袋定的而是业务方给出的容忍底线。举个例子一套核心交易系统的RPO可能是30分钟意思是故障发生后最多允许丢30分钟的数据RTO可能是4小时意思是必须在4小时内让应用重新跑起来。为了实现RPO≤30分钟你就得保证归档日志切换足够频繁并且归档文件完整保留为了实现RTO≤4小时你就得提前准备恢复脚本、确保备份集校验通过、甚至要有一台备用机器做好冷备。我常用的一个策略表可以参考环境类型全量备份频率增量备份频率归档保留策略恢复目标核心生产库每周日 22:00每天 22:00保留7天RPO≤30分钟RTO≤4小时一般业务库每周日 22:00不做增量保留3天RPO≤24小时RTO≤8小时开发测试库每两周一次不做增量保留3天允许丢一天数据注意一个容易被忽视的点全量备份本身也有开销。大库全备会占用大量磁盘IO如果备份窗口选在业务高峰可能直接影响线上性能。所以生产库的全备通常会排在凌晨低峰期增量备份则可以更加频繁。1.3 达梦和Oracle备份体系的映射老DBA三分钟上手达梦数据库的备份体系对Oracle背景的DBA非常友好。很多概念和工具都能一一对应上dmrman对应Oracle的RMANdexp/dimp对应Oracle的exp/imp归档模式的概念也基本一致。上手达梦时你不需要把以前的经验推倒重来只需要认清不同工具之间的差异。最核心的差别是达梦把备份恢复分成两条线物理备份走dmrman和SQL Backup命令逻辑备份走dexp/dimp。物理备份处理的是数据文件级别的复制和还原逻辑备份处理的是数据内容级别的导入导出。很多生产环境出事时DBA第一反应是找RMAN换成达梦后就要立刻切换到dmrman这套思路。这个映射关系我写出来老Oracle DBA看一遍就能建立起大致的心理认知。2. 先分清备份类型物理、逻辑、归档模式各管什么2.1 物理备份是主心骨物理备份直接备份数据库的物理文件包括数据文件、控制文件、日志相关信息等。恢复时按原样把文件放回去相当于把整个数据库“拍张快照”。它的优点是速度快、可靠性高适合全库级别的灾难恢复缺点是备份集体积大而且与操作系统和硬件平台强相关。达梦的物理备份又分为脱机备份和联机备份备份类型执行条件工具/命令适用场景脱机备份实例关闭dmrman初始化前的基线备份、维护窗口备份联机备份实例运行且开启归档SQL BACKUP命令生产环境日常备份、不停机备份增量备份实例运行且开启归档SQL BACKUP INCREMENT缩短备份时间、控制备份体积脱机备份要求数据库处于关闭状态因为实例没起来数据文件不会发生变化备份一致性天然满足。联机备份则必须在归档模式下执行原因很简单备份过程中业务还在写数据数据文件是动态变化的光靠文件复制不能保证一致性必须结合归档日志把备份点之前的事务补齐。这也是为什么联机备份前DBA第一件事永远是检查归档。2.2 逻辑备份是万里长征的保险绳逻辑备份通过dexp工具把数据导出为dmp文件本质上是把表结构和数据内容以逻辑方式读取出来并存储。dimp工具负责把这些内容导回数据库。逻辑备份的优点是粒度很细可以只导出一张表、一个模式(Schema)或一个完整数据库导出的文件与物理平台无关Windows上导出的dmp文件可以导入Linux环境。缺点是速度慢数据量上去之后全库逻辑导出耗时很长不适合作为大规模灾难恢复的主力方案。它的典型场景是小库迁移、跨平台抽数、给测试环境准备数据集、误删单表后的精准救援。2.3 归档模式联机备份和时间点恢复的前提归档模式是达梦数据库里一个容易让新人产生误区的概念。简单来说数据库的redo日志是循环写的写满一圈后如果不归档旧日志就会被覆盖。开启归档后redo日志在覆盖前会先复制一份到归档目录相当于把数据库的每一次变更都记录在案。有了归档才能做时间点恢复。比如今天下午三点误删了一张表最近一次全量备份是凌晨两点那么全量备份只能把库恢复到凌晨两点的状态之后十几个小时的数据变动全部丢失。但如果归档日志齐全你可以在全量备份基础上让数据库把凌晨两点到下午两点五十九分的归档重新回放一遍恢复到误操作前一秒的状态。归档配置一般分两步修改dmarch.ini并设置dm.ini的ARCH_INI参数然后重启数据库实例。dmarch.ini里最基本的内容是定义归档目录和文件大小[ARCHIVE_LOCAL1] ARCH_TYPE LOCAL ARCH_DEST /dm/arch ARCH_FILE_SIZE 1024 ARCH_SPACE_LIMIT 0配置完成后可以通过查询V$DATABASE确认实例是否处于归档模式。检查结果一定要盯着看因为联机备份命令在非归档模式下会直接报错而很多人都是在备份失败的那一刻才想起来去查归档状态。3. 联机全量备份实操从命令到脚本一个都不能少3.1 备份前先检查这三件事执行联机备份前我习惯固定检查三样东西磁盘空间、归档状态、业务负载。磁盘空间是最容易踩坑的地方。备份集体积通常和数据库实际占用空间接近再加上一些缓冲余量建议备份目录的剩余空间至少是数据库总体积的1.5倍。检查命令很简单Linux下用df -h看一下目标目录挂载盘的可用空间即可。别嫌我啰嗦我因为没检查空间导致备份中途失败已经不是一次两次了。归档状态检查可以用disql登录数据库执行SELECT NAME, ARCH_MODE FROM V$DATABASE;ARCH_MODE值为1表示归档模式0表示非归档模式。如果处于非归档模式联机备份前必须先完成归档配置并重启实例。业务负载方面备份会扫描数据文件理论上会产生不小的IO压力尽量把备份窗口安排在业务低峰期。3.2 BACKUP命令逐字拆解达梦的联机全量备份命令非常直观。用disql登录到数据库后执行SQL BACKUP DATABASE FULL BACKUPSET /bak/DM_FULL_20240101.bak;这条命令的含义很清晰对数据库执行全量备份备份集输出到/bak/DM_FULL_20240101.bak目录。如果命令执行成功会看到类似“备份成功”的提示并在指定目录下生成备份集相关文件。BACKUPSET如果不指定路径达梦会默认把备份集生成在数据目录下的bak子目录里这个习惯不好正式环境建议永远显式指定绝对路径。增量备份的写法类似把FULL换成INCREMENT即可SQL BACKUP DATABASE INCREMENT BACKUPSET /bak/DM_INCR_20240102.bak;达梦的增量备份支持基于上一次全量或上一次增量系统会自动在备份集之间建立依赖关系。要注意的是增量备份依赖之前的完整备份链基准备份一旦缺失或损坏后面的增量备份全部作废。备份完成后可以在dmrman中执行LIST BACKUPSET查看备份集的详细信息包括类型、时间、依赖关系等。3.3 生产环境可用的备份脚本模板手工执行备份命令没问题但生产环境一定要脚本化。我提供一个自用的联机全量备份脚本模板参数改成你自己的环境即可#!/bin/bash # 达梦数据库联机全量备份脚本 BACKUP_BASE/bak DATE$(date %Y%m%d_%H%M%S) BACKUP_DIR${BACKUP_BASE}/DM_FULL_${DATE}.bak LOG_FILE${BACKUP_BASE}/backup_${DATE}.log export DM_HOME/opt/dmdbms export LD_LIBRARY_PATH${DM_HOME}/bin:${LD_LIBRARY_PATH} ${DM_HOME}/bin/disql SYSDBA/密码localhost:5236 EOF SPOOL ${LOG_FILE} BACKUP DATABASE FULL BACKUPSET ${BACKUP_DIR}; SPOOL OFF EXIT EOF if [ $? -eq 0 ]; then echo [INFO] backup success: ${BACKUP_DIR} ${LOG_FILE} # 可以在这里追加异地拷贝或对象存储上传命令 else echo [ERROR] backup failed ${LOG_FILE} exit 1 fi # 清理30天前的备份文件 find ${BACKUP_BASE} -name DM_FULL_* -mtime 30 -exec rm -rf {} \;脚本里有两个细节值得说。一是disql的SPOOL可以把执行过程完整写入日志排查问题时非常有用二是find清理老备份时必须确认没有任何增量备份还依赖这些要被删除的全量备份否则就是给自己挖坑。3.4 备份集校验命令平时不用关键时刻救命备份脚本执行成功后还有一步很多人会偷懒跳过校验备份集是否可恢复。dmrman提供了一个专门命令RMAN VALIDATE DATABASE /opt/dmdbms/data/DAMENG/dm.ini FROM BACKUPSET /bak/DM_FULL_20240101.bak;VALIDATE命令会检查备份集内文件的完整性确认备份集没有被破坏。我强烈建议把校验步骤也写进备份脚本备份完成后自动执行一次。虽然这会让备份流程多花几分钟但换来的是关键时刻“肯定能用”的信心。4. 恢复实战一整机恢复/环境重建dmrman离线恢复全流程4.1 恢复前必须知道的三个事实物理恢复不是把备份文件复制回去就行有几个前提必须先讲清楚。第一备份集跨平台不可用。Windows环境下做的达梦物理备份不能拿到Linux环境直接恢复x86架构的备份也不能指望拿到ARM环境直接恢复。遇到过有人把Linux上的备份集传到Windows测试机尝试恢复折腾半天最后发现平台不匹配白白浪费时间。跨平台恢复的唯一选择是走逻辑备份dexp/dimp。第二新环境的安装路径尽量和原环境保持一致。备份集里记录了数据文件路径如果新环境初始化实例时指定的数据目录变了恢复后可能还要处理路径不一致的问题。最稳妥的办法是安装目录、数据目录、实例名统统按照原环境重建。第三恢复顺序不能乱。物理恢复永远是先RESTORE还原数据文件再RECOVER应用归档日志最后启动数据库。有人把RECOVER和RESTORE搞反了或者恢复了数据文件就直接启动结果必然是数据库状态异常。这个顺序要刻在脑子里。4.2 从零开始的标准恢复步骤以Linux环境、整机故障后重建为例完整流程如下。第一步安装达梦数据库软件版本尽量和备份时一致。安装完成后用dminit初始化一个与原库同名的实例cd /opt/dmdbms/bin ./dminit PATH/opt/dmdbms/data INSTANCE_NAMEDAMENG这里初始化实例的目的主要是生成恢复所需的dm.ini文件。如果环境路径和原库一致恢复后不需要额外调整参数。第二步确认新实例处于停止状态然后启动dmrmancd /opt/dmdbms/bin ./dmrman第三步在dmrman中执行RESTORE把备份集里的数据文件还原到目标目录RMAN RESTORE DATABASE /opt/dmdbms/data/DAMENG/dm.ini FROM BACKUPSET /bak/DM_FULL_20240101.bak;第四步执行RECOVER。如果只需要恢复到全量备份那一刻可以继续从备份集恢复RMAN RECOVER DATABASE /opt/dmdbms/data/DAMENG/dm.ini FROM BACKUPSET /bak/DM_FULL_20240101.bak;如果归档日志完整想恢复到最新状态则从归档目录恢复RMAN RECOVER DATABASE /opt/dmdbms/data/DAMENG/dm.ini WITH ARCHIVEDIR /dm/arch;第五步退出dmrman正常启动数据库。到这里一个最基本的整机恢复流程就完成了。4.3 恢复完成后的验证清单恢复完成后最重要的是验证。没有验证的恢复不能叫恢复只能说“看起来启动起来了”。我每次恢复后必做四件事查看实例状态是否为OPEN而不是MOUNT或SUSPEND对核心业务表执行count查询和备份前的行数做比对查询最近一笔交易数据的时间点确认日志应用到位让应用做一轮冒烟测试确认连接、读写正常。另外提醒一句恢复成功后的数据库备份链和归档记录都已经改变。建议在处理完业务验证后立刻做一次新的全量备份把备份链重置到干净状态避免后续增量备份依赖混乱。5. 恢复实战二误删数据后的时间点恢复5.1 误操作场景设定假设一个具体场景今天是1月2日晚上开发同事在下午14:00执行了一次误操作把业务模式下的核心表TRUNCATE了。最近一次全量备份是今天凌晨2:00完成归档日志从凌晨2:00开始持续归档没有中断。目标是恢复到1月2日13:59:30的状态——也就是误操作发生前的最后一刻。这个场景在生产中太常见了。此时如果直接拿凌晨2:00的全量备份恢复凌晨2点到下午2点之间产生的所有业务数据都会丢失这是不可接受的。正确做法是全量备份加归档日志做时间点恢复。5.2 时间点恢复的完整命令序列时间点恢复同样在dmrman中执行RESTORE阶段和前面一样关键在RECOVER阶段增加UNTIL TIME参数RMAN RESTORE DATABASE /opt/dmdbms/data/DAMENG/dm.ini FROM BACKUPSET /bak/DM_FULL_20240102.bak; RMAN RECOVER DATABASE /opt/dmdbms/data/DAMENG/dm.ini UNTIL TIME 2024-01-02 13:59:30 WITH ARCHIVEDIR /dm/arch;UNTIL TIME后面的时间格式要精确到秒时区一般以服务器本地时区为准。RECOVER执行过程中达梦会读取备份点之后、指定时间点之前的归档日志并逐条应用最终把数据库回放到13:59:30那一刻。恢复完成后启动数据库导出被误删的核心表数据再导回到原生产库这是比较标准的操作路径。如果你的业务能接受整个库回退也可以直接把恢复出来的实例切为生产使用但大多数核心系统很难接受全库回退所以我更推荐“恢复到新实例导出目标表再导入原库”这种折中方案。5.3 时间点恢复的局限和替代方案时间点恢复并不是万能的。第一它是库级恢复不是表级恢复。即便你只误删了一张表整个数据库也会被回退到指定时间点这意味着这段时间里其他表的所有合法变更都会一并丢失。在并发业务非常复杂的系统里这种回退带来的次生伤害可能比误删数据本身还要大。第二它依赖完整的归档日志。归档缺失一段恢复就只能停在缺失点之前无法到达你指定的时间。第三如果增量备份链断裂比如中间的增量备份文件被清理了基于该链的恢复也会失败。所以对于“只想找回一张表”这种需求更安全的替代方案往往是把备份集恢复到一台备用实例从备用实例导出目标表再导入生产环境。这样既找回了数据又不影响生产库的实时状态缺点是备库需要时间准备。真遇到十万火急的故障时间点恢复依然是最直接的保底手段。6. 逻辑备份与迁移dexp/dimp的经典用法6.1 导出一张表、一个用户、一个库达梦的逻辑备份工具是dexp它和Oracle老版本的exp命令使用习惯几乎一模一样。最常用的导出模式有三种。导出整个数据库dexp USERIDSYSDBA/密码localhost:5236 FILE/bak/full_20240101.dmp LOG/bak/full_20240101.log FULLY导出指定模式dexp USERIDSYSDBA/密码localhost:5236 FILE/bak/schema_20240101.dmp LOG/bak/schema_20240101.log SCHEMASTEST导出指定表dexp USERIDSYSDBA/密码localhost:5236 FILE/bak/table_20240101.dmp LOG/bak/table_20240101.log TABLESTEST.T_ORDER这里的关键参数是SCHEMAS和TABLES。SCHEMAS指定用户/模式TABLES指定表名表名前要带上模式名。实际使用中我建议导出时一定加LOG参数否则执行过程没有任何日志出了问题根本不知道卡在哪一步。导出完成后去日志里看“成功终止导出”或类似提示再确认文件体积是否合理。6.2 导入注意权限、表空间、字符集对应的导入工具是dimp。导入时最常遇到的问题是目标库没有对应的用户和表空间。直接执行导入大概率会报错所以导入前先建好用户和表空间是一种良好习惯。基本导入命令dimp USERIDSYSDBA/密码localhost:5236 FILE/bak/schema_20240101.dmp LOG/bak/imp_20240101.log SCHEMASTEST如果目标环境里已经存在同名对象需要根据需求决定是替换还是跳过这可以从达梦手册里查TABLE_EXISTS_ACTION参数来调整。字符集不一致也可能导致导入乱码或失败遇到中文数据导入异常时优先检查源库和目标库的字符集设置是否一致。综合来说逻辑备份做迁移时一定要先在测试环境完整跑一遍别拿生产环境当实验田。6.3 物理备份和逻辑备份怎么配合物理备份是主线路逻辑备份是辅助线。物理备份恢复速度快、粒度大适合做灾难恢复主方案逻辑备份灵活、跨平台、可精细化操作适合做数据迁移和单表救援。打个比方物理备份就像把整个家搬进仓库恢复时整屋还原逻辑备份像是把存折、证件这类贵重物品单独打包需要时可以精准取出其中某一件。一个成熟的达梦运维体系两者都该保留而不是二选一。日常使用中可以定期用物理备份做基础保护遇到跨库迁移或单表同步时再用逻辑备份。7. 那些年我在备份恢复上踩过的坑7.1 备份目录磁盘被写满有一次生产库做全量备份我估算备份文件体积大概和数据库占用空间接近而备份盘剩余空间刚好是数据库体积的1.2倍觉得够了。结果备份执行到70%的时候报“磁盘空间不足”备份失败。更糟的是备份过程对生产库的IO产生了明显影响业务方紧跟着就来找人了。那次之后我定了一条规矩备份目录剩余空间至少是数据库总体积的1.5倍备份前必须用脚本检查不满足条件直接报警。另外备份盘一定要单独挂载别和数据文件放在同一块磁盘上否则备份时IO和空间的双重压力会让生产库吃不消。7.2 归档日志不清理库写不动了归档模式开启后归档文件会持续累积。我有一个客户环境归档目录空间设置得不合理ARCH_SPACE_LIMIT没设上限结果归档目录被打满数据库无法切换redo日志整个实例直接hang住。业务中断半小时后才找到原因清了一部分历史归档才恢复正常。这个坑的教训是归档目录必须独立规划空间大小要结合业务写入量估算同时要建立归档清理机制。清理归档前一定要确认目标归档已经不需要用于恢复比如已经完成了全量备份并且业务侧能接受归档对应时间段内的数据不回溯。生产环境中我通常会设置合理的ARCH_SPACE_LIMIT并配合外部定时任务做归档文件的归档和清理。7.3 备份集没有校验恢复时才发现文件少了有一回异地容灾需要恢复备份我拿了一个多月前的全量备份集执行RESTORE时报错提示备份集文件缺失。查了半天发现这个备份集在当初从生产机拷贝到异地时tar包只打包了一半而原始备份目录里的文件早就被清理了完全没了补救机会。从那以后“备份后校验”成了我的铁律。备份完成当天就在源机上用VALIDATE命令验证一次拷贝到异地后再验证一次。这不是强迫症而是备份文件这种数据平时看起来没区别恢复时少一个字节都可能全盘失败。7.4 增量备份链断了增量备份依赖全量备份这是原理决定的。但真正执行维护时很多人会忽视这种依赖关系。有一家客户运维同事看到备份目录快满了随手删掉了几份最老的全量备份结果当天晚上增量备份批量失败。排查之后才发现这些增量备份的基准备份被删了备份链整个断掉。备份文件的生命周期管理必须和备份链依赖关系放在一起考虑。删除任何全量备份之前你要先确认没有增量备份还依赖它或者干脆按日期批量整体清理。最简单的方式是每次清理只允许清理超过N天的整个备份链而不是单独删其中的某一环。7.5 恢复后应用连不上/卡住的排查还有一类问题是恢复流程走完了数据库也正常OPEN了但应用侧就是连不上。这类问题通常不在数据库本身而在环境配置服务端口没监听、防火墙拦截、hosts解析不对、应用连接池里还是旧地址。我会先用ps -ef | grep dmserver确认进程在跑再用netstat -lnp确认5236端口监听正常最后让应用侧检查网络连通性和连接串。如果数据库能连上但业务卡住那就要考虑锁等待了。查询V$LOCK等视图找到阻塞会话评估后结束掉对应的会话或事务。这一条虽然不完全属于备份恢复范围但恢复上线时遇到最多的问题恰恰是这种“半连接状态”所以也值得顺手写进排查清单。最后分享一个我自己的习惯每次新环境交付不管多忙我都会安排一次完整的备份-恢复演练把恢复步骤写成文档标注清楚哪条命令要改哪个路径。等真出事时你根本没有时间翻手册手熟和流程熟才是最大的保险。备份恢复这件事平时练得越多关键时刻就越值钱。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进