本文档基于 CentOS 7 操作系统和达梦数据库 DM8 V8(20260707)版本,搭建一套由一个主库和一个备库组成的 DM8 数据守护(DataWatch)+ 读写分离集群。其中,数据守护负责实现主备数据库之间的实时数据同步、故障监测以及主备切换,为数据库提供高可用保障;读写分离则在数据守护的基础上,将写请求统一发送至主库执行,读请求根据配置策略自动分发至备库执行,从而降低主库压力,提高数据库整体的并发处理能力和资源利用率。
本实验采用两台 KVM 虚拟机分别部署主库和备库,通过配置数据库归档、MAL 通信、Watcher、Monitor 等组件,完成数据守护环境的搭建,并在此基础上配置客户端服务文件 dm_svc.conf,开启读写分离功能。实验过程中对主备实时同步、读请求转发、SQL 日志验证、事务统计验证以及客户端连接验证等功能进行测试,验证读写分离配置是否生效,并确保数据库系统在保证数据一致性的同时,实现读写请求分离处理,提高系统的可用性、可靠性及访问性能。
| 组件 | 规格/版本 |
|---|---|
| 虚拟化平台 | KVM(Kernel-based Virtual Machine) |
| 操作系统 | CentOS Linux 7 x86_64 |
| CPU | Intel® Xeon® 6966P-C(KVM虚拟CPU) |
| 内存 | 50GB |
| 磁盘 | 50GB |
| 数据库版本 | DM8 V8(20260707) |
# 检查嵌套虚拟化状态
cat /sys/module/kvm_intel/parameters/nested
N 或 0:未开启Y 或 1:已开启# 验证 CPU 是否支持硬件虚拟化扩展
grep -E '(vmx|svm)' /proc/cpuinfo
vmx):支持 Intel 虚拟化技术 (VT-x)# 临时开启嵌套虚拟化功能
modprobe -r kvm_intel
modprobe kvm_intel nested=1
# 永久开启
echo 'options kvm_intel nested=1' >> /etc/modprobe.d/kvm.conf
# 安装软件包
yum install -y qemu-kvm libvirt virt-install virt-manager libvirt-client bridge-utils
各组件说明:
# 启动并设置开机自启 libvirtd 服务
systemctl start libvirtd
systemctl enable libvirtd
# 检查内核模块是否加载
lsmod | grep kvm
输出应包含 kvm_intel 和 kvm,说明环境就绪。
# 创建存储目录
mkdir -p /var/lib/libvirt/images/iso
mkdir -p /var/lib/libvirt/images/vms
从宿主机传输 CentOS 镜像:
# 方法1:sftp 传输
sftp -P 5215 root@10.36.41.11
cd /var/lib/libvirt/images/iso/
put C:/study/06-iso/CentOS-7-x86_64-DVD-1804.iso
# 方法2:scp 传输
scp -P 5253 C:/study/06-iso/CentOS-7-x86_64-DVD-1804.iso root@10.36.41.11:/var/lib/libvirt/images/iso/
sudo virt-install \
--name dm-node1 \
--ram 4096 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/vms/dm-node1.qcow2,size=30,format=qcow2 \
--location /var/lib/libvirt/images/iso/CentOS-7-x86_64-DVD-1804.iso \
--network network=default \
--graphics none \
--os-type linux \
--os-variant centos7.0 \
--console pty,target_type=serial \
--extra-args 'console=ttyS0,115200n8 serial'
安装步骤:
English → United StatesAsia → ShanghaiMinimal Installdm-node1# 查看 IP 地址
ip addr show
# 关闭防火墙(两台虚拟机都需要)
sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo virt-install \
--name dm-node2 \
--ram 4096 \
--vcpus 2 \
--disk path=/var/lib/libvirt/images/vms/dm-node2.qcow2,size=30,format=qcow2 \
--location /var/lib/libvirt/images/iso/CentOS-7-x86_64-DVD-1804.iso \
--network network=default \
--graphics none \
--os-type linux \
--os-variant centos7.0 \
--console pty,target_type=serial \
--extra-args 'console=ttyS0,115200n8 serial'
# 连接 dm-node1
ssh root@192.168.122.67
# 连接 dm-node2
ssh root@192.168.122.139
在宿主机上执行:
# 检查连通性
ping 192.168.122.67
# 传输 DM8 安装包到 dm-node1
scp /mnt/nas/dm8_20260710_x86_centos7_64.iso root@192.168.122.67:/opt/
参照《达梦数据库 DM8 在 Kylin V10 SP3 上的安装部署手册》的步骤,在两台机器上都创建监控器日志保存目录:
mkdir -p /dmdata/log
chown -R dmdba:dinstall /dmdata/log
chmod -R 755 /dmdata/log
按照《达梦数据库 DM8 在 Kylin V10 SP3 上的安装部署手册》中的步骤进行安装。
重要提示:安装完成后需要启动 DMAP 服务,否则会影响后续的数据库备份:
cd /home/dmdba/dmdbms/bin
./DmAPService start
# 实例初始化
./dminit path=/dmdata/data INSTANCE_NAME=DMSERVER01 DB_NAME=DMDBA PORT_NUM=5234 PAGE_SIZE=32 EXTENT_SIZE=32 CASE_SENSITIVE=y CHARSET=1 LOG_SIZE=2048 SYSDBA_PWD=Dmdba123 SYSAUDITOR_PWD=Dmdba123
# 注册服务
./dm_service_installer.sh -t dmserver -dm_ini /dmdata/data/DMDBA/dm.ini -p DMSERVER01
# 拍摄快照
virsh snapshot-create-as dm-node1 snap_dm_installed --description "进行数据守护集群搭建前"
virsh snapshot-list dm-node1
# 停止服务
systemctl stop DmServiceDMSERVER01
# 实例初始化(仅为了生成配置文件和目录)
./dminit path=/dmdata/data INSTANCE_NAME=DMSERVER02 DB_NAME=DMDBA PORT_NUM=5234 PAGE_SIZE=32 EXTENT_SIZE=32 CASE_SENSITIVE=y CHARSET=1 LOG_SIZE=2048 SYSDBA_PWD=Dmdba123 SYSAUDITOR_PWD=Dmdba123
# 注册服务
./dm_service_installer.sh -t dmserver -dm_ini /dmdata/data/DMDBA/dm.ini -p DMSERVER02
# 拍摄快照
virsh snapshot-create-as dm-node2 snap_before_dm_protect --description "进行数据守护集群搭建前"
# 停止服务
systemctl stop DmServiceDMSERVER02
| 参数 | dm-node1 (主) | dm-node2 (备) |
|---|---|---|
| IP | 192.168.122.67 | 192.168.122.139 |
| 实例端口 (PORT_NUM) | 5234 | 5234 |
| MAL 监听端口 (MAL_PORT) | 5235 | 5235 |
| 守护进程端口 (MAL_DW_PORT) | 5236 | 5236 |
| 实例监听守护进程 TCP 连接的端口 (MAL_INST_DW_PORT) | 5237 | 5237 |
| OGUID | 45331 | 45331 |
vi /dmdata/data/DMDBA/dm.ini
修改以下参数:
INSTANCE_NAME = DMSERVER01
PORT_NUM = 5234 # 数据库实例监听端口
DW_INACTIVE_INTERVAL = 60 # 接收守护进程消息超时时间
ALTER_MODE_STATUS = 0 # 不允许手工方式修改实例模式/状态/OGUID
ENABLE_OFFLINE_TS = 2 # 不允许备库 OFFLINE 表空间
MAL_INI = 1 # 打开 MAL 系统
ARCH_INI = 1 # 打开归档配置
RLOG_SEND_APPLY_MON = 64 # 统计最近 64 次的日志发送信息
vi /dmdata/data/DMDBA/dmmal.ini
配置内容:
MAL_CHECK_INTERVAL = 5
MAL_CONN_FAIL_INTERVAL = 5
[MAL_INST1]
MAL_INST_NAME = DMSERVER01
MAL_HOST = 192.168.122.67
MAL_PORT = 5235
MAL_INST_HOST = 192.168.122.67
MAL_INST_PORT = 5234
MAL_DW_PORT = 5236
MAL_INST_DW_PORT = 5237
[MAL_INST2]
MAL_INST_NAME = DMSERVER02
MAL_HOST = 192.168.122.139
MAL_PORT = 5235
MAL_INST_HOST = 192.168.122.139
MAL_INST_PORT = 5234
MAL_DW_PORT = 5236
MAL_INST_DW_PORT = 5237
vi /dmdata/data/DMDBA/dmarch.ini
配置内容:
[ARCHIVE_TIMELY]
ARCH_TYPE = TIMELY
ARCH_DEST = DMSERVER02 # 指向备库实例名
ARCH_WAIT_APPLY = 0
[ARCHIVE_LOCAL1]
ARCH_TYPE = LOCAL
ARCH_DEST = /dmdata/arch
ARCH_FILE_SIZE = 128
ARCH_SPACE_LIMIT = 0
# 启动数据库
./DmServiceDMSERVER01 start
# 连接数据库
./disql SYSDBA/Dmdba123@localhost:5234
# 查看归档状态
SELECT * FROM V$ARCH_STATUS;
# 执行完全备份
BACKUP DATABASE FULL BACKUPSET '/dmdata/dmbak/db_full_bak_01';
# 查看备份结果
ls -lh /dmdata/dmbak/db_full_bak_01
# 复制备份到备库
scp -r /dmdata/dmbak/db_full_bak_01 dmdba@192.168.122.139:/dmdata/dmbak/
ps -ef | grep dmserver
cd /home/dmdba/dmdbms/bin
./dmrman CTLSTMT="CHECK BACKUPSET '/dmdata/dmbak/db_full_bak_01';"
./dmrman CTLSTMT="RESTORE DATABASE '/dmdata/data/DMDBA/dm.ini' FROM BACKUPSET '/dmdata/dmbak/db_full_bak_01';"
./dmrman CTLSTMT="RECOVER DATABASE '/dmdata/data/DMDBA/dm.ini' FOR STANDBY FROM BACKUPSET '/dmdata/dmbak/db_full_bak_01';"
# 修改 dm.ini(只需修改实例名)
vi /dmdata/data/DMDBA/dm.ini
# INSTANCE_NAME = DMSERVER02
# 修改 dmmal.ini(与主库一致)
vi /dmdata/data/DMDBA/dmmal.ini
# 修改 dmarch.ini(只需修改归档目标)
vi /dmdata/data/DMDBA/dmarch.ini
# ARCH_DEST = DMSERVER01 # 指向主库实例名
# 停止数据库后以 MOUNT 状态启动
./dmserver /dmdata/data/DMDBA/dm.ini mount
新开终端窗口,登录数据库执行:
-- 允许修改模式状态
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
-- 修改数据库模式为主库
ALTER DATABASE PRIMARY;
-- 设置 OGUID(需与 dmwatcher.ini 中一致)
SP_SET_OGUID(45331);
-- 恢复模式状态保护
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
同样以 MOUNT 状态启动:
./dmserver /dmdata/data/DMDBA/dm.ini mount
登录数据库执行:
-- 允许修改模式状态
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 1);
-- 修改数据库模式为备库
ALTER DATABASE STANDBY;
-- 设置 OGUID
SP_SET_OGUID(45331);
-- 恢复模式状态保护
SP_SET_PARA_VALUE(1, 'ALTER_MODE_STATUS', 0);
配置结束后关闭 MOUNT 前台进程。
两台机器都创建:
vi /dmdata/data/DMDBA/dmwatcher.ini
配置内容:
[GRP1]
DW_TYPE = GLOBAL
DW_MODE = AUTO
DW_ERROR_TIME = 10
INST_RECOVER_TIME = 60
INST_ERROR_TIME = 10
INST_OGUID = 45331
INST_INI = /dmdata/data/DMDBA/dm.ini
INST_AUTO_RESTART = 1
INST_STARTUP_CMD=/home/dmdba/dmdbms/bin/DmServiceDMSERVER01 start
RLOG_SEND_THRESHOLD = 0
RLOG_APPLY_THRESHOLD = 0
注意:dm-node2 中的 INST_STARTUP_CMD 需要修改为:
INST_STARTUP_CMD=/home/dmdba/dmdbms/bin/DmServiceDMSERVER02 start
以 root 用户执行:
cd /home/dmdba/dmdbms/script/root
# 在 dm-node1 注册
./dm_service_installer.sh -t dmwatcher -watcher_ini /dmdata/data/DMDBA/dmwatcher.ini -p DMSERVER01_WATCHER
# 在 dm-node2 注册
./dm_service_installer.sh -t dmwatcher -watcher_ini /dmdata/data/DMDBA/dmwatcher.ini -p DMSERVER02_WATCHER
# 查看服务是否注册成功
systemctl list-unit-files | grep WATCHER
监视器可以部署在任意一台节点上,或者单独的第三台机器。这里部署在 dm-node1 上。
vi /dmdata/data/DMDBA/dmmonitor.ini
配置内容:
MON_DW_CONFIRM = 1
MON_LOG_PATH = /dmdata/log
MON_LOG_INTERVAL = 60
MON_LOG_FILE_SIZE = 32
MON_LOG_SPACE_LIMIT = 0
[GRP1]
MON_INST_OGUID = 45331
MON_DW_IP = 192.168.122.67:5236
MON_DW_IP = 192.168.122.139:5236
在 DM8 数据守护(DataWatch)中,启动顺序非常重要:先启动数据库实例,再启动 Watcher,最后启动 Monitor。
# 启动数据库实例
systemctl start DmServiceDMSERVER01
# 检查服务状态
systemctl status DmServiceDMSERVER01
# 启动数据库实例
systemctl start DmServiceDMSERVER02
# 检查服务状态
systemctl status DmServiceDMSERVER02
注意:如果角色没有正确设置,不要启动 Watcher。因为 Watcher 启动后会认为数据库状态异常。
# 在 dm-node1 启动 Watcher
systemctl start DmWatcherServiceDMSERVER01_WATCHER
# 在 dm-node2 启动 Watcher
systemctl start DmWatcherServiceDMSERVER02_WATCHER
# 检查 Watcher 状态
systemctl status DmWatcherServiceDMSERVER01_WATCHER
systemctl status DmWatcherServiceDMSERVER02_WATCHER
# 切换到 dmdba 用户
su - dmdba
# 启动 Monitor
cd /home/dmdba/dmdbms/bin
./dmmonitor /dmdata/data/DMDBA/dmmonitor.ini
进入 Monitor 控制台后,可以查看集群状态:
-- 查看集群状态
show;
正常输出应显示两个实例均为 OPEN 状态,且主备关系正确。
# 切换到 root 用户
su - root
# 编辑配置文件
vi /etc/dm_svc.conf
添加以下配置内容:
# 定义服务名,指向主库和备库
RWW_SVC=(192.168.122.67:5234,192.168.122.139:5234)
# 全局设置(可选)
TIME_ZONE=(480)
LANGUAGE=(CN)
# 读写分离专用配置
[RWW_SVC]
RW_SEPARATE=(1) # 启用读写分离
RW_PERCENT=(0) # 主库承担 0% 的读事务
LOGIN_MODE=(1) # 优先连接主库
SWITCH_TIMES=(60)
SWITCH_INTERVAL=(1000)
保存退出(:wq),并确保 dmdba 用户可读:
chmod 644 /etc/dm_svc.conf
方法的原理是:读写分离生效时,备库会收到从主库转发来的查询请求,并记录在自身的 SQL 日志中。
# 切换到 dmdba 用户
su - dmdba
# 连接备库
cd /home/dmdba/dmdbms/bin
./disql SYSDBA/Dmdba123@localhost:5234
在 SQL 命令行中执行:
-- 开启 SQL 日志
SP_SET_PARA_VALUE(1, 'SVR_LOG', 1);
-- 查看日志参数是否生效
SELECT NAME, VALUE FROM V$PARAMETER WHERE NAME='SVR_LOG';
# 切换到 dmdba 用户
su - dmdba
# 连接主库
cd /home/dmdba/dmdbms/bin
./disql SYSDBA/Dmdba123@localhost:5234
在 SQL 命令行中执行:
-- 在主库上创建表(写操作会在主库执行)
CREATE TABLE TEST_RW(ID INT, NAME VARCHAR(50));
INSERT INTO TEST_RW VALUES(1, '主库写入');
COMMIT;
-- 查询操作会根据 RW_PERCENT 决定是否发往备库
SELECT * FROM TEST_RW;
在备库节点(dm-node2)上查看 SQL 日志:
# 查看最新的 SQL 日志文件
ls -lt /home/dmdba/dmdbms/log/dmsql_*.log | head -1
# 实时查看日志(替换为实际文件名)
tail -f /home/dmdba/dmdbms/log/dmsql_DMSERVER02_20260715_131657.log
如果读写分离配置生效,应该能看到类似以下内容:
2026-07-15 13:16:57.123 [INFO] SELECT * FROM TEST_RW;
客户端 IP: ::ffff:192.168.122.67
这表明查询是通过读写分离机制从主库自动转发到备库执行的,而非手动连接备库执行。
# 连接主库(直连或服务名均可)
./disql SYSDBA/Dmdba123@192.168.122.67:5234
# 查询当前总会话数
select * from v$sysstat where name like 'transaction commit count' or name like 'transaction rollback count';
# 连接备库
./disql SYSDBA/Dmdba123@192.168.122.139:5234
# 查询当前总会话数
SELECT COUNT(*) FROM V$SESSIONS;
只要读写分离生效,主库和备库上都会同时存在同一个客户端的连接会话。
# 连接备库
./disql SYSDBA/Dmdba123@192.168.122.139:5234
# 查看事务统计信息
SELECT * FROM V$SYSSTAT WHERE NAME LIKE 'transaction commit count' OR NAME LIKE 'transaction rollback count';
主库执行select前:
主库执行select后:
文章
阅读量
获赞
