达梦数据库数据页损坏修复实战指南
1. 概述
在日常数据库运维中,数据页损坏是较为严重的故障场景。当数据库中某个对象所在的数据页损坏,且该业务表有数据读写操作时,会导致数据库宕机。更严重的是,守护进程在拉起数据库进行回滚的过程中,如果涉及损坏的数据页,将导致数据库启动失败,整个集群无法恢复正常运行。
本文基于实际故障处理经验,详细记录MPP主备集群数据页损坏的修复流程,包括故障现象、恢复步骤、风险提示等关键信息。
2. 故障现象
2.1 数据页损坏时的读写报错
当数据页损坏的业务表有数据读写时,数据库日志会报错如下:
图1:数据页损坏时的读写报错日志
[错误信息示例] 数据页校验失败,xdec_move_from_nrec......2.2 数据库启动失败报错
数据库异常宕机后,守护进程尝试拉起数据库,但在回滚过程中涉及损坏的数据页,导致数据库启动失败,报错示例如下:
图2:数据库启动失败报错日志
[启动失败日志] 回滚过程中发现数据页损坏,无法继续恢复3. 恢复方案总览
整个恢复流程分为以下几个关键步骤:
- 主备切换尝试:首先尝试通过主备切换恢复集群
- 手动处理损坏对象:如果备库也同步了损坏数据,则需要手动处理
- 异常对象修复:定位并修复损坏的数据库对象
- 集群恢复:恢复正常集群运行状态
- 备库重建:通过备份还原恢复备库
4. 详细恢复步骤
4.1 主备切换
首先尝试通过监视器命令进行主备切换:
-- 切换指定组的指定库为PRIMARY库switchover[group_name[.]][db_name]-- 使用指定组的指定库接管故障PRIMARY库takeover[group_name[.]][db_name]-- 强制接管故障PRIMARY库takeoverforce[group_name[.]][db_name]注意事项:
- 正常切换后,对新主库进行全库备份,然后恢复到数据页损坏的备库
- 如果备库在同步过程中也复制了损坏的数据页,切换会失败,需要进入手动处理流程
4.2 手动处理主库损坏对象
4.2.1 停止集群并备份日志
- 停止整个MPP集群所有节点(守护进程、主库、备库)
- 备份故障时间段的数据库日志、归档日志、SQLLOG日志
# 备份日志示例cp-r/dm8/data/DAMENG/dmarch /dm8/data/DAMENG/dmarch_bakcp-r/home/dmdba/dmdbms/log /home/dmdba/dmdbms/log_bakcpdm8/data/DAMENG/logcommit dm8/data/DAMENG/logcommit_bak4.2.2 修改dm.ini参数
修改数据页损坏节点的dm.ini文件:
port_num = 6666 # 防止应用自动重连 pseg_recv = 0 # 跳过回滚 mal_ini = 0 # 关闭MAL系统 mpp_ini = 0 # 关闭MPP配置 ARCH_INI = 0 # 关闭归档,切断与其他节点通信4.2.3 启动损坏节点主库
以MOUNT模式启动数据页损坏节点主库,修改数据库状态为NORMAL并强制OPEN:
-- 启动数据库后执行SP_SET_PARA_VALUE(1,'ALTER_MODE_STATUS',1);alterdatabasenormal;ALTERDATABASEOPENFORCE;SP_SET_PARA_VALUE(1,'ALTER_MODE_STATUS',0);4.2.4 正常停库
使用命令正常停止数据库:
SHUTDOWNIMMEDIATE;关键检查点:确认数据库日志显示"shutdown successfully",非正常停库的实例无法进行dmdbchk检查。
4.2.5 使用dmdbchk找到问题对象
数据量小的情况
直接对整个数据库进行校验(适用于数据量较小的情况):
./dmdbchkpath=/dm8/data/DAMENG/dm.ini数据量大的情况
通过系统视图获取索引ID范围,分组进行多线程检查(适用于数据量较大的情况):
-- 获取最大最小索引IDSELECTMIN(ID),MAX(ID)FROMSYSINDEXES;假设ID范围差值为1059,分两组(500/559)进行检查:
# 第一组:ID 1-500./dmdbchkPATH=/dm8/data/DAMENG/dm.iniSTART_INDEXID=1END_INDEXID=500# 第二组:ID 500-1059./dmdbchkPATH=/dm8/data/DAMENG/dm.iniSTART_INDEXID=500END_INDEXID=1059dmdbchk输出日志示例:
检查结果
4.3 启动数据库处理异常对象
4.3.1 获取损坏对象信息
启动数据页损坏节点数据库服务,通过dmdbchk日志获取数据库中损坏的对象ID,通过SYSOBJECTS视图获取对应报错对象。对于索引进行删除后重建,业务表重命名后重建:
-- 通过对象ID获取对象名和对应模式SELECTowner,table_name,table_owner,INDEX_NAME,INDEX_typeFROMdba_indexesWHEREINDEX_NAMEIN(SELECTNAMEFROMSYSOBJECTSWHEREIDIN(对象ID1,对象ID2,对象ID3,...));4.4 恢复集群
4.4.1 恢复数据库配置
处理完损坏对象后,正常停库,然后恢复dm.ini原始配置:
port_num = 5236 # 恢复原端口 pseg_recv = 3 # 启用回滚 mal_ini = 1 # 启用MAL系统 mpp_ini = 1 # 启用MPP配置 ARCH_INI = 1 # 启用归档4.4.2 启动集群并检查状态
- 正常启动数据库
- 查看监视器状态,确认集群运行正常
4.4.3 修复损坏的表
对于损坏的业务表,采用重命名后重建的方式:
-- 1. 重命名原表ALTERTABLE模式名.表名RENAMETO表名_BAK;-- 示例ALTERTABLEFJQ.T1RENAMETOT1_BAK_20231101;4.4.4 修复损坏的索引
对于损坏的索引,删除后重建:
-- 1. 删除损坏的索引DROPINDEX"模式名"."索引名";-- 2. 如果是主键索引,先去掉主键约束ALTERTABLE"模式名"."表名"DROPPRIMARYKEY;-- 3. 重建索引(使用原索引DDL)CREATEINDEX"模式名"."索引名"ON"模式名"."表名"(列名);-- 4. 如果是主键,重新添加主键约束ALTERTABLE"模式名"."表名"ADDPRIMARYKEY(列名);4.4.5 踢出异常备库
踢出对应节点的备库,后续通过备份主库,还原备库方式恢复集群:
-- 在监视器中执行detachDATABASE组名.实例名4.5 备库重建(后续步骤)
备库踢出后,需要通过主库备份进行备库还原,恢复完整的集群架构:
- 对主库进行全库备份
- 在备库节点进行备份还原
- 重新配置守护进程
- 启动备库,建立主备同步
5. 风险提示与注意事项
5.1 方案局限性
- 不能直接修复数据:本方案主要修复数据页损坏的索引,不能直接修复表中损坏的数据
- 数据丢失风险:如果损坏对象是业务表数据或表结构,可能导致该表数据丢失
- 业务影响:修复过程中需要停库,对业务有影响
5.2 预防措施
- 定期备份:建立完善的备份策略,包括全量备份和增量备份
- 硬件检查:定期检查存储设备,避免硬件故障导致数据损坏
5.3 适用版本
本文档中的适配方法适用于所有DM8数据库版本以及数据架构。
6. 总结
达梦数据页损坏的修复是一个复杂且风险较高的操作,需要严格按照步骤执行。关键点包括:
- 优先尝试主备切换,减少业务中断时间
- 备份所有日志,便于问题定位和回退
- 分组进行dmdbchk检查,提高大库检查效率
- 谨慎处理损坏对象,避免数据丢失
- 完整测试恢复流程,确保集群稳定运行
建议在日常运维中加强监控和备份,防患于未然,降低数据页损坏带来的业务风险。
