读写分离的实现,依赖于驱动(如 DM JDBC、DPI 等)与 dm_svc.conf 文件的深度配合,整个过程对应用层代码透明。其核心路由逻辑如下:
拓扑感知与连接分配:
应用发起连接时,接口会根据 dm_svc.conf 中配置的 IP 列表进行**“裂变访问”,探测并获取当前集群的主、备机信息**。随后,严格根据配置的 LOGIN_MODE(登录模式)参数来返回相应的节点:
0(默认值):优先连主库(Primary) → 其次普通库(Normal) → 最后备库(Standby)
1:只连主库(Primary)
2:只连备库(Standby)
3:优先连备库(Standby) → 其次主库(Primary) → 最后普通库(Normal)
4:优先连普通库(Normal) → 其次主库(Primary) → 最后备库(Standby)
试探性路由分发:
在开启读写分离RW_SEPARATE=(1)后,接口在处理 SQL 时采用了试错策略:
优先抛给备库:接口会优先把 SQL 语句发送到备库去执行。
成功即返回:如果是普通的 SELECT 查询,备库执行成功,结果就直接返回给用户,完美分担压力。
失败切主库:如果是 INSERT/UPDATE/DELETE 或是DDL 语句,备库(因为是只读状态)执行必然会报错。接口在底层瞬间捕获到这个失败后,会立刻将同一个事务里的所有操作,全部打包重新发送给主库去执行。只要发生了切主,该事务周期内的后续所有 SQL 都会死死锁定在主库上,保证数据绝对的一致性。
| <br />1 机器 | 2 机器 | 3 机器(异步) | |
|---|---|---|---|
| 业务 IP | 192.168.163.131 | 192.168.163.132 | 192.168.163.135 |
| 心跳 IP | 192.168.163.133 | 192.168.163.134 | 192.168.163.136 |
| 实例名 | DMPRD1 | DMPRD2 | DMPRD3 |
| 实例端口 | 15236 | 15236 | 15236 |
| MAL 端口 | 5336 | 5337 | 5338 |
| MAL 守护进程端口 | 5436 | 5437 | 5438 |
| 守护进程端口 | 5536 | 5537 | 5538 |
| INST_OGUID | 45332 | 45332 | 45332 |
| 守护组 | DMPRD | DMPRD | DMPRD |
| 安装路径 | home/dmdba/dmdbms | home/dmdba/dmdbms | /home/dmdba/dmdbms |
| 实例路径 | /dmdata/data2 | /dmdata/data2 | /dmdata/data2 |
| 归档路径 | /dmadata/arch2 | /dmadata/arch2 | /dmadata/arch2 |
| 归档上限(MB) | 51200 | 51200 | 51200 |
| 确认监视器 IP | 192.168.163.128 |
#安装略,初始化数据库
dminit path=/dmdata/data2 page_size=32 instance_name=dmprd1 extent_size=32 log_size=2048 PORT_NUM=15236 CHARSET=1 sysdba_pwd=Dameng123 SYSAUDITOR_PWD=Dameng123
#启动服务,开启归档
dmserv /dmdata/data2/DAMENG/dm.ini
SQL> ALTER DATABASE MOUNT;
SQL> ALTER DATABASE ARCHIVELOG;
SQL> ALTER DATABASE ADD ARCHIVELOG 'DEST=/dmdata/arch2, TYPE=LOCAL, FILE_SIZE=1024, SPACE_LIMIT=51200';
SQL> ALTER DATABASE OPEN;
SQL> CHECKPOINT(100);
#备份数据库
backup database backupset '/dmdata/dmbak/fullprdbak0610';
#修改dm.ini
SQL> SP_SET_PARA_VALUE (2,'PORT_NUM',15236);
SQL> SP_SET_PARA_VALUE (2,'DW_INACTIVE_INTERVAL',60); -- 守护进程心跳间隔
SQL> SP_SET_PARA_VALUE (2,'ALTER_MODE_STATUS',0); -- 禁止手工切换主备角色,防止误操作
SQL> SP_SET_PARA_VALUE (2,'ENABLE_OFFLINE_TS',2); -- 允许备库表空间脱机
SQL> SP_SET_PARA_VALUE (2,'MAL_INI',1); -- 开启 MAL 通信,集群必须开
SQL> SP_SET_PARA_VALUE (2,'ARCH_INI',1); -- 开启归档,集群必须开
SQL> SP_SET_PARA_VALUE (2,'TIMER_INI',1); -- 开启定时器,给异步归档用
SQL> SP_SET_PARA_VALUE (2,'RLOG_SEND_APPLY_MON',64); -- 监控发送/应用日志的滑动窗口大小
#关闭前台实例
#修改dmarch.ini
[dmdba@~]$ vi /dmdata/data2/DAMENG/dmarch.ini
ARCH_WAIT_APPLY = 0 #0:高性能 1:事务一致
[ARCHIVE_LOCAL]
ARCH_TYPE = LOCAL #本地归档类型
ARCH_DEST = /data/dmdata/arch/ #本地归档存放路径
ARCH_FILE_SIZE = 1024 #单个归档大小,单位 MB
ARCH_SPACE_LIMIT = 51200 #归档上限,单位 MB
[ARCHIVE_REALTIME1]
ARCH_TYPE = REALTIME #实时归档类型
ARCH_DEST = DMPRD2 #实时归档目标实例名
[ARCHIVE_ASYNC]
ARCH_TYPE = ASYNC # 异步归档,按定时器批量推
ARCH_DEST = DMPRD3 # 目标是异步备库的实例名
ARCH_TIMER_NAME = TIMER1 # 关联哪个定时器(在 dmtimer.ini 里定义)
#修改dmmal.ini
[dmdba@~]$ vi /dmdata/data2/DAMENG/dmmal.ini
MAL_CHECK_INTERVAL = 10 #MAL 链路检测时间间隔
MAL_CONN_FAIL_INTERVAL = 10 #判定 MAL 链路断开的时间
MAL_TEMP_PATH = /data/dmdata/malpath/ #临时文件目录
MAL_BUF_SIZE = 512 #单个 MAL 缓存大小,单位 MB
MAL_SYS_BUF_SIZE = 2048 #MAL 总大小限制,单位 MB
MAL_COMPRESS_LEVEL = 0 #MAL 消息压缩等级,0 表示不压缩
[MAL_INST1]
MAL_INST_NAME = DMPRD1 #实例名,和 dm.ini 的 INSTANCE_NAME 一致
MAL_HOST = 192.168.163.133 #MAL 系统监听 TCP 连接的 IP 地址
MAL_PORT = 5336 #MAL 系统监听 TCP 连接的端口
MAL_INST_HOST = 192.168.163.131 #实例的对外服务 IP 地址
MAL_INST_PORT = 15236 #实例对外服务端口,和 dm.ini 的 PORT_NUM 一致
MAL_DW_PORT = 5436 #实例对应的守护进程监听 TCP 连接的端口
MAL_INST_DW_PORT = 5536 #实例监听守护进程 TCP 连接的端口
[MAL_INST2]
MAL_INST_NAME = DMPRD2
MAL_HOST = 192.168.163.134
MAL_PORT = 5337
MAL_INST_HOST = 192.168.163.132
MAL_INST_PORT = 15236
MAL_DW_PORT = 5437
MAL_INST_DW_PORT = 5537
[MAL_INST3]
MAL_INST_NAME = DMPRD3
MAL_HOST = 192.168.163.136
MAL_PORT = 5338
MAL_INST_HOST = 192.168.163.135
MAL_INST_PORT = 15236
MAL_DW_PORT = 5438
MAL_INST_DW_PORT = 5538
#配置dmwatcher,这里配置的手动切换
[dmdba@~]$ vi /dmdata/data2/DAMENG/dmwatcher.ini
[DMPRD]
DW_TYPE = GLOBAL #全局守护类型
DW_MODE = MANUAL #MANUAL:故障手切 AUTO:故障自切
DW_ERROR_TIME = 20 #远程守护进程故障认定时间
INST_ERROR_TIME = 20 #本地实例故障认定时间
INST_RECOVER_TIME = 60 #主库守护进程启动恢复的间隔时间
INST_OGUID = 45331 #守护系统唯一 OGUID 值
INST_INI = /dmdata/data2/DAMENG/dm.ini #dm.ini 文件路径
INST_AUTO_RESTART = 1 #打开实例的自动启动功能
INST_STARTUP_CMD = /home/dmdba/dmdbms/bin/dmserver #命令行方式启动
RLOG_SEND_THRESHOLD = 0 #指定主库发送日志到备库的时间阈值,默认关闭
RLOG_APPLY_THRESHOLD = 0 #指定备库重演日志的时间阈值,默认关闭
#配置timer.ini
[dmdba@~]$ vi /dmdata/data2/DAMENG/dmtimer.ini
[TIMER1]
TYPE = 2 # 按日执行模式
FREQ_MONTH_WEEK_INTERVAL = 1 # 间隔周/月数
FREQ_SUB_INTERVAL = 1 # 间隔天数
FREQ_MINUTE_INTERVAL = 1 # 间隔分钟数,这里设 1 分钟推一次
START_TIME = 00:00:00
END_TIME = 00:00:00 # 开始和结束都是 00:00:00 代表全天有效
DURING_START_DATE = 2020-01-01 01:01:01
DURING_END_DATE = 9999-12-31 23:59:59
NO_END_DATE_FLAG = 1
DESCRIBE = RT TIMER
IS_VALID = 1
#拷贝备份文件到备库和异步库
[dmdba@dm4 dmbak]$ scp -r fullprdbak0610/ dmdba@192.168.163.132:/dmdata/dmbak/
[dmdba@dm4 dmbak]$ scp -r fullprdbak0610/ dmdba@192.168.163.135:/dmdata/dmbak/
#注册服务
[root@~]# /home/dmdba/dmdbms/script/root/dm_service_installer.sh -t dmserver -p dmprd1 -dm_ini /dmdata/data2/DAMENG/dm.ini -m mount
[root@~]# /home/dmdba/dmdbms/script/root/dm_service_installer.sh -t dmwatcher -p prd1Watcher -watcher_ini /dmdata/data2/DAMENG/dmwatcher.ini
#安装略,初始化实例
dminit path=/dmdata/data2 page_size=32 instance_name=dmprd2 extent_size=32 log_size=2048 PORT_NUM=15236 CHARSET=1 sysdba_pwd=Dameng123 SYSAUDITOR_PWD=Dameng123
#恢复数据
[dmdba@~]$ dmrman CTLSTMT="RESTORE DATABASE '/dmdata/data2/DAMENG/dm.ini' FROM BACKUPSET '/dmdata/dmbak/fullprdbak0610'"
[dmdba@~]$ dmrman CTLSTMT="RECOVER DATABASE '/dmdata/data2/DAMENG/dm.ini' FROM BACKUPSET '/dmdata/dmbak/fullprdbak0610'"
[dmdba@~]$ dmrman CTLSTMT="RECOVER DATABASE '/dmdata/data2/DAMENG/dm.ini' UPDATE DB_MAGIC"
#修复dmarch.ini
#DaMeng Database Archive Configuration file
#this is comments
ARCH_WAIT_APPLY = 0 #0:高性能 1:事务一致
[ARCHIVE_LOCAL]
ARCH_TYPE = LOCAL #本地归档类型
ARCH_DEST = /data/dmdata/arch/ #本地归档存放路径
ARCH_FILE_SIZE = 1024 #单个归档大小,单位 MB
ARCH_SPACE_LIMIT = 51200 #归档上限,单位 MB
[ARCHIVE_REALTIME1]
ARCH_TYPE = REALTIME #实时归档类型
ARCH_DEST = DMPRD1 #实时归档目标实例名
[ARCHIVE_ASYNC]
ARCH_TYPE = ASYNC # 异步归档,按定时器批量推
ARCH_DEST = DMPRD3 # 目标是异步备库的实例名
ARCH_TIMER_NAME = TIMER1 # 关联哪个定时器(在 dmtimer.ini 里定义)
#修改dm.ini参数
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 次的日志重演信息
TIMER_INI = 1
#dmmal.ini、dmwatcher.ini、dmtimer.ini保持一致
#注册服务
[root@~]# /home/dmdba/dmdbms/script/root/dm_service_installer.sh -t dmserver -p dmprd2 -dm_ini /dmdata/data2/DAMENG/dm.ini -m mount
[root@~]# /home/dmdba/dmdbms/script/root/dm_service_installer.sh -t dmwatcher -p prd2Watcher -watcher_ini /dmdata/data2/DAMENG/dmwatcher.ini
#安装略,初始化实例
dminit path=/dmdata/data2 page_size=32 instance_name=dmprd2 extent_size=32 log_size=2048 PORT_NUM=15236 CHARSET=1 sysdba_pwd=Dameng123 SYSAUDITOR_PWD=Dameng123
#恢复数据
[dmdba@~]$ dmrman CTLSTMT="RESTORE DATABASE '/dmdata/data2/DAMENG/dm.ini' FROM BACKUPSET '/dmdata/dmbak/fullprdbak0610'"
[dmdba@~]$ dmrman CTLSTMT="RECOVER DATABASE '/dmdata/data2/DAMENG/dm.ini' FROM BACKUPSET '/dmdata/dmbak/fullprdbak0610'"
[dmdba@~]$ dmrman CTLSTMT="RECOVER DATABASE '/dmdata/data2/DAMENG/dm.ini' UPDATE DB_MAGIC"
#修改系统参数dm.ini
DW_INACTIVE_INTERVAL = 60 #接收守护进程消息超时时间
RLOG_SEND_APPLY_MON = 64 #统计最近 64 次的日志重演信息
ALTER_MODE_STATUS = 0 #不允许手工方式修改实例模式/状态/OGUID
ENABLE_OFFLINE_TS = 2 #不允许备库 OFFLINE 表空间
MAL_INI = 1 #打开 MAL 系统
ARCH_INI = 1 #打开归档配置
TIMER_INI = 1
#修改dmwatcher.ini
[DMPRD]
DW_TYPE = LOCAL #本地守护类型
DW_MODE = MAMUAL #MANUAL:故障手切 AUTO:故障自切
DW_ERROR_TIME = 20 #远程守护进程故障认定时间
INST_ERROR_TIME = 20 #本地实例故障认定时间
INST_RECOVER_TIME = 60 #主库守护进程启动恢复的间隔时间
INST_OGUID = 45331 #守护系统唯一 OGUID 值
INST_INI = /dmdata/data2/DAMENG/dm.ini #dm.ini 文件路径
INST_AUTO_RESTART = 1 #打开实例的自动启动功能
INST_STARTUP_CMD = /home/dmdba/dmdbms/bin/dmserver #命令行方式启动
RLOG_SEND_THRESHOLD = 0 #指定主库发送日志到备库的时间阈值,默认关闭
RLOG_APPLY_THRESHOLD = 0 #指定备库重演日志的时间阈值,默认关闭
#修改dmarch.ini,异步只本地备份即可
ARCH_WAIT_APPLY = 0 #0:高性能 1:事务一致
[ARCHIVE_LOCAL]
ARCH_TYPE = LOCAL #本地归档类型
ARCH_DEST = /data/dmdata/arch/ #本地归档存放路径
ARCH_FILE_SIZE = 1024 #单个归档大小,单位 MB
ARCH_SPACE_LIMIT = 51200 #归档上限,单位 MB
#注册服务
[root@~]# /home/dmdba/dmdbms/script/root/dm_service_installer.sh -t dmserver -p dmprd3 -dm_ini /dmdata/data2/DAMENG/dm.ini -m mount
[root@~]# /home/dmdba/dmdbms/script/root/dm_service_installer.sh -t dmwatcher -p prd3Watcher -watcher_ini /dmdata/data2/DAMENG/dmwatcher.ini
[dmdba@~]$ vi /home/dmdba/dmdbms/bin/dmmonitordmprd.ini
MON_DW_CONFIRM = 0 #0:非确认(故障手切) 1:确认(故障自切)
MON_LOG_PATH = /home/dmdba/prdlog #监视器日志文件存放路径
MON_LOG_INTERVAL = 60 #每隔 60s 定时记录系统信息到日志文件
MON_LOG_FILE_SIZE = 512 #单个日志大小,单位 MB
MON_LOG_SPACE_LIMIT = 2048 #日志上限,单位 MB
[DMPRD]
MON_INST_OGUID = 45331 #组 GRP1 的唯一 OGUID 值
MON_DW_IP = 192.168.163.133:5436 #IP 对应 MAL_HOST,PORT 对应 MAL_DW_PORT
MON_DW_IP = 192.168.163.134:5437
MON_DW_IP = 192.168.163.136:5438
#注册服务
[root@~]# /home/dmdba/dmdbms/script/root/dm_service_installer.sh -t dmmonitor -p Monitor -monitor_ini /home/dmdba/dmdbms/bin/dmmonitordmprd.ini
#启动数据库修改参数
##A 主
[dmdba@dm4 ~]$ dmserver /dmdata/data2/DAMENG/dm.ini mount
[dmdba@dm4 ~]$ disql sysdba/Dameng123@localhost:15236
SQL> SP_SET_OGUID(45331);
SQL> ALTER DATABASE PRIMARY;
##B 备
[dmdba@dm4 ~]$ dmserver /dmdata/data2/DAMENG/dm.ini mount
[dmdba@dm4 ~]$ disql sysdba/Dameng123@localhost:15236
SQL> SP_SET_OGUID(45331);
SQL> ALTER DATABASE STANDBY;
##C 异步
[dmdba@dm4 ~]$ dmserver /dmdata/data2/DAMENG/dm.ini mount
[dmdba@dm4 ~]$ disql sysdba/Dameng123@localhost:15236
SQL> SP_SET_OGUID(45331);
SQL> ALTER DATABASE STANDBY;
#启动守护进程,主备异步的顺序
dmwatcher /dmdata/data2/DAMENG/dmwatcher.ini
#启动监视器查看集群状态
dmmonitor dmdbms/bin/dmmonitorprd.ini
vim /etc/dm_svc.conf
##以#开头的行表示是注释
##全局配置区
TIME_ZONE=(480)
LANGUAGE=(cn)
DMRW=(192.168.163.131:15236,192.168.163.132:15236,192.168.163.135:15236)
##服务配置
[DMRW]
LOGIN_MODE=(1)
RW_SEPARATE=(1)
RW_PERCENT=(30)
SWITCH_TIMES=(60)
SWITCH_INTERVAL=(1000)
LOGIN_MODE
指定优先登录的服务器模式。0:优先连接 PRIMARY 模式的库,NORMAL 模式次之,最后选择 STANTBY 模式;
1:只连接主库;2:只连接备库;3:优先连接 STANDBY 模式的库,PRIMARY 模式次之,最后选择 NORMAL 模式;
4:优先连接 NORMAL 模式的库,PRIMARY 模式次之,最后选择 STANDBY 模式。
SWITCH_TIMES
表示以服务名连接数据库时,若未找到符合条件的库成功建立连接,将尝试遍历服务名中库列表的次数。有效值范围 1~9223372036854775807,默认值为 1,可以设置至少 3 次用来避免由于网卡的波动,造成数据库连接测频繁切换。
SWITCH_INTERVAL
表示在服务器之间切换的时间间隔,单位为毫秒,有效值范围 1~9223372036854775807。与参数 SWITCH_TIMES、EP_SELECTOR 配合使用,EP_SELECTOR 设置为 0,等待 SWITCH_INTERVAL 后会切换尝试连接下一个服务器,EP_SELECTOR 设置为 1,等待 SWITCH_INTERVAL 后会继续尝试连接该服务器,直到 SWITCH_TIMES 次再切换下一个服务器。
RW_SEPARATE
表示是否启用读写分离。0:不启用;1:启用;2:启用,备库由客户端进行选择,且只会选择服务名中配置的节点。
RW_PERCENT
表示读写分离分发比例,有效值范围 0~100,主库占所有事物数的比例。可以根据主备库的实际压力来设定。
达梦社区技术 https://eco.dameng.com
文章
阅读量
获赞
