注册
达梦数据库Redo文件损坏修复
技术分享/ 文章详情 /

达梦数据库Redo文件损坏修复

迷枫 2026/08/14 101 0 0

本文记录一次达梦数据库 Redo 文件损坏修复实验。这里说的“修复”,不是把原来的 .log 文件修好后继续使用,而是在联机 Redo 已经丢失或损坏、又没有备份归档可以正常恢复时,尝试让故障库临时打开,尽快把还能读取的数据抢救出来。

需要先明确:这种无备份、无归档条件下的应急处理,无法保证全部数据恢复。故障发生附近,已经提交但尚未写入数据文件、仅存在于原 Redo 中的修改可能丢失。

先把结论放在前面:

有备份和归档
    → 优先走正规恢复

没有备份归档,Redo 又不可用
    → 才考虑替换 Redo 临时启动

数据库能启动
    → 不等于修复完成
    → 目标应是导出数据、重建新库、导入校验

本文实验只适用于测试环境。生产环境必须长期保留可用的物理备份和归档日志,并定期验证备份可恢复性。生产库遇到 Redo 损坏时,应先保护故障现场,优先评估备份、归档、主备副本和厂商支持,不要直接照搬替换 Redo、修改文件头或调整抢救参数。

一、Redo 损坏后,真正缺的是什么

Redo 是数据库故障恢复的重要依据。执行 DDL、DML 时,数据库会生成 Redo 记录,保存数据库物理更改信息。数据页不一定在事务提交时立刻全部写入数据文件,但恢复所需的 Redo 必须被保护下来。

这条链路可以简化成:

用户修改数据
    ↓
内存中的数据页发生变化
    ↓
生成 Redo
    ↓
Redo 写入联机日志
    ↓
数据页随后通过检查点等机制落盘

异常停库后,只要数据文件、控制文件、联机 Redo 都还完整,数据库重启时就可以从检查点附近读取 Redo,重做尚未完整落盘的修改,再处理未提交事务。

Redo 丢失或损坏时,问题就变了:

数据库不是“不知道怎么启动”
而是“正常恢复所需的依据坏了”

这时所谓“替换 Redo”,本质不是恢复原来的 Redo 历史。新的 Redo 是从新实例里拿来的,它没有原库故障前那段真实修改记录。替换的目标只是让数据库获得一组结构合法、身份匹配的联机日志文件,尝试跨过启动阶段。

因此,替换 Redo 更像一次数据抢救:

放弃已经不可用的原 Redo 历史,尝试接受当前数据文件状态,争取一次导出数据的机会。

二、先选恢复路线,再谈替换 Redo

Redo 损坏时,首先要判断有没有正规恢复条件。

如果有备份和归档,优先选择:

还原备份
    ↓
应用归档日志
    ↓
恢复到故障前尽可能新的时间点

这条路线的目标是恢复一个一致、可以继续使用的数据库。生产环境应把可用备份和连续归档作为前提,而不是把替换 Redo 当成常规恢复手段。

如果没有备份、没有归档,也没有可用副本,才进入应急抢救。Redo 不可用时,故障库本身已经无法正常提供业务读写;临时拉起后也不应恢复应用接入或继续承载生产交易。这个阶段的主线应当是:

临时打开故障库
    ↓
确认核心对象是否还能读取
    ↓
尽快导出能读取的数据
    ↓
初始化全新数据库
    ↓
导入并校验

这里不是“把原库恢复到故障前的完整状态”。原 Redo 中尚未落盘的修改已经无法通过新 Redo 重演,因此故障附近的数据可能丢失,最终能够抢救出的数据范围要以实际查询、导出和业务校验结果为准。

因此,启动日志中看到:

SYSTEM IS READY

只能说明数据库进程打开了。它不代表所有事务都完整,也不代表所有表、索引和空间结构都健康。

三、新 Redo 为什么要“认回原库”

联机 Redo 文件不是普通文本日志,也不是只要文件名存在就可以。

例如直接执行:

touch DAMENG01.log
touch DAMENG02.log

