在生产环境面临磁盘空间不足的情况,运维人员一般想到的就是查找大文件进行删除缓解一下磁盘空间问题。比如审计日志和redolog文件都放在数据库目录文件下,运维人员觉得.log结尾的文件一般是可删除的普通日志文件,加上redo文件有几个G的大小,就使用rm -rf /dmdata/dmdb/*.log进行删除了。Redolog记录了数据库中物理数据页的变更,既包括已提交的也包括未提交事务的数据修改,在事务提交后数据库会按一定的时机进行日志归档和数据刷盘,一旦redo日志文件被误删除会导致数据库无法启动和数据丢失。
在误删redo文件后,处理的方式分3种,首先最稳妥的方式是利用数据库日常(前提是有开启归档和设置定时作业)的物理备份集进行还原;如果没有备份或者备份集太久远了那么再考虑单独还原redolog文件的方式:首先开当前实例是否还在运行,如果进程还在那么从proc中通过进程号找到被标记为(deleted)状态的redolog文件并将它们复制回数据目录下;如果实例已经异常关闭无法启动了,那么就需要重新初始化一个新的实例将生成的redolog文件复制过来并修改名称和redolog文件内容以及dm.ini参数进行启动。
单机数据库,具体版本信息为:企业版 8.1.4.80_Pack24
在生产环境都会创建定时备份作业,开启归档日志并对数据库进行物理全备和增量备份。如果数据库有这些备份集存在并且数据库数据量不大的情况下则优先采用数据库备份还原的方式。
如果数据库还在运行则直接关闭数据库:
su - dmdba
cd /home/dmdba/dmdbms/bin
./DmServicedmdb stop
利用备份集还原:
/DB_DSC_INCREMENT_CUMULATIVE_2025_09_11_23_00_36是最近一次增量备份集;/dmbak/dmdba/dmbak/arch_log/arch是归档日志目录,也可以单独将增量备份以后的归档日志拷贝出来再指定目录;
# 校验备份集
./dmrman CTLSTMT="check backupset '/dmbak/dmdba/dmbak/DB_DSC_INCREMENT_CUMULATIVE_2025_09_11_23_00_36' "
# 还原数据库,如果数据库还是开启状态的话需要关闭实例服务
./dmrman CTLSTMT="RESTORE DATABASE '/dmdata/dmdb/dm.ini' FROM BACKUPSET '/dmbak/dmdba/dmbak/DB_DSC_INCREMENT_CUMULATIVE_2025_09_11_23_00_36'"
# 恢复归档日志
./dmrman CTLSTMT="RECOVER DATABASE '/dmdata/dmdb/dm.ini' WITH ARCHIVEDIR '/dmbak/dmdba/dmbak/arch_log/arch'"
# 更新数据库魔数
./dmrman CTLSTMT="RECOVER DATABASE '/dmdata/dmdb/dm.ini' UPDATE DB_MAGIC"
还原后重启数据库服务。
在刚删除redo文件不久会有一个窗口期,在这期间数据库仍在正常运行,进程未关闭。
既然此时数据库实例进程还存在,那么我们就可以利用Linux系统的/proc虚拟文件系统,找到操作系统中该进程打开的文件句柄,并从中cp出两个被标记为删除的redo文件放回到原目录。
linux服务器是没有垃圾站这个东西的,文件用rm命令删除后一半就找不回来了。但是由于我们的dmserver进程已经将这个文件加载到内存了,我们可以通过内存中的数据来恢复这个目录以及目录中的文件。
在Windows中文件句柄是用来操作文件的,你可以理解为一个指针,在linux也是一样的只不过他叫文件描述符。
通过dmserver进程PID查找到对应的内存文件目录:
可以看到9号链接文件对应的是dmdb01.log,10链接文件对应的是dmdb02.log文件,它们都被标记为(deleted)状态标识已经被删除了,但是由于dmserver进程还在运行所以并未真正删除。
因为mount状态下,不允许访问数据库对象,只能进行控制文件维护、归档配置、数据库模式修改等操作。所以就相当于数据库是只读状态了,这样避免新的数据进来。
接着是让那些记录在系统缓冲区中被修改过的数据页写入磁盘,尽可能保留更多的数据。
ALTER DATABASE MOUNT;
CHECKPOINT(100);
对于未提交的事务,如果继续执行的话会提示:事务被强制回滚
链接文件可以认为是当前实例最新一致状态的redolog备份文件,此时可以直接将两个链接文件cp到原实例数据目录下,并改名为对应的redolog文件,然后重启数据库实例服务即可:
cp /proc/104062/fd/9 /dmdata/dmdb/
cp /proc/104062/fd/10 /dmdata/dmdb/
cd /dmdata/dmdb/
mv 9 dmdb01.log
mv 10 dmdb02.log
chown -R dmdba:dinstall /dmdata/dmdb/dmdb01.log
chown -R dmdba:dinstall /dmdata/dmdb/dmdb02.log
Redo文件复制回去并授权后重启数据库实例:
cd /home/dmdba/dmdbms/bin
./DmServicedmdb stop
./DmServicedmdb start
通过内存文件还原的redolog虽然可以正常运行,但是系统表空间(SYSTEM.DBF)中的这些元数据有可能已经因为redo的丢失而损坏或不一致,后续可能会引发其他问题,建议做一次迁移,比如初始化一个一模一样的新实例然后将原实例通过逻辑导出或者DTS迁移的方式将数据迁移到新的实例,这样新的实例系统内所有的文件和元数据状态均是一致的。
使用逻辑导出全库:
cd /home/dmdba/dmdbms/bin
./dexp USERID=SYSDBA/'"密码"'@localhost:5236 FILE=dmdb01_FULL.dmp DIRECTORY=/dmdata/dmbak/ LOG=dmdb01_FULL.log FULL=Y
在新实例创建表空间、用户、模式后进行导入:
cd /home/dmdba/dmdbms/bin
./dimp USERID=SYSDBA/'"密码"'@localhost:5237 FILE=dmdb01_FULL.dmp DIRECTORY=/dmdata/dmbak/ LOG=dmdb01_FULL_dimp.log FULL=Y
注意:逻辑备份不会备份作业,定时作业需要手动导出并进行创建。
物理备份还原会还原当时数据库一致性的状态,包括redolog和undo等文件的一致性,所以不能在启动误删除redolog的实例后进行脱机备份然后用此物理备份进行还原。通过只还原redolog的办法可能会跳过clsn或者元数据不一致等造成数据库系统有不稳定的隐患,比如purge机制异常等问题,所以都是需要使用物理备份还原和DTS迁移的。
删除后数据库还能正常使用,可以进行增删改查,应该是下次切换日志才会有报错。在测试环境就直接删掉两个redo文件然后kill -9 进程号了:
redo日志文件名为实例名+01.log以此类推,比如实例名为dmdb的数据目录下就有:dmdb01.log和dmdb02.log
查看日志可以发现报错信息是缺少redo日志文件:
根据源库的初始化参数,重新初始化一个数据库实例,REDO大小要>=源库的重做日志文件大小。
初始化参数要和原库一致,页大小、大小写敏感、字符集等。
查看初始化日志文件:
[dmdba@localhost.localdomain:/dmdata/dmdb]$ cat /dmdata/dmdb/dminit20250909174517.log
start init database: V8, 2025-09-09 17:45:17
init params:
db path: /dmdata/dmdb
db name: dmdb
auto overwrite: 0
page size: 32768
extent size: 32
char_fix_storage: 0
sql_log_forbid: 0
secur_flag: 2
enable mac: 0
time zone: +08:00
string case sensitive: 1
charset: 1
page check mode: 3
page check algorithm id: 0
priv flag: 0
env label: 0
rlog enc flag: 0
use new hash: 1
blank pad mode: 0
sec priv mode: 0
huge with delta: 1
rlog gen for huge: 1
pseg_mgr_flag: 0
auto_adj_para: 1
auto_adj_cpus: 0
auto_adj_mem: 0
log file path: /dmdata/dmdb/dmdb01.log
log file path: /dmdata/dmdb/dmdb02.log
create ini file /dmdata/dmdb/dm.ini success.
create rlog file /dmdata/dmdb/dmdb01.log success.
create rlog file /dmdata/dmdb/dmdb02.log success.
SYSTEM file : /dmdata/dmdb/SYSTEM.DBF
MAIN file : /dmdata/dmdb/MAIN.DBF
ROLL file : /dmdata/dmdb/ROLL.DBF
create dm database success. 2025-09-09 17:45:17
注意:初始化日志文件并不一定准确,有可能客户通过物理全备覆盖过,所以实际参数以数据库查询为准:
select para_name,para_value from v$dm_ini where para_name in ('COMPATIBLE_MODE', 'ORDER_BY_NULLS_FLAG','CALC_AS_DECIMAL','ENABLE_SEQ_REUSE','ENABLE_PL_SYNONYM','ENABLE_BLOB_CMP_FLAG');
select para_name,para_value from v$dm_ini where para_name in ('LENGTH_IN_CHAR', 'BLANK_PAD_MODE','COMPATIBLE_MODE');
注意一下LENGTH_IN_CHAR,老版本(2024年第二季度以前的版本可以指定)重新初始化需要指定。
--查询数据库基本信息
SELECT '页大小',cast(PAGE()/1024 as varchar) union all SELECT '簇大小',cast(SF_GET_EXTENT_SIZE() as varchar) union all
SELECT '字符集',CASE SF_GET_UNICODE_FLAG() WHEN '0' THEN 'GBK18030' WHEN '1' then 'UTF-8' when '2' then 'EUC-KR' end union all
SELECT '大小写敏感',cast(SF_GET_CASE_SENSITIVE_FLAG() as varchar) union all
select 'VARCHAR类型长度是否以字符为单位',para_value from v$dm_ini where para_name='LENGTH_IN_CHAR' union all
select '空格兼容模式',para_value from v$dm_ini where para_name='BLANK_PAD_MODE' union all
select '实例名称' 数据库选项,INSTANCE_NAME 数据库集群相关参数值 FROM v$instance union all
select '数据库名',name from v$database union all
select '端口号',para_value from v$dm_ini where para_name='PORT_NUM' union all
select '数据库版本1',substr(svr_version,instr(svr_version,'(')) FROM v$instance union all
select '数据库版本2', id_code from dual union all
select '数据库模式',MODE$ from v$instance union all
SELECT '数据库兼容模式', para_value FROM v$dm_ini WHERE para_name='COMPATIBLE_MODE' union all
select '唯一魔数',cast(permanent_magic as varchar) union all
select 'LSN',cast(cur_lsn as varchar) from v$rlog union all
select 'KEY文件属性', cluster_type from v$license union all
SELECT '日志文件大小',TO_CHAR(RLOG_SIZE/1024/1024) FROM V$RLOGFILE;
初始化:
cd /home/dmdba/dmdbms/bin
./dminit path=/dmdata page_size=32 extent_size=32 charset=1 CASE_SENSITIVE=0 log_size=2048 db_name=dmdba_test instance_name=dmdba_test SYSDBA_PWD="密码" SYSAUDITOR_PWD="密码" PORT_NUM=15236
cd /home/dmdba/dmdbms/bin
# 用前台启动的方式就不用注册服务了,看到SYSTEM IS READY.并且使用disql能连接后输入exit关闭数据库
./dmserver /dmdata/dmdba_test/dm.ini
将新初始化实例目录下的的两个Redo文件拷贝到故障的实例目录下,并且修改Redo文件名:
cd /dmdata/dmdba_test/
cp dmdba_test01.log /dmdata/dmdb/dmdb01.log
cp dmdba_test02.log /dmdata/dmdb/dmdb02.log
利用dmmdf 工具修改新拷贝到故障实例的两个Redo日志的db_magic、pemnt_magic的值,保持和源库(故障库)一样。
通过查看故障库的数据文件头信息,可以找到数据库魔数(db_magic)、永久魔数(pemnt_magic)值:
cd /home/dmdba/dmdbms/bin
./dmmdf type=1 file=/dmdata/dmdb/SYSTEM.DBF
# ./dmmdf type=1 file=/dmdata/dmdb/system.dbf
修改redo日志中的db_magic和pemnt_magic:
./dmmdf type=2 file=/dmdata/dmdb/dmdb01.log
./dmmdf type=2 file=/dmdata/dmdb/dmdb02.log
输入对应的行号,则可以更新对应的字段信息:
db_magic:
pemnt_magic:
不要忘记修改第二个文件,否则启动报错:
查看该实例的PSEG_RECV值修改前的值是多少,然后设置为0。
关于PSEG_RECV参数:
该参数是系统级的动态参数,默认为1。系统故障重启时,对活动事务和已提交事务的处理方式。0:跳过回滚活动事务和 PURGE 已经提交事务的步骤。在回滚表空间出现异常、损坏、系统无法正常启动时,可将 PSEG_RECV设置为 0,让系统启动;但存在一定风险,未提交事务的修改将无法回滚,破坏事务的原子性;另外,已提交未 PURGE 的事务,将导致部分存储空间无法回收;1:回滚活动事务并PURGE 已经提交事务;2:延迟 PURGE 已提交事务,延迟回滚活动事务;3:回滚活动事务,延迟 PURGE 已提交事务。
原值为3
修改为0
vi /dmdata/dmdb/dm.ini
后面发现2024年以后的新版达梦数据库还是不能启动实例,启动会出现以下报错:
新版本的数据库还要修改clsn值,在(可查询对应server运行日志最后打印的cur_lsn值,如果有归档可分析对应归档的最大lsn值,稍大于此值即可),因为前面尝试启动过数据库,导致无法修改lsn号,所以要重新拷贝日志过来然后一并修改db_magic和pemnt_magic的值【旧版本一定不要修改clsn!】
比这个值大就行,比如+64。如果修改lsn的时候提示“ERROR, rlog is active, dmserver should shutdown normal.”
但实际你是前台启动的时候使用exit关闭的,那你再开启一次并且在SQl命令行执行shutdown immediate;进行关闭。后面发现02日志的sta=0但是sta=1,于是尝试将sta改为1,然后修改clsn号后把sta重新改为0就可以了。
另外还要在dm.ini中追加参数RLOG_CHECK_SPACE=2;
前台启动数据库实例:
cd /home/dmdba/dmdbms/bin
./dmserver /dmdata/dmdb/dm.ini
成功启动后关闭实例
exit
将修改的RLOG_CHECK_SPACE参数注释掉以及PSEG_RECV改为3
vi /dmdata/dmdb/dm.ini
但是对于没有归档的修改都会丢失。
故障库建议重新迁移,否则有可能触发其他的故障。
迁移的时候使用逻辑导入导出的方式或者DTS迁移,具体请看5.5节。
上面3种恢复方式中最稳妥的是第一种,所以在生产环境一定要配置归档和定时备份作业并定期检查备份作业执行情况;第二种的优势在于可以快速恢复,但是窗口期短;第三种方式需要修改redolog文件还有dm.ini;后两者均存在隐患,建议在业务空闲期重新进行迁移,迁移完成后再使用。
因为redolog的文件后缀为.log有可能会被运维人员当成是普通日志文件进行删除,我们也可以在初始化实例的时候通过指定RLOG_POSTFIX_NAME参数修改redolog的后缀名为.DBF,这样可以减少误删风险:
cd /home/dmdba/dmdbms/bin
./dminit path=/dmdata page_size=32 extent_size=32 charset=0 CASE_SENSITIVE=0 log_size=2048 db_name=DMDATA instance_name=DMDATA SYSDBA_PWD="密码" SYSAUDITOR_PWD="密码" PORT_NUM=5238 RLOG_POSTFIX_NAME=DBF
可以看到现在数据库实例目录下的redolog文件的后缀名改为了.DBF:
文章
阅读量
获赞
