
我最早接触达梦数据库DM的时候最头疼的不是SQL语法差异而是备份这件事。数据库跑在业务系统后面白天不能动晚上要自动备份备份文件还得定期清理不然磁盘迟早被撑爆。公司有一台测试库就因为只配了备份没配清理半年下来备份目录把数据盘塞满了最后数据库直接只读业务全部卡死。那次事故之后我把达梦数据库的定时备份和清理备份任务彻底梳理了一遍从手动执行到自动调度从备份策略到清理策略形成了一套可以直接照搬的落地方法。这篇内容主要面向两类读者一类是刚接手达梦数据库运维、需要尽快把备份机制建起来的同学另一类是已经在用其他数据库比如Oracle、MySQL想了解达梦在备份调度上的差异和坑位的朋友。我会把达梦数据库备份清理的核心逻辑、实际操作步骤、常见问题都展开讲不需要你有多深的达梦基础跟着做就能在自己环境里复现。1. 备份和清理任务的整体设计思路很多人在配定时备份的时候只想着“怎么把备份跑起来”但很少先想清楚“备份策略本身合不合理”。达梦的备份和清理其实是一套组合拳备份负责兜底数据安全清理负责控制成本磁盘空间、管理成本。两者拆开配置迟早会出问题。1.1 备份策略先搞清楚你要备份什么达梦数据库的备份体系从层级上看分为物理备份和逻辑备份。物理备份又分为全量备份、增量备份基于上一次增量或全量的LSN增量。从实际使用频率来看绝大多数生产环境最常用的是全量备份归档日志备份的组合数据量特别大的库才会引入增量备份。我给你算一笔账你就知道备份策略该怎么定了。假设一个业务库的纯数据量是500GB每天产生归档日志约20GB如果每天做一次全量备份备份文件按压缩后约0.6-0.7倍原始体积估算一天约350GB保留7天就是2.4TB左右。如果每周一次全量 每天增量 每天归档全量压缩后350GB 每天增量平均30GB 归档20GB保留两周约1TB出头。很明显数据量小的库可以天天全量省心数据量大的库建议用“周全量日增量”的节奏。另外备份前必须确认归档模式是开启的否则就算你做了备份崩溃恢复时可能也无法恢复到最新状态。达梦里可以用SELECT ARCH_MODE FROM V$DATABASE;查看返回ARCHIVE就是已开启返回NOARCHIVELOG就需要在mount状态下打开归档并配置归档目录这一步不做后面一切都是无根之木。备份保留周期也要提前定好常见做法是“本地保留7天 异机/云存储保留1个月”。注意这里说的保留周期不是备份完之后不管了而是要和清理策略联动我们下面详细说。1.2 清理策略为什么备份完必须马上考虑清理清理备份这件事很多人没当回事觉得“磁盘不够了再删不就行了”。但真实场景里等你发现磁盘不够的时候往往已经晚了——备份任务会因为空间不足失败数据库可能因为写不进日志而挂起业务直接受损。我把清理策略总结成三个原则第一清理必须和备份放在同一个调度体系里。不是手动想起来才清理而是每次备份任务跑完之后自动触发清理逻辑。第二保留策略要有明确的数字指标。比如“全量备份保留最近4次增量备份保留最近7天”。这样无论备份任务跑得顺不顺利磁盘占用都是可控的。第三清理逻辑要能被复查。也就是说你到底清掉了哪些文件、剩下了哪些文件要有日志可查。手动rm命令一时爽出问题排查火葬场这个后面在常见问题部分细说。1.3 两条实现路线数据库作业 vs 操作系统定时任务达梦定时备份的实现方式业内主流的有两种路线A数据库内部作业用的是达梦的作业系统DBMS_JOBOracle风格。这种方式适合“不想依赖外部环境”的场景——只要数据库在跑备份作业就会按计划执行不需要操作系统层面额外配置。它的缺点是备份状态不好观测作业失败后如果没有配置告警你可能很久都不知道备份挂了。路线B操作系统定时任务 disql/dmrman脚本Linux用crontabWindows用任务计划程序。这种方式灵活性强可以在备份命令前后自由扩展逻辑比如先检查磁盘空间、再执行备份、然后清理过期文件、最后写日志也方便接入现有的监控告警系统。缺点是和操作系统绑定数据库所在主机本身挂了备份也就无从谈起。我个人的实践体会是生产环境首选路线B尤其是当你有多个实例、多个备份目录需要统一管理时脚本的灵活性远胜数据库作业。但如果是小环境、单实例、图省事路线A也能用需要把作业失败后的告警想办法补上。下面两部分我会把两条路线的具体实现都走一遍你可以按需选择。2. 从手动备份到定时执行让备份任务自己跑起来在配置任何定时任务之前我强烈建议你先手动执行一遍备份命令确认命令本身没问题、目录权限没问题、备份产物能正常生成。跳过这一步直接配定时等出了事再来排查很难分清是命令的问题还是调度的问题。2.1 先手动跑通一条备份命令达梦执行物理备份的常用入口有两个一个是disql里执行BACKUP DATABASE语句另一个是用专用的备份恢复工具dmrman。对于全库备份disql方式更简单直观。打开终端用SYSDBA账号登录数据库实例disql SYSDBA/SYSDBA_PASSWORDlocalhost:5236执行全量备份BACKUP DATABASE FULL BACKUPSET /dm_data/backup/full_bak_20250101_000001;这条命令的意思是对数据库做一次全量备份FULL生成的备份集目录名称为full_bak_20250101_000001。执行成功后在那个目录下会生成备份集相关文件。你可能会问每次起个手动备份集名字还能接受定时任务里怎么动态生成文件名答案是使用DISK_PATH加时间格式的方式。我习惯用shell脚本先生成带日期时间的备份集名再传给disql执行。比如BACKUP_DIR/dm_data/backup BACKUP_NAMEfull_$(date %Y%m%d_%H%M%S) $DM_HOME/bin/disql SYSDBA/SYSDBA_PASSWORDlocalhost:5236 EOF BACKUP DATABASE FULL BACKUPSET $BACKUP_DIR/$BACKUP_NAME; EXIT; EOF这样每次生成的备份集目录名都不同方便后续清理时按时间筛选。这里有几个关键点要提醒你必须在本地或远程能连上实例。如果disql都连不上备份任务绝对跑不成。经常有人遇到DBeaver连不上达梦或者Navicat连接报驱动错误那多半是驱动版本或者URL写法的问题我们在第4部分统一讲排查。备份目录的权限必须属于dmdba用户达梦通常以dmdba运行不然会报权限不足。你可以在Linux里用ls -ld /dm_data/backup确认。大库备份建议加上压缩参数COMPRESSED和PARALLEL例如BACKUP DATABASE FULL BACKUPSET /dm_data/backup/full_20250101 COMPRESSED PARALLEL 4;并行度根据CPU核数合理设定不是越高越好太高了反而会把IO和CPU都打满影响业务。2.2 用DBMS_JOB在数据库内部配置定时备份如果你决定用数据库内部作业那么在达梦里就是走DBMS_JOB包。和Oracle的DBMS_JOB很相似如果之前用过Oracle上手几乎无成本。创建定时备份作业的完整示例DECLARE JOB_ID INT; BEGIN DBMS_JOB.SUBMIT( JOB JOB_ID, WHAT BACKUP DATABASE FULL BACKUPSET /dm_data/backup/full_auto;, NEXT_DATE TRUNC(SYSDATE) 1/24, INTERVAL SYSDATE 1 ); COMMIT; END; /解释一下这个示例NEXT_DATE是第一次执行时间TRUNC(SYSDATE)1/24表示今天凌晨1点INTERVAL SYSDATE 1表示每隔24小时执行一次。如果你想每天凌晨2点运行就把1/24改成2/24。作业创建之后可以在系统视图里查看SELECT JOB, WHAT, NEXT_DATE, INTERVAL, BROKEN, FAILURES FROM DBA_JOBS;几个注意事项JOB默认不是持久化的如果数据库重启作业可能会丢失取决于配置。生产环境建议对作业做额外配置或者干脆用外部脚本方式避免这种不确定性。作业里写SQL语句时要特别注意单引号转义上面示例里一行一撇、两行两撇折腾得很。如果SQL写错了作业执行会失败而且不会立刻报错要去DBA_JOBS看FAILURES字段。作业是跑在数据库进程里如果备份时数据库并发很高可能会对实例产生额外负载。建议错峰执行。作业里最好使用绝对路径的备份目录避免环境变量问题。这个方式比较适合不想写shell脚本、一切都要在数据库内部搞定的场景。但从可观测性看我不太推荐生产环境纯靠DBMS_JOB跑备份这里的关键问题在于“数据库正常才跑数据库挂了没人跑”你无法在数据库层面之外对备份状态做监控。2.3 用shell脚本加crontab实现定时备份推荐这是我最推荐的方式。先写一个完整的备份脚本再通过crontab调用。脚本示例dm_backup.sh#!/bin/bash # 达梦数据库定时备份脚本 # 使用方法在crontab中配置定时执行 export DM_HOME/dm/dmdbms export LD_LIBRARY_PATH$DM_HOME/bin:$LD_LIBRARY_PATH DB_USERSYSDBA DB_PWDSYSDBA_PASSWORD DB_HOSTlocalhost DB_PORT5236 BACKUP_BASE/dm_data/backup BACKUP_DIR$BACKUP_BASE/full_$(date %Y%m%d_%H%M%S) LOG_FILE$BACKUP_BASE/backup_$(date %Y%m%d).log # 创建备份目录如果不存在 mkdir -p $BACKUP_BASE # 记录开始时间 echo [$(date %Y-%m-%d %H:%M:%S)] 开始备份到 $BACKUP_DIR $LOG_FILE # 执行disql备份 $DM_HOME/bin/disql $DB_USER/$DB_PWD$DB_HOST:$DB_PORT EOF $LOG_FILE 21 BACKUP DATABASE FULL BACKUPSET $BACKUP_DIR COMPRESSED PARALLEL 4; EXIT; EOF # 判断备份是否成功 if [ $? -eq 0 ]; then echo [$(date %Y-%m-%d %H:%M:%S)] 备份成功: $BACKUP_DIR $LOG_FILE else echo [$(date %Y-%m-%d %H:%M:%S)] 备份失败请检查! $LOG_FILE exit 1 ficrontab配置示例每天凌晨1点00分执行0 1 * * * /dm/scripts/dm_backup.sh /dm/scripts/dm_backup_cron.log 21几点经验脚本里的LD_LIBRARY_PATH一定要加。达梦的客户端工具依赖动态库不设置环境变量直接在crontab环境下执行很容易报libdmoci.so找不到之类的错误。这是新人最容易踩的坑没有之一。crontab环境比交互shell环境要干净很多PATH、LD_LIBRARY_PATH都得在脚本内显式指定。不要指望crontab能读到你在/etc/profile里设置的环境变量。备份日志要单独放。我习惯按天生成日志文件这样查看历史备份情况只用看当天的日志就行。也可以把日志统一写到syslog方便接入日志平台。在Windows环境下的做法类似用bat或PowerShell脚本再配任务计划程序。我遇到不少Windows达梦测试环境的同学用任务计划程序跑一个包含disql备份命令的bat文件效果和crontab一样。需要注意的就是bat里的路径分隔符和引号转义之前有过案例路径没加双引号备份目录含空格导致命令失败。3. 清理备份任务别让备份把磁盘吃满备份文件越来越占地方是不可逆的所以清理操作必须自动化和策略化。清理的核心问题是什么能删、什么不能删、怎么删才安全。3.1 用dmrman管理备份集并删除过期备份达梦自带的dmrman工具是管理备份集的正规军它会去读取数据库备份的元数据知道哪些备份集是有效可恢复的哪些是孤立无用的。用它来清理能保证不会误删掉正在使用的备份链。首先进入dmrman并查看备份集信息/dm/dmdbms/bin/dmrman在dmrman提示符下执行RMAN SHOW BACKUPSET /dm_data/backup;这会列出备份目录下的所有备份集包括备份集ID、类型、数据库ID、备份时间等信息。删除过期备份的命令示例RMAN DELETE BACKUPSET /dm_data/backup UNTIL TIME 2025-01-01 00:00:00;这条命令会删除2025年1月1日之前的所有备份集。如果只想保留最近5份可以按备份集数量来删。但dmrman的DELETE语法本身没有直接“保留最近N份”的选项所以一般还是用时间窗口来控制。这种方式的好处是它知道哪些备份集属于同一个备份链。比如你做了全量备份增量备份增量备份依赖于全量备份。如果直接删物理文件可能把完整备份链破坏掉导致后续备份集无法恢复。通过dmrman删除它会自动判断依赖关系安全得多。所以在有条件的情况下我强烈建议用dmrman的DELETE而不是直接rm文件。3.2 用shell脚本按时间清理备份文件简单粗暴但有效不是所有环境都方便进入dmrman尤其是当你把备份脚本和清理脚本写在一起时用文件系统级别的删除往往更直接。纯清理脚本示例dm_cleanup.sh#!/bin/bash # 达梦数据库备份清理脚本 # 删除7天前的全量备份文件 BACKUP_BASE/dm_data/backup RESERVE_DAYS7 find $BACKUP_BASE -maxdepth 1 -type d -name full_* -mtime $RESERVE_DAYS -exec rm -rf {} \;这个命令会找出备份基础目录下所有full_开头的目录并删除修改时间超过7天的。注意几个点-maxdepth 1很关键。防止递归删除到备份目录下的子目录导致误删。-mtime 7是以天为单位指的是文件内容修改时间距今超过7天。这个时间判断是向下取整的如果某些文件时间是23:59分修改的可能在还没到严格7天的边缘处就被删了。为了稳妥建议边界留出余量比如想保留7天实际用6或直接保留7后手动核查一次。删除日志一定要留。我习惯把删除动作写进日志每删一个目录就记录一行。宁可日志啰嗦也不要事后不知道删了什么。这个方法只适用于你自己能确定备份目录的命名规则和内容的情况下。如果里面有手工恢复出来的备份集、或者其它程序写入的目录一个rm -rf会把你坑得很惨。所以生产环境的备份目录最好单独划分不和其它文件混放。3.3 把备份和清理合成一个任务推荐方案既然定时调度都在一起了不如把备份和清理写进同一个脚本每次备份完成后自动清理过期备份。这样的好处是逻辑收敛在一个脚本里排障只需要看一份日志。下面是一个简化版的一体化脚本兼具备份和清理功能#!/bin/bash # 达梦定时备份清理一体化脚本 export DM_HOME/dm/dmdbms export LD_LIBRARY_PATH$DM_HOME/bin:$LD_LIBRARY_PATH DB_USERSYSDBA DB_PWDSYSDBA_PASSWORD DB_HOSTlocalhost DB_PORT5236 BACKUP_BASE/dm_data/backup BACKUP_DIR$BACKUP_BASE/full_$(date %Y%m%d_%H%M%S) RESERVE_DAYS7 LOG_FILE$BACKUP_BASE/backup_$(date %Y%m%d).log mkdir -p $BACKUP_BASE echo [$(date %Y-%m-%d %H:%M:%S)] 开始备份 $LOG_FILE $DM_HOME/bin/disql $DB_USER/$DB_PWD$DB_HOST:$DB_PORT EOF $LOG_FILE 21 BACKUP DATABASE FULL BACKUPSET $BACKUP_DIR COMPRESSED PARALLEL 4; EXIT; EOF if [ $? -eq 0 ]; then echo [$(date %Y-%m-%d %H:%M:%S)] 备份成功: $BACKUP_DIR $LOG_FILE else echo [$(date %Y-%m-%d %H:%M:%S)] 备份失败不再执行清理 $LOG_FILE exit 1 fi echo [$(date %Y-%m-%d %H:%M:%S)] 开始清理 ${RESERVE_DAYS} 天前的备份 $LOG_FILE find $BACKUP_BASE -maxdepth 1 -type d -name full_* -mtime $RESERVE_DAYS -exec rm -rf {} \; -exec echo [$(date %Y-%m-%d %H:%M:%S)] 删除过期备份: {} $LOG_FILE \; echo [$(date %Y-%m-%d %H:%M:%S)] 备份与清理任务完成 $LOG_FILE这个脚本有几个设计思路值得参考当次备份失败时不执行清理。避免因为备份失败导致已有备份被误删这个逻辑非常重要。清理只删full_前缀目录不影响其它文件。每个关键步骤都打印到日志后续接监控告警也方便。配套的crontab配置我建议在备份高峰后隔一段时间再执行清理。比如备份在凌晨1点跑清理就不用再单独配时间了因为一体化脚本已经包含了清理逻辑。如果拆成两个脚本清理时间可以放在备份任务后半小时比如当天1点30分确保备份任务执行完成后再清理。补充说明如果你用的是Windows任务计划同样可以把备份和清理写在一个bat脚本里。但Windows下查找和删除旧文件建议用PowerShell的Get-ChildItem和Remove-Item比forfiles更直观$base D:\dm_data\backup $days 7 Get-ChildItem -Path $base -Directory -Filter full_* | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$days) } | Remove-Item -Recurse -Force同样在备份失败时不执行清理逻辑用$LASTEXITCODE判断即可。3.4 备份清理的配套监控与告警备份和清理自动化了不代表可以甩手不管。一个完整的备份体系必须有监控和告警不然万一备份连续失败一周等到你需要恢复数据时才发现没有可用备份那是真正的灾难。我常用的监控手段有两种一是在备份日志里筛关键字。通过脚本周期扫描日志内容如果当日日志里出现“备份失败”就触发告警。这个可以在crontab里再加一个监控任务。二是监控备份目录的总大小。提前给备份目录设置一个磁盘使用率阈值比如80%超过阈值告警这样即使清理任务失效也能在磁盘爆满前及时介入。如果你用的是zabbix或Prometheus达梦也有对应的监控插件或者通过自定义脚本暴露指标可以比较方便地把备份目录容量和最新备份时间纳入监控。“最近一次成功备份时间”这个指标比磁盘容量更能直接反映备份健康度建议一定要盯。4. 常见问题与排查技巧实录这部分我把实际运维中遇到的频率最高的问题做个梳理也是我踩过的坑的汇总。有些问题表面看和备份清理无关但实际会影响备份任务的成功率比如连接不上数据库、管理工具显示异常等。顺便说一下前面热词里提到的“Navicat连接达梦数据库”“DBeaver连接达梦报错”“达梦管理工具没有对象导航栏”这类问题数据连接层面不通定时备份自然无从谈起排查思路是类似的。4.1 定时任务到点没执行问题现象crontab配置了备份脚本到时间了备份目录里没有新文件。排查步骤先手动执行一遍脚本看是否能正常完成。如果手动执行成功问题大概率在crontab环境。查看crontab日志确认任务是否被触发grep CRON /var/log/cron。重点检查脚本中环境变量是否设置尤其是LD_LIBRARY_PATH和DM_HOME。检查脚本是否具备执行权限ls -l dm_backup.sh没有x权限就chmod x。这里我还遇到过一种情况脚本中有exit 1但crontab还是认为执行成功导致没有告警。这是因为crontab只看最后一条命令的返回值如果你脚本最后一行是echo那返回值往往是0。所以要做精细化的返回值管理或者用告警平台主动轮询备份日志文件是否更新。4.2 备份时报磁盘空间不足问题现象执行备份命令时报错提示无法写入备份文件或者磁盘空间不足。排查建议df -h看备份目录所在的文件系统使用率。记住备份需要的空间不是简单按数据文件大小估算压缩率、并行度、临时文件都会影响实际占用。检查是不是备份目录和数据库数据目录在同一个磁盘上。如果是备份和数据库在磁盘IO和空间上互相挤占生产环境一定要分开。检查备份目录下是否堆积大量旧备份没清掉。很多时候不是磁盘真小而是清理逻辑失效了。我遇到过印象最深的案例备份脚本里用了find -exec rm -rf但因为目录名里有个特殊字符导致rm一直失败备份越堆越多。所以清理命令执行之后一定看一眼日志里到底删没删成功不要只看脚本退出码为0。4.3 dmrman无法登录或者找不到备份集问题现象进入dmrman后执行命令提示无法连接或者SHOW BACKUPSET显示的备份集不是预期的。原因和解决dmrman工具没有指定实例的dm.ini。通常需要在登录时指定CTL路径或用SYSDBA/SYSDBA_PASSWORD连接实例。如果按备份脚本的方式可以这样/dm/dmdbms/bin/dmrman CTLSTMTBACKUP DATABASE FULL BACKUPSET /dm_data/backup/full_test如果用RMAN SHOW BACKUPSET /dm_data/backup显示的列表为空先检查目录路径是否正确、使用的用户是否有读权限以及备份集是不是被移动过位置。有时候你把备份目录整个mv到新机器元数据里面记录的信息和实际路径不匹配dmrman就会“看不到”这些备份集。另外dmrman的版本最好和数据库版本一致。跨版本操作可能会出现元数据解析异常虽然不一定致命但没必要冒这个险。4.4 连接工具连接达梦失败/报错虽然这不是备份清理本身但确实会影响备份操作。常见的热词里“dbever no suitable driver found for jdbc:dm://…”这类报错基本就是JDBC驱动没加载或URL格式问题。排查经验驱动要放对位置。DBeaver里需要手动添加达梦驱动jar包下载DM的JDBC驱动DmJdbcDriver18.jar加到库管理器。URL格式用jdbc:dm://IP:PORT端口默认5236。用户名密码确认无误且用户具备访问权限。听说有用户连接失败其实是用了SYSDBA默认密码但密码被改掉了。再说一下“达梦管理工具没有对象导航栏”的情况。这不是备份问题但管理工具打不开对象树你就没法图形化看表、看备份操作起来很别扭。一般先确认连接是否正常、当前用户是否有权限如果刚装完就看不到多半是版本兼容问题换个客户端版本或者用DBeaver替代都行。图形化管理工具只是辅助核心的备份恢复命令还是要都会手动敲。4.5 清理后备份不可用或恢复失败问题现象删除过期备份后需要做恢复演练时发现某一次备份无法使用。原因分析直接rm文件打破了备份链。比如你有一个增量备份依赖的前置全量备份被你删了那这个增量备份就废了。备份集目录被部分删除比如删了目录里的某些文件剩一个空壳目录。备份时没有开启归档导致备份虽然生成但无法用于完整恢复。这里强调一遍优先使用dmrman的DELETE命令清理不要直接用rm删文件。如果因为空间压力必须快速释放磁盘可以用rm但要在清理前备份好备份集的元数据并且绝对不要删到当天最新备份或者仍在备份链上的数据。4.6 达梦数据库突然连不上这个问题也经常上榜。如果是备份任务跑着跑着突然连不上了先看是否归档日志把磁盘写满数据库自动挂起。我经历过一次就是归档目录满了实例直接不能正常服务disql都登不进去。这时候要先清理归档日志重启数据库服务恢复连接后赶紧排查归档策略和备份清理配置。另一个常见原因是数据库服务异常退出或者监听进程挂掉。可以用systemctl status DmServiceXXXLinux服务名通常是DmService 实例名来查看服务状态。4.7 备份任务排查速查表症状可能原因排查/解决动作定时任务没执行crontab环境变量/权限问题手动执行脚本、检查crontab日志备份报磁盘满磁盘空间不足/清理失效df -h、清理过期备份、拆分目录dmrman看不到备份路径/权限/版本不匹配检查目录、用户权限、版本一致性备份后恢复失败备份链断裂/未开归档用dmrman删除、确认归档开启数据库连不上磁盘满/服务异常清归档、重启服务、查日志清理没反应find/rm执行失败查看清理日志、检查特殊字符5. 一点实操心得最后分享一个我在实际运维中的习惯每个星期至少抽查一次备份日志和备份目录大小。不要以为自动化配好了就一劳永逸很多隐患都是从“日志里开始出现异常但没人发现”开始的。我自己的做法是每周一看一下上周七天的备份日志重点看有没有“失败”“异常”关键字再看一下备份目录总体积是否在预期范围内。这套检查动作五分钟以内就能完成但对于数据安全来说价值不可估量。另一个值得扩展的思路是如果你有多台达梦实例可以写一个统一调度的管理脚本通过指定实例端口和备份目录的方式在一个主控节点上集中下发备份命令。这样备份策略的变更只需要改一处维护成本会明显下降。我目前就是把备份脚本模板化每台机器留一个配置文件里面记录库名、端口、备份目录、保留天数主脚本统一读取配置执行逻辑清爽很多。如果你已经有了定时备份加清理的雏形下一步可以朝这个方向演进。