这种文件没有 Redo 内部结构,没有日志控制信息,也没有数据库身份信息,数据库不会把它当成合法联机日志。

比较稳妥的应急思路是:

查看原库初始化参数
    ↓
使用一致的关键参数初始化新实例
    ↓
启动并正常停止新实例
    ↓
从新实例取得结构合法的 Redo
    ↓
读取原库 SYSTEM.DBF 的身份信息
    ↓
修改新 Redo 的 db_magic 和 pemnt_magic
    ↓
替换故障库对应 Redo
    ↓
尝试启动故障库

这条流程有两个关键点。

第一,新实例不是为了替代原库,而是为了生成一组结构正常的 Redo 文件。初始化参数要尽量和原库一致,尤其是页大小、簇大小、大小写敏感、字符集、日志大小等关键参数。

第二,新 Redo 原本属于新实例。要让原库识别它,需要把其中的 db_magicpemnt_magic 调整为原库的值。原库身份信息可以从 SYSTEM.DBF 读取:

dmmdf TYPE=1 FILE=/dmdata/DAMENG/SYSTEM.DBF

再修改新 Redo:

dmmdf TYPE=2 FILE=/dmdata/DAMENG/DAMENG01.log
dmmdf TYPE=2 FILE=/dmdata/DAMENG/DAMENG02.log

db_magicpemnt_magic 可以理解为数据库文件之间的身份标识。数据文件属于原库,而新生成的 Redo 属于新库,如果身份不一致,启动时就可能报 magic 不匹配。

实际处理时不能机械理解成“必须替换两个日志”。前台启动和实例日志通常会指出 DAMENG01.logDAMENG02.log 中哪个文件不存在、读取失败或校验异常;如果只有一个 Redo 文件有问题,正常只处理该文件,保留另一个完好的 Redo。本文实验同时移走并处理两个文件,只是为了完整演示流程。完成处理后,仍然是使用放回原故障库目录、已经调整过身份信息的 Redo,前台启动原故障库进行验证。

本次实验涉及的工具可以先这样理解:

工具 作用 本文中的定位
dminit 初始化一个新实例 用相同关键参数生成结构合法的新 Redo
dmserver 启动数据库实例 用前台启动观察真实报错和 SYSTEM IS READY
dmmdf 查看或修改达梦数据文件、Redo 文件的部分文件头属性 读取 SYSTEM.DBFdb_magicpemnt_magic,再写入新 Redo
dmhcr 部分环境或案例中可能出现的辅助工具 本次实验未使用,本文不把它写成必需步骤;如果现场版本提供该工具,应以对应版本说明和厂商建议为准
dmdbchk 检查数据库物理结构 数据抢救后可用于辅助校验,但不能替代逻辑导出和业务校验

其中 dmmdf 是本次实验最关键的工具。它不是普通文本编辑器,而是按文件类型读取和修改达梦文件头信息。本文只使用它处理 db_magicpemnt_magic 这两个身份字段,不把 clsnnext_seq 等日志位置字段作为初学实验的修改项。

四、第一次实验:按基础替换流程尝试

实验放在单机测试库中进行,目标是模拟“联机 Redo 丢失后,通过新实例 Redo 临时拉起故障库”。主备、DSC、ASM、控制文件损坏、Undo 损坏等场景暂时不混入,先把 Redo 替换这一条线看清楚。

实验数据库信息如下:

端口:15236
原实例目录:/dmdata/DAMENG
备份目录:/dmdata/bak_DAMENG
新实例目录:/dmdata/NEW_DAMENG/DAMENG
测试用户:TEST
测试表:TEST.T_REDO

实验主线如下:

先准备一个可恢复的测试现场
    ↓
正常停库并备份数据目录
    ↓
移走联机 Redo,模拟 Redo 丢失
    ↓
确认原库无法启动
    ↓
新建同参数实例,取得合法 Redo
    ↓
修改新 Redo 的 magic 信息
    ↓
替换原库 Redo 并尝试启动
    ↓
启动后只做查询、导出、迁移验证

下面进入实操。

  1. 准备测试数据。
CREATE USER TEST IDENTIFIED BY "Test@123456";

