一份手把手教你用"热拷贝"方式完成数据库恢复、主备搭建和DSC+DW集群重建的技术手册
在数据库运维的日常工作中,我们经常会遇到这样的需求:
达梦数据库提供的联机拷贝数据库还原技术,正是应对这些场景的一把利器。它允许我们在数据库不中断服务的情况下,通过拷贝数据文件并结合归档日志,完成数据库的完整还原。
本文将沿着"单机 → 主备集群 → 故障恢复 → DSC+DW集群"的技术演进路线,为您全面剖析这一技术的原理、操作细节和实战经验。
传统的数据库恢复通常依赖全量备份集,流程是:先做一次全备,然后定期做增量或归档备份,恢复时依次还原。这种方式虽然成熟稳定,但存在几个问题:
联机拷贝还原提供了一种新的思路:
核心思想:源库正常运行期间,直接拷贝其数据文件、控制文件、日志文件作为"物理副本",再结合源库的归档日志将副本恢复到最新状态。
这种方式相当于"文件系统级别的物理复制 + 归档日志重做"的组合,具有以下特点:
在开始操作之前,请务必牢记以下约束,否则操作会失败甚至导致数据不一致:
| 序号 | 约束 | 详细说明 | 违反后果 |
|---|---|---|---|
| 1 | 关闭自动提交 | 调用 SP_BACKUP_COPY_BEGIN 前需设置 AUTO_COMMIT = FALSE |
系统过程无法正确记录起始 LSN |
| 2 | 同一连接 | SP_BACKUP_COPY_BEGIN 和 SP_BACKUP_COPY_END 必须在同一个会话连接中执行 |
END 过程报错,无法生成备份集 |
| 3 | 禁止建表空间 | 两个过程之间不能执行 CREATE TABLESPACE 操作 |
表空间数据文件变化导致拷贝不一致 |
| 4 | 必须配置归档 | 联机拷贝前数据库必须已开启本地归档 | SP_BACKUP_COPY_END 执行报错 |
| 5 | 备份集专用性 | 生成的空备份集只能用于本次拷贝的副本还原 | 用于其他库还原会报错 |
SP_BACKUP_COPY_BEGIN 和 SP_BACKUP_COPY_END 的核心作用是记录拷贝时间窗口的起止位置:
还原恢复时,DMRMAN 利用归档日志,从 BEGIN_LSN 位置开始重做,直到 END_LSN(或最新状态),从而将副本恢复到一致状态。这个过程类似于 Oracle 的"基于 SCN 的不完全恢复"。
这是最基础的应用场景,也是理解整个技术栈的起点。我们将详细演示如何将一台运行中的单机数据库完整复制到另一台机器。
| 项目 | 源机器(A) | 目标机器(B) |
|---|---|---|
| 业务IP | 192.168.0.203 | 192.168.0.201 |
| 实例名 | DMSERVER | DMSERVER |
| 实例端口 | 5236 | 5236 |
| 安装目录 | /opt/dmdbms | /opt/dmdbms |
| 实例目录 | /opt/data/DAMENG | /opt/data/DB_COPY |
| 归档上限 | 1024 MB | 1024 MB |
说明:实际环境中 IP 和路径请根据现场调整。本例中源库数据目录为
/opt/data/DAMENG,目标副本目录为/opt/data/DB_COPY。
-- 首先关闭自动提交
SET AUTO_COMMIT = FALSE;
-- 调用 BEGIN 过程
SP_BACKUP_COPY_BEGIN();
执行效果:系统会在内部记录当前数据库的 LSN 和 SEQ 值,这些值将作为后续归档重做的起点。
执行结果示例:
DMSQL 过程已成功完成
已用时间: 5.123(毫秒). 执行号: 5.
注意事项:
拷贝开始后,使用常规方式(scp/rsync)将源库的完整数据目录拷贝到目标位置。
必须拷贝的文件清单:
| 文件类型 | 文件名示例 | 用途 |
|---|---|---|
| 配置文件 | dm.ini | 数据库初始化参数 |
| 控制文件 | dm.ctl | 数据库结构元数据 |
| 密钥文件 | dm_service.prikey | 加密服务密钥(如有加密) |
| 联机日志 | DAMENG01.log, DAMENG02.log | 在线重做日志 |
| 数据文件 | *.DBF | 表空间数据 |
| 临时文件 | TEMP.DBF | 临时表空间(可选,但建议包含) |
# 切换到源库数据目录
cd /opt/data/DAMENG
# 执行拷贝
scp dm.ini dm.ctl dm_service.prikey \
DAMENG01.log DAMENG02.log \
*.DBF 192.168.63.203:/opt/data/DB_COPY/
执行效果:
dm.ini 100% 23KB 2.3MB/s 00:00
dm.ctl 100% 7168 7.0MB/s 00:00
dm_service.prikey 100% 633 0.6MB/s 00:00
DAMENG01.log 100% 256MB 12.5MB/s 00:20
DAMENG02.log 100% 256MB 12.8MB/s 00:19
SYSTEM.DBF 100% 128MB 15.2MB/s 00:08
MAIN.DBF 100% 128MB 14.5MB/s 00:09
ROLL.DBF 100% 128MB 14.8MB/s 00:08
重要提醒:
rsync 或 nohup scp 在后台执行,避免会话超时中断在调用 END 过程之前,可以先查看源库的数据状态,以便后续对比验证。
-- 查看源库测试表数据
SELECT COUNT(*) FROM SYSDBA.TEST_TABLE;
-- 假设结果为 1000 行
SELECT * FROM SYSDBA.TEST_TABLE WHERE ROWNUM <= 10;
执行结果示例:
行号 ID NAME
------- ---------- ----------
1 1 测试数据1
2 2 测试数据2
...
10 10 测试数据10
拷贝完成后,调用 SP_BACKUP_COPY_END 结束拷贝阶段,并生成一个仅包含元数据(meta)的空备份集。
-- 参数指定空备份集的存放路径
SP_BACKUP_COPY_END('/opt/data/bakset_copy');
执行效果:
DMSQL 过程已成功完成
已用时间: 8.456(毫秒). 执行号: 8.
这个空备份集的内容:
重要提示:
归档未配置,无法生成备份集# 拷贝归档日志目录
cd /opt/data
scp -r arch/ 192.168.63.203:/opt/data/
# 拷贝空备份集
scp -r bakset_copy/ 192.168.63.203:/opt/data/
为什么需要拷贝归档日志?
这是整个过程中最容易出错的环节。目标库的副本来自源库,所有配置文件中记录的路径都是源库的绝对路径,必须全部修改为目标库的实际路径。
6.1 修改 dm.ini
cd /opt/data/DB_COPY/
vi dm.ini
需要修改的参数(标注 ### 的部分):
# 实例名(如果目标库需要使用不同实例名,在这里修改)
INSTANCE_NAME = DMSERVER
# 数据库文件路径(最关键!)
CTL_PATH = /opt/data/DB_COPY/dm.ctl ### 原为 /opt/data/DAMENG/dm.ctl
SYSTEM_PATH = /opt/data/DB_COPY/SYSTEM.DBF ### 原为 /opt/data/DAMENG/SYSTEM.DBF
ROLL_PATH = /opt/data/DB_COPY/ROLL.DBF ### 原为 /opt/data/DAMENG/ROLL.DBF
MAIN_PATH = /opt/data/DB_COPY/MAIN.DBF ### 原为 /opt/data/DAMENG/MAIN.DBF
# 日志文件路径
RLOG_PATH1 = /opt/data/DB_COPY/DAMENG01.log ### 原为 /opt/data/DAMENG/DAMENG01.log
RLOG_PATH2 = /opt/data/DB_COPY/DAMENG02.log ### 原为 /opt/data/DAMENG/DAMENG02.log
# 临时表空间路径(如有)
TEMP_PATH = /opt/data/DB_COPY/TEMP.DBF ### 原为 /opt/data/DAMENG/TEMP.DBF
# 归档配置(先关闭,后续根据需要重新配置)
ARCH_INI = 0 ### 临时关闭,避免路径冲突
# MAL 系统(单机不需要)
MAL_INI = 0
6.2 修改 dm.ctl(控制文件)
控制文件中记录了数据文件和日志文件的路径信息,必须同步修改。达梦提供了 dmctlcvt 工具来完成控制文件的"文本化"编辑。
Step 1:将二进制控制文件转换为文本文件
cd /opt/dmdbms/bin
./dmctlcvt type=1 src=/opt/data/DB_COPY/dm.ctl dest=/opt/data/DB_COPY/dm.txt
参数说明:
type=1:表示 二进制 → 文本src:源控制文件路径dest:目标文本文件路径执行结果:
DMCTLCVT V8
convert ctl file to txt file success!
Step 2:编辑文本文件修改路径
cd /opt/data/DB_COPY
vi dm.txt
需要修改的内容示例:
# 原文件内容(部分)
fil_path=/opt/data/DAMENG/SYSTEM.DBF
fil_path=/opt/data/DAMENG/ROLL.DBF
fil_path=/opt/data/DAMENG/MAIN.DBF
fil_path=/opt/data/DAMENG/DAMENG01.log
fil_path=/opt/data/DAMENG/DAMENG02.log
# 修改后
fil_path=/opt/data/DB_COPY/SYSTEM.DBF
fil_path=/opt/data/DB_COPY/ROLL.DBF
fil_path=/opt/data/DB_COPY/MAIN.DBF
fil_path=/opt/data/DB_COPY/DAMENG01.log
fil_path=/opt/data/DB_COPY/DAMENG02.log
注意:如果源库有用户表空间,也需要一并修改对应的文件路径。
Step 3:将文本文件转换回二进制控制文件
cd /opt/dmdbms/bin
./dmctlcvt type=2 src=/opt/data/DB_COPY/dm.txt dest=/opt/data/dm.ctl
参数说明:
type=2:表示 文本 → 二进制dest 指定了输出路径为 /opt/data/dm.ctlStep 4:将新控制文件移动到正确位置
mv /opt/data/dm.ctl /opt/data/DB_COPY/
现在准备工作就绪,可以开始真正的还原操作了。
cd /opt/dmdbms/bin
./dmrman
7.1 还原数据文件
RMAN> restore database '/opt/data/DB_COPY/dm.ini' overwrite from backupset '/opt/data/bakset_copy';
这里 overwrite 参数表示覆盖已有文件。即使目标目录中已有拷贝过来的数据文件,也会被备份集(虽然是空的)中的元数据重建。
执行过程:
restore database '/opt/data/DB_COPY/dm.ini' overwrite from backupset '/opt/data/bakset_copy';
file dm.key not exists, use default key!
restore of database + disql normal + append nolog +
restore start at 2024-07-25 14:32:18
restore end at 2024-07-25 14:32:20
restore success!
7.2 重做归档日志恢复数据
RMAN> recover database '/opt/data/DB_COPY/dm.ini' with archivedir '/opt/data/arch';
这一步会读取归档日志目录中的所有归档文件,从 BEGIN_LSN 开始重做,直到 END_LSN。
执行过程:
recover database '/opt/data/DB_COPY/dm.ini' with archivedir '/opt/data/arch';
recover start at 2024-07-25 14:32:25
recover begin lsn: 123456, seq: 100
recover end lsn: 124890, seq: 120
recover end at 2024-07-25 14:32:30
recover success!
7.3 更新数据库魔数(DB_MAGIC)
RMAN> recover database '/opt/data/DB_COPY/dm.ini' update db_magic;
这一步非常重要:更新 DB_MAGIC 使副本成为一个独立的数据库实例,避免与源库产生冲突。
执行过程:
recover database '/opt/data/DB_COPY/dm.ini' update db_magic;
recover start at 2024-07-25 14:32:35
update db_magic success!
recover end at 2024-07-25 14:32:36
recover success!
cd /opt/dmdbms/bin
./dmserver /opt/data/DB_COPY/dm.ini
启动成功后会看到类似输出:
DM Database Server x64 V8 1-2-1-2024.04.10-190000-10000-ENT startup...
Database mode = 0, oguid = 0
License will expire on 2025-07-10
Startup time: 2024-07-25 14:35:12
total system count: 1
Normal of GLOBAL
Server startup successfully, listen on port: 5236
验证数据一致性:
-- 连接到目标库
./disql SYSDBA/SYSDBA@127.0.0.1:5236
-- 查询测试表数据量与源库对比
SELECT COUNT(*) FROM SYSDBA.TEST_TABLE;
-- 应该与源库的 COUNT 结果一致
-- 检查最近插入的数据是否完整
SELECT * FROM SYSDBA.TEST_TABLE ORDER BY ID DESC FETCH FIRST 10 ROWS ONLY;
验证结果示例(源库 vs 目标库):
| 对比项 | 源库结果 | 目标库结果 | 状态 |
|---|---|---|---|
| 表总数 | 156 | 156 | ✅ 一致 |
| TEST_TABLE 行数 | 1000 | 1000 | ✅ 一致 |
| 最新插入记录 | ID=1000, '测试数据1000' | ID=1000, '测试数据1000' | ✅ 一致 |
| 优点 | 注意事项 |
|---|---|
| ✅ 源库全程在线,不中断业务 | ⚠️ 拷贝期间数据库必须保持归档可用 |
| ✅ 速度快,直接文件拷贝 | ⚠️ 路径修改必须彻底(dm.ini + dm.ctl) |
| ✅ 不需要全量备份集 | ⚠️ 空备份集具有专有性,不可混用 |
| ✅ 操作步骤清晰,可脚本化 | ⚠️ BEGIN/END 必须在同一连接中 |
掌握了单机拷贝还原后,我们可以将其应用到更复杂的场景——快速搭建主备集群。
传统主备集群搭建流程:
而联机拷贝方式:
核心优势:对于 TB 级数据库,传统方式可能需要数小时甚至数天的备份+传输+还原时间,而拷贝方式可能只需要几十分钟。
| 项目 | 主库(主机A) | 备库(主机B) |
|---|---|---|
| 业务IP | 192.168.0.201 | 192.168.0.203 |
| 心跳IP | 192.168.0.201 | 192.168.0.203 |
| 实例名 | GRP1_RT_01 | GRP1_RT_02 |
| 实例端口 | 5236 | 5236 |
| MAL端口 | 61141 | 61142 |
| MAL守护进程端口 | 33141 | 33142 |
| 守护进程端口 | 52141 | 52141 |
| OGUID | 453331 | 453331 |
| 守护组 | GRP1 | GRP1 |
| 实例目录 | /opt/data/DAMENG | /opt/data/DB_COPY |
-- 关闭自动提交
SET AUTO_COMMIT = FALSE;
-- 执行 BEGIN
SP_BACKUP_COPY_BEGIN();
这一步是为了验证拷贝期间的数据变更能否正确同步。
-- 创建测试表
CREATE TABLE SYSDBA.TEST_MASTER (
ID INT PRIMARY KEY,
NAME VARCHAR(100),
CREATE_TIME DATETIME DEFAULT SYSDATE
);
-- 批量插入数据(模拟拷贝期间的业务写入)
DECLARE
i INT := 1;
BEGIN
LOOP
INSERT INTO SYSDBA.TEST_MASTER (ID, NAME)
VALUES (i, '测试数据_' || TO_CHAR(i));
IF i = 100000 THEN
EXIT;
END IF;
i := i + 1;
END LOOP;
COMMIT;
END;
/
cd /opt/data/DAMENG
scp dm.ini dm.ctl dm_service.prikey \
DAMENG01.log DAMENG02.log \
*.DBF 192.168.63.203:/opt/data/DB_COPY/
SP_BACKUP_COPY_END('/opt/data/bakset_copy');
注意:此时主库可以继续运行,不需要停止。但如果后续需要修改主库配置,建议在完成拷贝后择机重启。
cd /opt/data
scp -r arch/ 192.168.63.203:/opt/data/
scp -r bakset_copy/ 192.168.63.203:/opt/data/
详细操作参见 2.2 步骤六,此处不再重复。
cd /opt/dmdbms/bin
./dmrman
RMAN> restore database '/opt/data/DB_COPY/dm.ini' overwrite from backupset '/opt/data/bakset_copy';
RMAN> recover database '/opt/data/DB_COPY/dm.ini' with archivedir '/opt/data/arch';
RMAN> recover database '/opt/data/DB_COPY/dm.ini' update db_magic;
vi /opt/data/DAMENG/dm.ini
关键参数设置:
INSTANCE_NAME = GRP1_RT_01
PORT_NUM = 5236
DW_INACTIVE_INTERVAL = 60
ALTER_MODE_STATUS = 0
ENABLE_OFFLINE_TS = 2
MAL_INI = 1
ARCH_INI = 1
RLOG_SEND_APPLY_MON = 64
vi /opt/data/DB_COPY/dm.ini
关键参数设置:
INSTANCE_NAME = GRP1_RT_02
PORT_NUM = 5236
DW_INACTIVE_INTERVAL = 60
ALTER_MODE_STATUS = 0
ENABLE_OFFLINE_TS = 2
MAL_INI = 1
ARCH_INI = 1
RLOG_SEND_APPLY_MON = 64
# 在主库创建并编辑
vi /opt/data/DAMENG/dmmal.ini
# 在备库创建相同内容
vi /opt/data/DB_COPY/dmmal.ini
MAL_CHECK_INTERVAL = 30
MAL_CONN_FAIL_INTERVAL = 30
[MAL_INST1]
MAL_INST_NAME = GRP1_RT_01
MAL_HOST = 192.168.63.201
MAL_PORT = 61141
MAL_INST_HOST = 192.168.63.201
MAL_INST_PORT = 5236
MAL_DW_PORT = 52141
MAL_INST_DW_PORT = 33141
[MAL_INST2]
MAL_INST_NAME = GRP1_RT_02
MAL_HOST = 192.168.63.203
MAL_PORT = 61142
MAL_INST_HOST = 192.168.63.203
MAL_INST_PORT = 5236
MAL_DW_PORT = 52142
MAL_INST_DW_PORT = 33142
参数说明:
| 参数 | 说明 |
|---|---|
| MAL_HOST | MAL 系统监听的 IP 地址 |
| MAL_PORT | MAL 系统监听的端口(用于节点间通信) |
| MAL_INST_HOST | 实例对外的服务 IP |
| MAL_INST_PORT | 实例对外的服务端口 |
| MAL_DW_PORT | 守护进程监听的端口 |
| MAL_INST_DW_PORT | 实例监听守护进程连接的端口 |
主库 (/opt/data/DAMENG/dmarch.ini):
[ARCHIVE_REALTIME]
ARCH_TYPE = REALTIME
ARCH_DEST = GRP1_RT_02
[ARCHIVE_LOCAL1]
ARCH_TYPE = LOCAL
ARCH_DEST = /opt/data/arch
ARCH_FILE_SIZE = 1024
ARCH_SPACE_LIMIT = 5120
备库 (/opt/data/DB_COPY/dmarch.ini):
[ARCHIVE_REALTIME]
ARCH_TYPE = REALTIME
ARCH_DEST = GRP1_RT_01
[ARCHIVE_LOCAL1]
ARCH_TYPE = LOCAL
ARCH_DEST = /opt/data/arch
ARCH_FILE_SIZE = 1024
ARCH_SPACE_LIMIT = 5120
主库 (/opt/data/DAMENG/dmwatcher.ini):
[GRP1]
DW_TYPE = GLOBAL
DW_MODE = AUTO
DW_ERROR_TIME = 10
INST_RECOVER_TIME = 60
INST_ERROR_TIME = 10
INST_OGUID = 453331
INST_INI = /opt/data/DAMENG/dm.ini
INST_AUTO_RESTART = 1
INST_STARTUP_CMD = /opt/dmdbms/bin/dmserver
RLOG_SEND_THRESHOLD = 0
RLOG_APPLY_THRESHOLD = 0
备库 (/opt/data/DB_COPY/dmwatcher.ini):
[GRP1]
DW_TYPE = GLOBAL
DW_MODE = AUTO
DW_ERROR_TIME = 10
INST_RECOVER_TIME = 60
INST_ERROR_TIME = 10
INST_OGUID = 453331
INST_INI = /opt/data/DB_COPY/dm.ini
INST_AUTO_RESTART = 1
INST_STARTUP_CMD = /opt/dmdbms/bin/dmserver
RLOG_SEND_THRESHOLD = 0
RLOG_APPLY_THRESHOLD = 0
启动主库(Mount 状态):
./dmserver /opt/data/DAMENG/dm.ini mount
配置主库:
./disql SYSDBA/SYSDBA
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
SQL> sp_set_oguid(453331);
SQL> alter database primary;
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
启动备库(Mount 状态):
./dmserver /opt/data/DB_COPY/dm.ini mount
配置备库:
./disql SYSDBA/SYSDBA
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
SQL> sp_set_oguid(453331);
SQL> alter database standby;
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
主库:
./dmwatcher /opt/data/DAMENG/dmwatcher.ini &
备库:
./dmwatcher /opt/data/DB_COPY/dmwatcher.ini &
vi /opt/data/dmmonitor.ini
MON_DW_CONFIRM = 1
MON_LOG_PATH = /opt/data/log
MON_LOG_INTERVAL = 60
MON_LOG_FILE_SIZE = 32
MON_LOG_SPACE_LIMIT = 0
[GRP1]
MON_INST_OGUID = 453331
MON_DW_IP = 192.168.63.201:52141
MON_DW_IP = 192.168.63.203:52142
cd /opt/dmdbms/bin
./dmmonitor /opt/data/dmmonitor.ini
正常状态应该显示:
GROUP OGUID MON_CONFIRM MODE MPP_FLAG
GRP1 453331 TRUE AUTO FALSE
INST_NAME INST_STATE MODE MSTATE RSTAT N_OPEN LSN
GRP1_RT_01 OPEN PRIMARY VALID VALID 1 124890
GRP1_RT_02 OPEN STANDBY VALID VALID 1 124890
| 步骤 | 操作 | 关键点 |
|---|---|---|
| 1 | 主库 BEGIN | 记录起始 LSN |
| 2 | 拷贝数据到备库 | 包含所有必需文件 |
| 3 | 主库 END | 生成空备份集 |
| 4 | 拷贝归档+备份集 | 用于恢复 |
| 5 | 备库修改路径 | dm.ini + dm.ctl |
| 6 | 备库 DMRMAN 还原 | 空备份集 + 归档重做 |
| 7 | 配置集群文件 | dmmal.ini/dmarch.ini/dmwatcher.ini |
| 8 | 启动集群 | 主库 PRIMARY / 备库 STANDBY |
在实际生产环境中,拷贝期间源库可能正在执行大量复杂的业务操作。本章将验证在 SP_BACKUP_COPY_BEGIN 和 SP_BACKUP_COPY_END 之间执行各类复杂操作后,拷贝还原的副本是否能保持数据一致性。
我们在拷贝时间窗口内,模拟以下复杂业务场景:
| 序号 | 操作类型 | 具体内容 | 目的 |
|---|---|---|---|
| 1 | 死循环插入 | 持续向大表插入数据 | 验证高频 DML 下的归档重做能力 |
| 2 | 触发器 | 创建 INSERT 触发器,更新关联表 | 验证触发器逻辑的正确同步 |
| 3 | 视图 | 创建跨表视图 | 验证视图元数据的同步 |
| 4 | DDL 操作 | 创建新表 | 验证 DDL 操作的同步 |
| 5 | 存储过程 | 创建并调用存储过程 | 验证程序对象的同步 |
-- 创建目标大表
CREATE TABLE SYSDBA.DM_VARCHAR (
ID INT IDENTITY(1,1) NOT NULL,
AES VARCHAR(1000) DEFAULT NULL,
SM4 VARCHAR(1000) DEFAULT NULL,
SM4_A VARCHAR(1000) DEFAULT NULL,
EMAIL VARCHAR(1000) DEFAULT NULL,
PHONE VARCHAR(1000) DEFAULT NULL,
SSN VARCHAR(1000) DEFAULT NULL,
MILITARY VARCHAR(1000) DEFAULT NULL,
CREDIT_CARD VARCHAR(1000) DEFAULT NULL,
JOB VARCHAR(1000) DEFAULT NULL,
NOT CLUSTER PRIMARY KEY(ID)
) STORAGE(ON "MAIN", CLUSTERBTR);
-- 死循环插入(拷贝期间持续运行)
DECLARE
i INT := 1;
BEGIN
LOOP
i := i + 1;
INSERT INTO SYSDBA.DM_VARCHAR (
AES, SM4, SM4_A, EMAIL, PHONE, SSN, MILITARY, CREDIT_CARD, JOB
) VALUES (
'胡小芬',
'北京xx网络技术有限公司',
'北京市',
'xxx@yahoo.com',
'15652996964',
'210302199608124861',
'武水电字第3632734号',
'6227612145830440',
'测试开发工程师'
);
COMMIT;
-- 注释掉的退出条件:可根据需要调整循环次数
-- EXIT WHEN i = 1000000;
END LOOP;
END;
/
-- 创建关联表 AAA(用于验证触发器效果)
CREATE TABLE SYSDBA.AAA (
ID INT PRIMARY KEY,
SORT INT DEFAULT 0
);
INSERT INTO SYSDBA.AAA VALUES (1, 0);
COMMIT;
-- 创建触发器:每次向 DM_VARCHAR 插入数据时,AAA 表的 SORT 列自动 +1
CREATE OR REPLACE TRIGGER SYSDBA.ABC
AFTER INSERT ON SYSDBA.DM_VARCHAR
FOR EACH STATEMENT
BEGIN
UPDATE SYSDBA.AAA SET SORT = SORT + 1;
END;
/
验证方法:拷贝前后分别查询 AAA 表的 SORT 值,应该等于 DM_VARCHAR 表的行数增量。
-- 创建基于 AAA 表的视图
CREATE VIEW SYSDBA.V_AAA AS
SELECT * FROM SYSDBA.AAA;
-- 创建另一个测试表
CREATE TABLE SYSDBA.BBB (
TEST1 CHAR(10),
TEST2 VARCHAR2(20)
);
INSERT INTO SYSDBA.BBB VALUES ('TEST', '测试数据');
COMMIT;
-- 创建测试表
CREATE TABLE SYSDBA.TEST_TABLE (
ID INT,
NAME VARCHAR(50)
);
-- 创建存储过程:插入 1-1000 之间的偶数
CREATE OR REPLACE PROCEDURE SYSDBA.INSERT_AND_PROCESS
IS
BEGIN
FOR i IN 1..1000 LOOP
IF MOD(i, 2) = 0 THEN
INSERT INTO SYSDBA.TEST_TABLE VALUES (i, 'test_' || TO_CHAR(i));
COMMIT;
END IF;
END LOOP;
END;
/
-- 调用存储过程
EXECUTE SYSDBA.INSERT_AND_PROCESS;
-- 验证结果
SELECT COUNT(*) FROM SYSDBA.TEST_TABLE;
-- 应该返回 500(1-1000 之间的偶数个数)
完成上述操作后,按照标准流程拷贝数据文件、调用 END 过程、还原备库,然后验证:
| 验证项 | 预期结果 | 验证方法 |
|---|---|---|
| DM_VARCHAR 表数据 | 与源库完全一致 | COUNT(*) 比对 |
| AAA.SORT 值 | 等于 DM_VARCHAR 行数 | SELECT 对比 |
| V_AAA 视图 | 与 AAA 表一致 | SELECT * 对比 |
| BBB 表 | 数据完整 | SELECT 查询 |
| TEST_TABLE 表 | 500 行偶数数据 | COUNT(*) = 500 |
| 存储过程 | 存在且可调用 | EXECUTE 测试 |
结论:即使在拷贝期间执行大量复杂的 DML/DDL 操作,通过联机拷贝 + 归档重做的方式,目标库依然能够完整、一致地恢复数据。
这是联机拷贝技术最实用的场景之一:当主备集群的主库数据文件被误删除后,如何利用备库和拷贝技术快速重建。
初始状态:一套正常运行的主备集群,主库为 GRP1_RT_01(IP: 192.168.63.201),备库为 GRP1_RT_02(IP: 192.168.63.203)。
故障发生:由于误操作,主库的所有数据文件被删除(可能是 rm -rf /opt/data/DAMENG/* 或类似操作)。
目标:在不重建集群的前提下,恢复主库的正常运行。
cd /opt/dmdbms/bin
./dmmonitor /opt/data/dmmonitor.ini
正常状态显示:
INST_NAME INST_STATE MODE MSTATE RSTAT N_OPEN
GRP1_RT_01 OPEN PRIMARY VALID VALID 1
GRP1_RT_02 OPEN STANDBY VALID VALID 1
cd /opt/data/DAMENG
rm -rf *
此时主库数据目录已被清空。
./dmserver /opt/data/DAMENG/dm.ini
报错信息类似:
dm_ctl_open failed, code=-1001, msg='file /opt/data/DAMENG/dm.ctl not found'
Database init failed!
这证实了主库已经无法正常启动。
在监视器界面中执行:
# 进入监视器命令模式
takeover force GRP1_RT_02
执行结果:
takeover force GRP1_RT_02
execute takeover force success!
此时备库 GRP1_RT_02 已成为新的主库。
再次查看集群状态:
INST_NAME INST_STATE MODE MSTATE RSTAT N_OPEN
GRP1_RT_01 MOUNT STANDBY INVALID INVALID 0
GRP1_RT_02 OPEN PRIMARY VALID VALID 1
-- 以 SYSDBA 登录新主库(原备库)
SET AUTO_COMMIT = FALSE;
SP_BACKUP_COPY_BEGIN();
参考第四章的示例,在拷贝窗口内执行一些 DML/DDL 操作,以验证恢复的数据完整性。
# 在新主库的数据目录执行
cd /opt/data/DAMENG
scp dm.ini dm.ctl dm_service.prikey DAMENG01.log DAMENG02.log *.DBF \
192.168.63.201:/opt/data/DAMENG/
注意:这里的目标 IP 是原主库(故障节点)的 IP。
SP_BACKUP_COPY_END('/opt/data/bakset_copy');
cd /opt/data
scp -r arch/ 192.168.63.201:/opt/data/
scp -r bakset_copy/ 192.168.63.201:/opt/data/
因为数据是从备库(新主库)拷贝过来的,需要将路径从备库路径修改为原主库路径。
修改 dm.ini:
cd /opt/data/DAMENG
vi dm.ini
# 将所有 /opt/data/DB_COPY 改为 /opt/data/DAMENG
修改 dm.ctl:
# 转换控制文件
./dmctlcvt type=1 src=/opt/data/DAMENG/dm.ctl dest=/opt/data/DAMENG/dm.txt
# 编辑修改路径
vi /opt/data/DAMENG/dm.txt
# 将 /opt/data/DB_COPY 全部替换为 /opt/data/DAMENG
# 转换回控制文件
./dmctlcvt type=2 src=/opt/data/DAMENG/dm.txt dest=/opt/data/DAMENG/dm.ctl
cd /opt/dmdbms/bin
./dmrman
RMAN> restore database '/opt/data/DAMENG/dm.ini' overwrite from backupset '/opt/data/bakset_copy';
RMAN> recover database '/opt/data/DAMENG/dm.ini' with archivedir '/opt/data/arch';
RMAN> recover database '/opt/data/DAMENG/dm.ini' update db_magic;
修改 dm.ini:
INSTANCE_NAME = GRP1_RT_01
PORT_NUM = 5236
# ... 其他参数与集群配置一致
确保配置文件完整:
启动故障节点并设置为备库:
./dmserver /opt/data/DAMENG/dm.ini mount
# 在 disql 中执行
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
SQL> sp_set_oguid(453331);
SQL> alter database standby;
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
# 主库(原备库)
./dmwatcher /opt/data/DAMENG/dmwatcher.ini &
# 备库(原主库,已恢复)
./dmwatcher /opt/data/DAMENG/dmwatcher.ini &
./dmmonitor /opt/data/dmmonitor.ini
正常状态:
INST_NAME INST_STATE MODE MSTATE RSTAT N_OPEN LSN
GRP1_RT_01 OPEN STANDBY VALID VALID 1 125000
GRP1_RT_02 OPEN PRIMARY VALID VALID 1 125000
| 步骤 | 操作 | 关键点 |
|---|---|---|
| 1 | 备库 takeover 切换为主库 | 确保业务不中断 |
| 2 | 在新主库执行 BEGIN | 记录恢复起点 |
| 3 | 拷贝数据到故障节点 | 注意路径映射 |
| 4 | 执行 END 生成备份集 | 记录恢复终点 |
| 5 | 故障节点 DMRMAN 还原 | 使用空备份集+归档 |
| 6 | 配置故障节点为备库 | 重新加入集群 |
| 7 | 启动守护进程 | 集群恢复运行 |
恢复完成时间:主要取决于数据文件拷贝时间 + 归档重做时间,对于 TB 级数据库,通常在 1-2 小时内完成。
本章介绍如何使用联机拷贝技术,从运行中的 DSC 集群拷贝数据,搭建一个全新的 DSC+DW 集群架构。
DSC(达梦共享集群):
DW(守护集群):
典型架构示意:
| 组件 | 节点1 | 节点2 | 备库节点 |
|---|---|---|---|
| 角色 | DSC_0 | DSC_1 | DSC_DW |
| 数据存储 | ASM 磁盘组 | ASM 磁盘组 | 本地磁盘 |
| 数据共享 | 共享存储 | 共享存储 | 独立存储 |
| 项目 | DSC_0 | DSC_1 | DSC_DW |
|---|---|---|---|
| 业务IP | 192.168.0.200 | 192.168.0.202 | 192.168.0.201 |
| 实例名 | GRP1_DSC_01 | GRP1_DSC_02 | DMSERVER |
| 实例端口 | 5236 | 5236 | 5236 |
| 安装目录 | /dm/dmdbms/dm8/dmdbms | /dm/dmdbms/dm8/dmdbms | /home/dmdba/dmdbms |
| 实例目录 | /dm/dmdbms/dm8/data | /dm/dmdbms/dm8/data | /opt/dm8 |
| 归档上限 | 51200 MB | 51200 MB | 51200 MB |
在 DSC 集群的任意节点执行,记录拷贝起点。
-- 以 SYSDBA 登录 DSC 节点
SET AUTO_COMMIT = FALSE;
SP_BACKUP_COPY_BEGIN();
由于 DSC 的数据存储在 ASM 磁盘组中,需要通过 dmasmtool 工具将数据从 ASM 拷贝出来。
# 进入 ASM 工具
cd /dm/dmdbms/dm8/bin
./dmasmtool dcr_ini=/dm/dmdbms/dm8/data/dmdcr.ini
# 拷贝 DSC 数据目录
ASM> cd DMDATA01/dmdata
ASM> cp -r xpcdsc /dm
# 拷贝用户表空间数据文件
ASM> cd +DMDATA02
ASM> cp *.dbf /dm
# 退出 ASM 工具,将本地文件传输到 DW 节点
cd /dm/
scp -r xpcdsc/ TEST1.dbf TEST2.dbf 192.168.63.201:/opt/dm8
# 拷贝 dm.ini 配置文件
cd dmdbms/dm8/data/xpcdsc1_config/
scp dm.ini 192.168.63.201:/opt/dm8/xpcdsc
关键说明:DSC 集群的数据文件分散在多个 ASM 磁盘组中,需要逐一确认并拷贝。本例中:
+DMDATA01/dmdata/xpcdsc/:存放系统表空间(SYSTEM、MAIN、ROLL)+DMDATA02/:存放用户表空间文件在 DSC 节点执行 END 过程,生成空备份集。
SP_BACKUP_COPY_END('/dm/bakset_copy');
这是最关键的步骤。DW 节点需要从 DSC 的 ASM 路径转换为本地文件系统路径。
4.1 修改 dm.ini
cd /opt/dm8/xpcdsc
vi dm.ini
需要修改:
+DMDATA01/dmdata/xpcdsc/ 路径改为 /opt/dm8/xpcdsc/MAL_INI = 1 改为 MAL_INI = 0(暂不启用 MAL,后续统一配置)4.2 修改 dm.ctl(控制文件)
# 将控制文件转为文本
cd /opt/dmdbms/bin
./dmctlcvt type=1 src=/opt/dm8/xpcdsc/dm.ctl dest=/opt/dm8/dm.txt
# 编辑文本文件
vi /opt/dm8/dm.txt
需要修改的内容:
# 原内容(DSC 集群有两个节点)
dsc_nodes=2
fil_path=+DMDATA01/dmdata/xpcdsc/SYSTEM.DBF
fil_path=+DMDATA01/dmdata/xpcdsc/MAIN.DBF
fil_path=+DMDATA01/dmdata/xpcdsc/ROLL.DBF
rlog_path=+DMLOG/DSC_0_LOG01.LOG
rlog_path=+DMLOG/DSC_0_LOG02.LOG
rlog_path=+DMLOG/DSC_1_LOG01.LOG
rlog_path=+DMLOG/DSC_1_LOG02.LOG
# 修改后(DW 为单节点)
dsc_nodes=1
fil_path=/opt/dm8/xpcdsc/SYSTEM.DBF
fil_path=/opt/dm8/xpcdsc/MAIN.DBF
fil_path=/opt/dm8/xpcdsc/ROLL.DBF
# 移除 DSC_1 的日志,只保留一组本地日志
rlog_path=/opt/dm8/xpcdsc/DAMENG01.LOG
rlog_path=/opt/dm8/xpcdsc/DAMENG02.LOG
重点注意:
dsc_nodes 必须从 2 改为 1fil_path 需要从 ASM 路径改为本地路径# 将文本文件转换回控制文件
./dmctlcvt type=2 src=/opt/dm8/dm.txt dest=/opt/dm8/dm.ctl
# 替换原有的控制文件
cd /opt/dm8/xpcdsc/
mv dm.ctl dm.ctl_bak
mv ../dm.ctl ./
5.1 将 DSC 生成的空备份集和归档拷贝到 DW 库
# 从 ASM 中拷贝归档文件到本地
cd /dm/dmdbms/dm8/bin
./dmasmtool dcr_ini=/dm/dmdbms/dm8/data/dmdcr.ini
ASM> cd DMDATA01
ASM> cp -r ARCH /dm
# 传输到 DW 节点
cd /dm
scp -r bakset_copy/ ARCH/ 192.168.63.201:/opt/dm8
5.2 使用 dmrman 工具还原
cd /opt/dmdbms/bin
./dmrman
RMAN> restore database '/opt/dm8/xpcdsc/dm.ini' from backupset '/opt/dm8/bakset_copy';
RMAN> recover database '/opt/dm8/xpcdsc/dm.ini' with archivedir '/opt/dm8/ARCH/DSC0/arch';
RMAN> recover database '/opt/dm8/xpcdsc/dm.ini' update db_magic;
在配置集群之前,需要先停止 DSC 节点的服务。
# DSC_0
cd /dm/dmdbms/dm8/bin
./DmWatcherServiceDSC01 stop
./DmServicexpcdsc1 stop
# DSC_1
./DmWatcherServiceDSC02 stop
./DmServicexpcdsc2 stop
7.1 修改 dmmal.ini(各节点配置一致)
MAL_CHECK_INTERVAL = 30
MAL_CONN_FAIL_INTERVAL = 30
[MAL_INST0]
MAL_INST_NAME = XPCDSC1
MAL_HOST = 192.168.63.200
MAL_PORT = 9340
MAL_INST_HOST = 192.168.63.200
MAL_INST_PORT = 5236
MAL_DW_PORT = 9338
MAL_INST_DW_PORT = 9339
[MAL_INST1]
MAL_INST_NAME = XPCDSC2
MAL_HOST = 192.168.63.202
MAL_PORT = 9340
MAL_INST_HOST = 192.168.63.202
MAL_INST_PORT = 5236
MAL_DW_PORT = 9338
MAL_INST_DW_PORT = 9339
[MAL_INST2]
MAL_INST_NAME = DMSERVER
MAL_HOST = 192.168.63.201
MAL_PORT = 9340
MAL_INST_HOST = 192.168.63.201
MAL_INST_PORT = 5236
MAL_DW_PORT = 9338
MAL_INST_DW_PORT = 9339
7.2 修改 dmarch.ini
DSC_0 (/dm/dmdbms/dm8/data/xpcdsc1_config/dmarch.ini):
ARCH_WAIT_APPLY = 0
[ARCHIVE_LOCAL1]
ARCH_TYPE = LOCAL
ARCH_DEST = +DMDATA01/ARCH/DSC0/arch
ARCH_FILE_SIZE = 1024
ARCH_SPACE_LIMIT = 51200
[ARCHIVE_REMOTE1]
ARCH_TYPE = REMOTE
ARCH_DEST = XPCDSC2
ARCH_INCOMING_PATH = +DMDATA01/ARCH/DSC1/arch
ARCH_FILE_SIZE = 1024
ARCH_SPACE_LIMIT = 51200
[ARCHIVE_REALTIME1]
ARCH_TYPE = REALTIME
ARCH_DEST = DMSERVER
DSC_1 配置类似,只需交换 REMOTE 和 LOCAL 的对应关系。
DSC_DW (/opt/dm8/xpcdsc/dmarch.ini):
[ARCHIVE_LOCAL1]
ARCH_TYPE = LOCAL
ARCH_DEST = /opt/dm8/arch
ARCH_FILE_SIZE = 1024
ARCH_SPACE_LIMIT = 51200
[ARCHIVE_REALTIME1]
ARCH_TYPE = REALTIME
ARCH_DEST = XPCDSC1/XPCDSC2
7.3 修改 dmwatcher.ini
DSC_0 (/dm/dmdbms/dm8/data/xpcdsc1_config/dmwatcher.ini):
[GRP1]
DW_TYPE = GLOBAL
DW_MODE = MANUAL
DW_ERROR_TIME = 60
INST_RECOVER_TIME = 60
INST_ERROR_TIME = 35
INST_INI = /dm/dmdbms/dm8/data/xpcdsc1_config/dm.ini
DCR_INI = /dm/dmdbms/dm8/data/dmdcr.ini
INST_OGUID = 453331
INST_STARTUP_CMD = /dm/dmdbms/dm8/bin/dmserver
INST_AUTO_RESTART = 0
RLOG_SEND_THRESHOLD = 0
RLOG_APPLY_THRESHOLD = 0
DSC_1 类似,注意 INST_INI 路径改为 xpcdsc2_config。
DSC_DW (/opt/dm8/xpcdsc/dmwatcher.ini):
[GRP1]
DW_TYPE = GLOBAL
DW_MODE = MANUAL
DW_ERROR_TIME = 60
INST_RECOVER_TIME = 60
INST_ERROR_TIME = 35
INST_INI = /opt/dm8/xpcdsc/dm.ini
INST_OGUID = 453331
INST_STARTUP_CMD = /opt/dmdbms/bin/dmserver
INST_AUTO_RESTART = 0
RLOG_SEND_THRESHOLD = 0
RLOG_APPLY_THRESHOLD = 0
DSC_0:
cd /dm/dmdbms/dm8/bin
./DmServicexpcdsc1 start
DSC_1:
cd /dm/dmdbms/dm8/bin
./DmServicexpcdsc1 start
# 配置 OGUID
./disql
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
SQL> sp_set_oguid(453331);
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
DSC_DW:
cd /opt/dmdbms/bin
./DmServiceDSC_DW start
# 配置为备库
./disql
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
SQL> sp_set_oguid(453331);
SQL> alter database standby;
SQL> SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
# DSC_0
cd /dm/dmdbms/dm8/bin
./DmWatcherServiceDSC01 start
# DSC_1
./DmWatcherServiceDSC02 start
# DSC_DW
cd /opt/dmdbms/bin
./DmWatcherServiceDSC_DW start
cd /opt/dm8
vi dmmonitor.ini
MON_DW_CONFIRM = 1
MON_LOG_PATH = /opt/data/log
MON_LOG_INTERVAL = 60
MON_LOG_FILE_SIZE = 32
MON_LOG_SPACE_LIMIT = 0
[GRP1]
MON_INST_OGUID = 453331
MON_DW_IP = 192.168.63.200:9338/192.168.63.202:9338
MON_DW_IP = 192.168.63.201:9338
cd /opt/dmdbms/bin
./dmmonitor /opt/dm8/dmmonitor.ini
| 序号 | 注意事项 | 说明 |
|---|---|---|
| 1 | ASM 路径转换 | DSC 到 DW 需要将 ASM 路径全部转换为本地路径 |
| 2 | dsc_nodes 修改 | 控制文件中必须将 dsc_nodes 从 2 改为 1 |
| 3 | RLOG 清理 | 需要移除 DSC 集群多余的联机日志条目 |
| 4 | 守护模式 | DSC+DW 集群建议使用 MANUAL(手动切换)模式 |
| 5 | 配置文件一致性 | dmmal.ini 必须在所有节点保持一致 |
| 特性 | 联机拷贝还原 | 传统备份还原 |
|---|---|---|
| 源库影响 | 低(仅文件 I/O) | 中(备份时可能有性能影响) |
| 速度 | 快(直接文件拷贝) | 中(备份集生成+压缩) |
| 适用场景 | 单机复制、主备搭建、故障重建 | 所有场景 |
| DSC+DW 支持 | 支持(需注意路径转换) | 完全支持 |
| 空间要求 | 需要额外存储存放副本 | 需要备份集存储空间 |
| 操作复杂度 | 中等(路径修改是关键) | 标准 |
| 序号 | 检查项 | 状态 |
|---|---|---|
| 1 | 源库已配置归档且归档正常 | ☐ |
| 2 | 目标目录有足够磁盘空间 | ☐ |
| 3 | BEGIN 前已关闭 AUTO_COMMIT | ☐ |
| 4 | BEGIN/END 在同一连接中执行 | ☐ |
| 5 | 拷贝了所有必需文件(.ini/.ctl/.log/.dbf) | ☐ |
| 6 | dm.ini 中所有路径已修改 | ☐ |
| 7 | dm.ctl 中所有路径已修改 | ☐ |
| 8 | DSC→DW 时已修改 dsc_nodes 参数 | ☐ |
| 9 | 使用正确的空备份集还原 | ☐ |
| 10 | 归档日志完整拷贝 | ☐ |
| 11 | 还原后更新了 DB_MAGIC | ☐ |
| 12 | 验证了数据一致性 | ☐ |
Q1:SP_BACKUP_COPY_END 报错"归档未配置"
SELECT * FROM V$ARCH_STATUSARCH_INI=1 并配置 dmarch.iniQ2:DMRMAN 还原时报错"备份集无效"
Q3:启动目标库时报错"控制文件路径错误"
dmctlcvt 重新转换并修改控制文件Q4:集群中备库无法同步
telnet IP PORTQ5:DW 节点启动报错关于 dsc_nodes
dsc_nodes 已从 2 改为 1-- 1. 开始拷贝
SET AUTO_COMMIT = FALSE;
SP_BACKUP_COPY_BEGIN();
-- 2. 结束拷贝
SP_BACKUP_COPY_END('/path/to/backup_set');
-- 3. 设置 OGUID
SP_SET_OGUID(453331);
-- 4. 切换数据库模式
ALTER DATABASE PRIMARY;
ALTER DATABASE STANDBY;
-- 1. 还原数据文件
RESTORE DATABASE '/path/to/dm.ini' OVERWRITE FROM BACKUPSET '/path/to/backup_set';
-- 2. 重做归档
RECOVER DATABASE '/path/to/dm.ini' WITH ARCHIVEDIR '/path/to/arch';
-- 3. 更新 DB_MAGIC
RECOVER DATABASE '/path/to/dm.ini' UPDATE DB_MAGIC;
# 二进制 → 文本
./dmctlcvt type=1 src=/path/to/dm.ctl dest=/path/to/dm.txt
# 文本 → 二进制
./dmctlcvt type=2 src=/path/to/dm.txt dest=/path/to/dm.ctl
# 进入 ASM 工具
./dmasmtool dcr_ini=/path/to/dmdcr.ini
# 创建磁盘组
CREATE DISKGROUP 'DMDATA01' ASMDISK '/dev/dm/asm-diskd';
# 复制文件到 ASM
CP /local/path/file '+DMDATA01/target/path/';
# 从 ASM 复制到本地
CP '+DMDATA01/source/file' /local/path/;
达梦数据库的联机拷贝还原技术,为数据库运维人员提供了一种高效、灵活的数据复制和恢复手段。从简单的单机复制,到主备集群的快速搭建,再到 DSC+DW 架构的平滑搭建,这一技术展现出了强大的实用价值。
在实际应用中,需要特别注意路径修改、控制文件参数调整等关键环节。尤其在 DSC+DW 场景下,从 ASM 磁盘组到本地文件系统的路径转换、dsc_nodes 参数的修改,都是决定成败的关键操作。
希望本文能为您的达梦数据库运维工作提供有价值的参考。
文章
阅读量
获赞