CREATE TABLE TEST.T_REDO
(
    ID   INT,
    NAME VARCHAR(50)
);

INSERT INTO TEST.T_REDO VALUES (1, 'REDO_TEST_1');
INSERT INTO TEST.T_REDO VALUES (2, 'REDO_TEST_2');
COMMIT;

01.jpeg
2. 正常停止测试库,完整复制数据目录,并单独备份原 Redo 文件。

/dmdbms/bin/DmServiceDMSERVER stop

cp -a /dmdata/DAMENG /dmdata/bak_DAMENG

cp /dmdata/DAMENG/DAMENG01.log /dmdata/DAMENG/DAMENG01.log.bak
cp /dmdata/DAMENG/DAMENG02.log /dmdata/DAMENG/DAMENG02.log.bak

这一步必须先停库再复制。/dmdata/bak_DAMENG 是完整现场备份,单独备份 .log 文件是为了实验结束后还能还原 Redo。

02.jpeg
3. 移走联机 Redo,模拟 Redo 丢失。

本实验为了展示完整流程,同时移走了两个 Redo。真实故障中应先根据前台启动信息和实例日志判断具体是 DAMENG01.log 还是 DAMENG02.log 有问题;如果只损坏一个,就只替换对应文件。

cd /dmdata/DAMENG

mv DAMENG01.log DAMENG01.log.lost
mv DAMENG02.log DAMENG02.log.lost

03.jpeg
4. 启动原库,保存启动报错和实例日志,用来确认故障现象确实来自联机 Redo 不可用。

04.jpeg
5. 查看原实例的 dminit*.log,按关键初始化参数创建新实例。

需要记录的内容包括:

PAGE_SIZE
EXTENT_SIZE
CASE_SENSITIVE
CHARSET 或 UNICODE_FLAG
LOG_SIZE
DB_NAME
INSTANCE_NAME
PORT_NUM

05.jpeg
如果 dminit*.log 中字段显示的是描述性名称,例如 page size: 8192,需要换算成 dminit 参数:8192 字节对应 PAGE_SIZE=832768 字节对应 PAGE_SIZE=32

随后在新目录初始化一个临时实例,用来生成结构合法的 Redo。示例:

mkdir -p /dmdata/NEW_DAMENG

/dmdbms/bin/dminit PATH=/dmdata/NEW_DAMENG PORT_NUM=15237 PAGE_SIZE=32 EXTENT_SIZE=32 LOG_SIZE=2048 CHARSET=0 CASE_SENSITIVE=Y SYSDBA_PWD=Dameng@1234 SYSAUDITOR_PWD=Dameng@1234

06.jpeg
07.jpeg

这些参数要按原库实际情况填写,PORT_NUM 可以使用新端口,避免和原实例冲突。新实例初始化完成后,启动一次再正常关闭:

./dmserver /dmdata/NEW_DAMENG/DAMENG/dm.ini

08.jpeg
09.jpeg
看到 SYSTEM IS READY 后,正常停止新实例。这样可以取得一组由达梦正常生成并处理过的 Redo 文件,后面再复制到故障库目录中处理 magic 信息。

10.jpeg
6. 从原库 SYSTEM.DBF 读取 db_magicpemnt_magic,再用 dmmdf 修改新 Redo 中对应的 magic 信息。

先读取原库 SYSTEM.DBF。这里读取的是故障库自己的系统数据文件,不是新实例的 SYSTEM.DBF

cd /dmdbms/bin

./dmmdf TYPE=1 FILE=/dmdata/DAMENG/SYSTEM.DBF

进入 dmmdf 后,重点记录这两个值:

db_magic=502961763
pemnt_magic=1019282663

如果输出里还能看到 enable_page_check,也一并记下来,后面排查 magic 不匹配或页校验问题时可能用到。这里只读取原库身份信息,不修改 SYSTEM.DBF。记录完成后输入:

q

11.jpeg
然后把新实例生成的 Redo 复制到原库目录。当前新实例目录是 /dmdata/NEW_DAMENG/DAMENG,原实例目录是 /dmdata/DAMENG

cp /dmdata/NEW_DAMENG/DAMENG/DAMENG01.log /dmdata/DAMENG/DAMENG01.log
cp /dmdata/NEW_DAMENG/DAMENG/DAMENG02.log /dmdata/DAMENG/DAMENG02.log

接着修改复制回来的 Redo。先处理第一个:

./dmmdf TYPE=2 FILE=/dmdata/DAMENG/DAMENG01.log

进入交互界面后,按菜单编号修改:

输入 6
    将 db_magic 修改为原库 SYSTEM.DBF 中记录的 db_magic

按提示输入 y
    保存修改

输入 12
    将 pemnt_magic 修改为原库 SYSTEM.DBF 中记录的 pemnt_magic

按提示输入 y
    保存修改

12.jpeg
13.jpeg

第二个 Redo 同样处理:

./dmmdf TYPE=2 FILE=/dmdata/DAMENG/DAMENG02.log

同样修改 6 db_magic12 pemnt_magic,保存退出。

  1. 启动原实例,观察替换后的 Redo 是否能通过检查。
/dmdbms/bin/dmserver /dmdata/DAMENG/dm.ini

14.jpeg
15.jpeg

五、第一次启动失败:不要只看“非法指令”

第一次使用修改过 magic 的新 Redo 前台启动原故障库后,数据库已经不再报 DAMENG01.log not exist,也没有停在 magic 不匹配上,说明文件存在性和身份检查已经通过。

前台最终显示:

非法指令 (核心已转储)

这只是进程异常停止时的外部现象,不能单独作为根因。应继续回到实例日志,查找它之前最靠近故障时间的 ERRORFATAL 信息。本次实例日志中的关键报错是:

rlog4_adjust_clsn_off_4k rpkg decode failed
rlog4_adjust_clsn_off_4k failed
code = -4602, dm_sys_halt now!!!

这说明数据库已经能够读取新 Redo 的文件头,但在继续解析或调整 Redo 日志包位置时失败。db_magicpemnt_magic 只解决“新 Redo 是否属于原库”的身份问题,不能把原库故障前真实的日志内容、日志位置和日志包进度恢复出来。

达梦官方 FAQ 中也有“前台启动报非法指令(核心已转储)”的案例。该案例真正的实例日志是 Redo log try flush over space,官方解释为日志环被冲破,并针对这一特定错误给出了 RLOG_CHECK_SPACE=0 的处理建议。由此可以看出,同样的前台“非法指令”可能对应不同的实例日志根因,不能只按前台一句话套用参数;本次仍应以实际出现的 rlog4_adjust_clsn_off_4k-4602 为分析依据。

这个结果把替换 Redo 的边界暴露得很清楚:

文件存在
    ≠ Redo 内容可用于原库恢复

magic 匹配
    ≠ 数据库一定能启动

基础替换流程完成
    ≠ 抢救一定成功

因此,第一次失败并不表示前面的步骤毫无作用,而是说明基础替换只完成了第一段:让 Redo 文件结构和身份信息通过检查。继续启动失败时,必须回到实例日志,判断后续是否涉及日志包解析、日志空间检查、页校验或事务恢复阶段。

六、为什么此时才讨论 PSEG_RECV 和 RLOG_CHECK_SPACE

PSEG_RECV=0 不应该放在 Redo 替换流程最前面。Redo 文件不存在、损坏或身份不匹配时,数据库连基本的 Redo 检查都无法通过,这时修改 PSEG_RECV 不能把 Redo 修好。

只有当 Redo 文件已经放回原库、magic 等基础检查通过,数据库启动流程继续向后推进时,事务恢复参数才可能开始产生影响。

先区分两个参数:

PSEG_RECV=0
    → 跳过活动事务回滚和已提交事务 PURGE
    → 只影响后续事务恢复阶段
    → 不修复 Redo,也不恢复丢失数据

RLOG_CHECK_SPACE
    → 与 Redo 日志空间检查有关
    → 应结合具体实例日志、数据库版本和官方说明使用

PSEG_RECV=0 风险很高。数据库异常关闭时,未提交事务正常应被回滚;跳过回滚后,事务可能只留下部分修改,破坏原子性。因此它只用于无正规恢复条件时争取临时打开和导出数据的机会,不能作为长期运行配置。

对于 RLOG_CHECK_SPACE,达梦官方 FAQ 在 Redo log try flush over space、日志环被冲破的案例中明确给出的处理值是:

RLOG_CHECK_SPACE=0

官方对该值的说明是:日志刷盘时不检查日志空间是否溢出。这个说明对应的是“日志环被冲破”这一特定报错。

本次实验参考社区案例,实际使用的是:

RLOG_CHECK_SPACE=2

并在当前测试版本中成功启动。但公开官方 FAQ 没有给出值 2 的通用释义,因此本文不把 RLOG_CHECK_SPACE=2 写成所有 Redo 损坏场景的标准处理,也不把官方对值 0 的解释直接套到值 2 上。生产环境应以对应版本参数说明、实际实例日志和厂商建议为准。

本文涉及的主要字段和参数可以这样区分:

名称 所在位置 作用
db_magic SYSTEM.DBF、Redo 文件头 数据库文件身份标识,新 Redo 要改成原库值
pemnt_magic SYSTEM.DBF、Redo 文件头 数据库文件身份标识,通常和 db_magic 一起核对
enable_page_check SYSTEM.DBF,部分版本 Redo 文件头也可能出现 页校验相关字段;本次 dmmdf TYPE=2 未显示可修改项,所以没有处理
PSEG_RECV=0 dm.ini 跳过活动事务回滚和已提交事务 PURGE,是高风险抢救参数
RLOG_CHECK_SPACE=0 dm.ini 官方 FAQ 在“日志环被冲破”案例中的处理值,含义为日志刷盘时不检查日志空间是否溢出
RLOG_CHECK_SPACE=2 dm.ini 本次社区案例和测试环境采用的值;公开 FAQ 未给出通用释义,不应泛化
clsnclsn_offnext_seq Redo 文件头 与日志位置、日志包解析有关,本文只观察不修改

七、第二次实验:补充参数后本次环境启动成功

第一轮失败后,没有继续修改 Redo 头里的 clsnnext_seq 这类位置字段。它们和日志包位置直接相关,改错以后很难判断新的错误来自哪里。

结合社区案例,本次在 dm.ini 文件末尾追加两个参数。同一个参数如果在文件中出现多次,读取时以最后一次配置为准,因此直接在末尾追加即可,避免前面已有同名配置影响本次实验:

PSEG_RECV = 0
RLOG_CHECK_SPACE = 2

16.jpeg
这两个参数的定位并不相同:

PSEG_RECV=0
    → Redo 基础检查通过后,跳过活动事务回滚和已提交事务 PURGE
    → 不负责修复缺失或损坏的 Redo

RLOG_CHECK_SPACE=2
    → 本次参考社区案例采用的实验值
    → 当前测试版本能够识别,并在本次现场中继续推进启动
    → 不代表所有版本和所有 Redo 故障都应设置为 2

需要再次区分:官方 FAQ 针对 Redo log try flush over space 给出的值是 RLOG_CHECK_SPACE=0,其含义为日志刷盘时不检查日志空间是否溢出;本次使用的值 2 来自社区案例和实际测试,公开 FAQ 没有给出值 2 的通用解释。

至于 enable_page_check,本次没有修改。虽然 dmmdf TYPE=1 查看 SYSTEM.DBF 时能看到:

enable_page_check=3

但当前版本执行:

./dmmdf TYPE=2 FILE=/dmdata/DAMENG/DAMENG01.log

Redo 文件头输出中没有 enable_page_check 字段,可修改列表里也没有对应编号:

You can only reset sta(4) or db_magic (6) or clsn (9) or clsn_fil(10)
or clsn_off(11) or pemnt_magic(12) or fil_id(13) or next_seq(15)
or g_next_seq(16) or p_db_magic(22) or n_apply_ep(23).

所以这一步不强行处理。第二次实验相对第一次,实际变化只有两处:

Redo 文件:
    仍然只修改 db_magic、pemnt_magic

dm.ini:
    新增 PSEG_RECV=0
    新增 RLOG_CHECK_SPACE=2

再次前台启动:

/dmdbms/bin/dmserver /dmdata/DAMENG/dm.ini

这次实例成功进入:

SYSTEM IS READY

17.jpeg
说明第一轮的失败点并不是 magic 不匹配。只改 Redo 身份信息时,数据库仍会在后续 Redo 检查或恢复阶段失败;本次测试环境在文件末尾补充 PSEG_RECV=0RLOG_CHECK_SPACE=2 后,实例获得了临时打开的机会。这个结果只能描述本次版本和本次现场,不能直接推广成通用固定组合。

但这仍然不能理解成“数据库已经修好”。本次实验的结论应当写得更克制:

替换 Redo + 修改 magic
    → 通过 Redo 文件身份检查

再配合 PSEG_RECV=0、RLOG_CHECK_SPACE=2
    → 本次测试库可以临时启动

临时启动成功
    → 只用于查询、导出、迁移和校验

启动成功后,应立即验证测试表:

SELECT * FROM TEST.T_REDO;

18.jpeg
如果测试数据可读,下一步就是逻辑导出、重建新库、导入校验。走到这一步,这次 Redo 抢救实验才算闭环。

另外,PSEG_RECV=0RLOG_CHECK_SPACE=2 是为了抢救数据临时加入的参数,不适合作为正常运行配置长期保留。完成导出迁移后,应以新库校验结果为准,而不是继续扩大故障库的使用范围。

八、总结

Redo 文件损坏修复最容易误解的地方,是把“启动成功”当成“数据库修好了”。

更稳妥的认识是:

  • Redo 完整时,数据库可以进行正常实例恢复;
  • Redo 丢失或损坏时,优先选择备份加归档恢复;
  • 生产环境必须保留可用备份和归档,并验证恢复链路;
  • 没有正规恢复条件时,替换 Redo 只是临时抢救数据;
  • 新 Redo 不能恢复原 Redo 中已经丢失的历史记录,故障附近尚未落盘的数据可能丢失,不能宣称全部恢复;
  • db_magicpemnt_magic 匹配只是第一层检查通过,不代表 Redo 包一定能解析;
  • 实际故障应根据启动日志定位具体损坏的 DAMENG01.logDAMENG02.log,单个文件有问题时只处理对应文件;
  • PSEG_RECV=0 不是修复 Redo,而是在 Redo 基础检查通过后高风险跳过事务恢复步骤;
  • 官方 FAQ 对 RLOG_CHECK_SPACE=0 的解释适用于“日志环被冲破”案例;本次使用的值 2 只记录为当前测试现象,不作通用参数解释;
  • enable_page_check 是否需要处理取决于版本和 dmmdf 输出,本次没有修改;
  • 故障库启动后,应立即导出迁移,不应继续作为正常生产库运行。

Redo 修复的目标不是让两个 .log 文件看起来正常,而是尽可能把数据从不完整的故障现场里带出来。能启动,只是拿到了抢救窗口;能迁移并校验,才是这类应急处理真正结束。

拓展参考资料

  • 达梦 FAQ:Redo 日志损坏时优先选择备份加归档恢复;无备份归档时,可尝试替换 Redo 后迁移数据;同一 FAQ 还说明了“日志环被冲破”场景中 RLOG_CHECK_SPACE=0 的用途。
    https://eco.dameng.com/document/dm/zh-cn/faq/faq-troubleshooting.html
  • 达梦社区《达梦redo损坏修复测试》:记录了替换 Redo 后继续通过 RLOG_CHECK_SPACE=2enable_page_check 等方式尝试启动的过程。
    https://eco.dameng.com/community/article/202212091743284X0SXIA8PR7HJSVE25
  • 达梦社区问答《报错 rlog4_adjust_clsn_off_4k rpkg decode failed》:可以作为本次第一轮实验失败现象的对照。
    https://eco.dameng.com/community/question/d6c5a788b4d1fba3b573e734f34be667
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服