1概述

在DM8的主备集群中,主库是可读可写的,备库只读不能进行修改操作。为了进一步提高集群的吞吐量,可将读写请求进行过滤,让主库响应写请求,备库进行读请求的响应,降低主库服务器压力,提高备库服务器性能利用率,本节进行DM8读写分离集群的故障恢复学习,包括主机故障后备机接管并对外提供服务、恢复故障主机并加入集群、手动进行集群主库切换。
本节主要关注的是在集群在自动切换模式、手动切换模式下以及在集群正常的情况下进行主库切换情况下未提交事务是否会丢失。

2操作内容

2.1环境信息

在读写分离数据守护集群搭建好的基础上进行本节测试,具体环境如下。
1主2备1台部署了确认监视器的服务器共3节点主备数据守护集群:
IP规划:
主机名 服务ip 心跳ip 数据库名 实例名 备注
dmdb01 192.168.30.148 192.168.100.148 dmdb rw1 主库
dmdb02 192.168.30.149 192.168.100.149 dmdb rw2 备库
dmdb03 192.168.30.150 192.168.100.150 dmdb rw3 备库、普通监视器
dmdb04 192.168.30.151 192.168.100.151 dmdb 部署确认监视器
端口规划:
实例名 实例端口 MAL 系统监听 TCP 连接的端口 实例本地的守护进程监听 TCP 连接的端口 实例监听守护进程 TCP 连接的端口
rw1 5236 7336 7436 7536
rw2 5236 7336 7436 7536
Rw3 5236 7336 7436 7536
目录规划:(在对应服务器上创建目录owner为dmdba组为dinstall)
数据库软件安装目录 /home/dmdba/dmdbms
实例安装目录 /dmdata/
归档日志存放目录 /dmdata/arch
备份文件存放目录 /dmdata/dmbak/

2.2自动切换主库

模拟应用系统连接读写分离集群,然后进行业务处理,提交了一个事务(表示业务成功处理),然后在处理一个新的业务的时候还没有完成(commit)的时候主机就挂掉了,此时再commit事务的时候会怎么样?进行读操作又会怎么样?

2.2.1模拟业务场景

首先,使用dmdb04连接集群,执行以下SQL语句创建一个测试表,内容如下:

su - dmdba
disql SYSDBA/'"输入密码"'@DMRW

create table TEST_RW_FAULT
(
	FID INT,
	FDESC VARCHAR2(200)
);
/

在数据库中,默认是需要手动提交(commit)事务的,但是DDL语句会自动提交当前事务,所以不需要而外commit。
在这里插入图片描述

继续执行以下SQL语句,插入一条FID为1的数据,然后修改此记录的FDESC为“已处理”并且commit;再插入一条FID为2的记录,此时还未完成提交事务(按业务来说这个事务其实还要修改FDESC字段并commit)主库就以外宕掉了。

-- 事务A(已提交)
insert into TEST_RW_FAULT(FID) values(1);
update TEST_RW_FAULT set FDESC = '已处理' where FID = 1;
commit;
-- 事务B(未提交)
insert into TEST_RW_FAULT(FID) values(2);

在这里插入图片描述

此时,在主库所在的机器dmdb01上查出rw1实例的进程ID并通过kill命令强制将rw1进程杀掉。

ps -ef|grep dmdba
kill -9 1455

在这里插入图片描述

此时,在dmdb03监视器里面可以看到以下日志输出,首先是监测到rw1实例挂掉了,然后集群会尝试重启rw1实例,在这个过程中,由于配置了确认监视器以及自动切换主库,此时rw2备库被选择为了新的主库,由于rw1实例所在的dmdb01的守护进程并没有挂掉因为此rw1实例成功启动起来了。
在这里插入图片描述
在这里插入图片描述

然后在dmdb01查看进程发现rw1实例进程重启了,使用DISQl连接rw1数据库发现处于备库打开状态,在监视器上使用tip命令查看集群信息发现此时集群已恢复正常:
在这里插入图片描述
在这里插入图片描述

然后我们回到dmdb04那台连接集群的disql中发现,会话没有关闭也没有错误提示,此时我们继续模拟剩下的业务:修改FID为2记录的FDESC字段,并提交事务(就是模拟用户继续完成事务B的业务):

update TEST_RW_FAULT set FDESC = '已处理' where FID = 2;
commit;
-- 查看测试表信息
select * from TEST_RW_FAULT;

在这里插入图片描述

可以发现如果在主库挂掉的时候有未提交的事务,那么事务会丢失(就是那条insert语句执行丢失了),即使在commit前原主库(rw1)重新加入了读写分离集群了,也是会丢失。因为主库切换为了rw2,而rw2上的Redo日志并没有rw1未提交事务的日志信息,在实时归档模式下,主库只有提交事务的时候才会发送对应的Redo日志到备库进行重演。

2.2.2故障恢复

在配置确认监视器并且DW_MODE=AUTO自动切换模式的时候,会自动选择一个备库作为新的主库对外提供服务,不需要人为介入。
像前面那种守护进程没有挂掉,只有主库实例进程挂掉的情况,确认监视器能够通过MAL连接主库的守护进程,会尝试启动数据库实例,并切换为备库状态,而不需要人为操作。

如果在主库的守护进程也挂掉的情况下又会怎么样呢?
首先在dmdb04的DISQL继续执行以下SQL:

insert into TEST_RW_FAULT(FID) values(2);

现在新的主库是rw2,我在rw2所在的dmdb02服务器上直接把守护进程和数据库实例都kill掉:

ps -ef|grep dmdba
kill -9 1409
kill -9 1413

在这里插入图片描述

接着在dmdb04的DISQL继续执行剩余的update和commit操作并查询测试表数据:

update TEST_RW_FAULT set FDESC = '已处理' where FID = 2;
commit;
-- 查看测试表信息
select * from TEST_RW_FAULT;

在这里插入图片描述

然后查看监视器信息,发现提示守护进程rw2已经连接不上了,并且rw1被自动切换为了新的主库。
在这里插入图片描述

在人工介入重新把故障主机加入集群前,以为已经切换主库对正常服务了,所以可能有新的事务已经提交了,所以我在dmdb04继续执行以下SQL:
– 事务C

insert into TEST_RW_FAULT(FID) values(3);
update TEST_RW_FAULT set FDESC = '已处理' where FID = 3;
commit;
-- 查看测试表信息
select * from TEST_RW_FAULT;

在这里插入图片描述

如果此时,我按以下命令启动rw2的实例和守护进程的话,可以发现可以正常启动。

# 启动实例
systemctl start DmServicerw
# 启动守护进程
systemctl start DmWatcherServicerw

在这里插入图片描述

用DIQSL连接rw2实例,查询测试表发现查到了在集群切换主库后新提交的事务,并且通过监视器查询集群状态可以看到也是正常的:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

因此在配备确认了监视器和自动切换主库的读写分离集群,如果主库发生了故障那么故障主机重新启动实例和守护进程即可完成重新加入集群。

2.3手动主库切换

2.3.1配置守护进程配置文件 dmwatcher.ini

修改dmdb01、dmdb02、dmdb03服务器额守护进程配置文件 dmwatcher.ini:

vi /dmdata/dmdb/dmwatcher.ini

在这里插入图片描述

将DW_MODE = AUTO改为MANUAL,然后按照以下顺序重启读写分离集群:

关闭确认监视器:systemctl stop DmMonitorServiceconfirm
关闭备库守护进程:systemctl stop DmWatcherServicerw
关闭主库守护进程:systemctl stop DmWatcherServicerw
关闭主库实例:systemctl stop DmServicerw
关闭备库实例:systemctl stop DmServicerw
启动备库实例:systemctl start DmServicerw
启动主库实例:systemctl start DmServicerw
启动主库守护进程:systemctl start DmWatcherServicerw
启动备库守护进程:systemctl start DmWatcherServicerw
启动确认监视器:systemctl start DmMonitorServiceconfirm

2.3.2模拟故障

还是一样,在dmdb04上连接集群完成事务D的提交,并且在执行事务E的insert操作后将主库的守护进程和数据库实例都kill掉:

-- 事务D(已提交)
insert into TEST_RW_FAULT(FID) values(4);
update TEST_RW_FAULT set FDESC = '已处理' where FID = 4;
commit;
-- 事务E(未提交)
insert into TEST_RW_FAULT(FID) values(5);

在这里插入图片描述

在dmdb01上杀掉以下进程:
在这里插入图片描述

继续在dmdb04上执行以下SQL:

update TEST_RW_FAULT set FDESC = '已处理' where FID = 5;

可以看到此时集群已经停止了,显示连接丢失:
在这里插入图片描述

2.3.3故障恢复

故障发生后,首先应排查错误发生的原因,之后再启动数据库实例:

systemctl start DmServicerw

然后使用DISQL连接主库rw1数据库可以发现数据库处于mount状态:
在这里插入图片描述

接着主库启动启动守护进程:

systemctl start DmWatcherServicerw

通过DISQL连接rw1实例可以看到:处于主库打开状态,并且可以查到故障前已提交的事务D,但是未提交的事务E的insert数据则丢失了。
在这里插入图片描述

在dmdb03监视器上可以看到以下信息:
在这里插入图片描述

在dmdb04上连接集群查询:
在这里插入图片描述

因此,在手动切换模式的读写分离集群中如果主库发生故障,在恢复正常后依次启动实例(如果是数据文件损坏需要通过全备恢复数据并通过mount启动数据库实例)和守护进程即可自动加入集群。

2.4手动切换主备集群

在主备库正常的情况下,也可以在监视器dmdb03上执行手动切换主库命令:

su - dmdba
dmmonitor /dmdata/dmdb/dmmonitor.ini

在切换主库前,在dmdb04上连接集群并且执行insert操作未提交:

insert into TEST_RW_FAULT(FID) values(6);

在这里插入图片描述

进行切换主库:

Login
# 以SYSDBA的身份登录
switchover GRP_RW.rw2

在这里插入图片描述
在这里插入图片描述

可以看到此时rw2被切换为了主库,在dmdb04原来的会话执行执行update操作并查询数据:可以看到切换主库时未提交的操作会丢失。

update TEST_RW_FAULT set FDESC = '已处理' where FID = 6;

在这里插入图片描述

因此,在使用switchover切换主库因慎重,需要确保此时数据库已无未提交的事务才执行,因为切换时未提交的操作会丢失。

2.5查询活跃会话

经过上面的三个测试发现,如果故障发生时或者手动切换主库时有未提交的事务会丢失,在切换主库时应确保此时已无未提交的事务。
要检查数据库的活动会话情况,是否存在未提交的事务。如果存在,要等这种事务自动执行完,再开始进行数据库切换操作。可以创建以下存储过程:

create or REPLACE PROCEDURE gs
as
begin
    select 'sp_close_session('||sess_id||');' ,
    thrd_id ,
    sess_id ,
    trx_Id ,
    datediff(ss, last_recv_time, sysdate) "EXECTIME(s)",
    to_char(sf_get_session_sql(sess_id)) "SQL" , ( select ins_cnt||' '||del_cnt||' '||upd_cnt idu
    from v$trx
    where id =a.trx_id
    and trx_id>0 ) "insert|del|update" ,
    curr_sch ,
    user_name,
    clnt_host,
    clnt_ip ,
    clnt_type,
    osname ,
    left(last_send_time, 19)
    from v$sessions a
    where state='ACTIVE'
    order by 5 desc;
end;

执行gs

CALL gs();

在这里插入图片描述

观察EXECTIME(s)执行时间和insert|del|update 增删改数据量判断是否存在大事务;
在这里插入图片描述

存在的话,询问一下是什么业务,等这种事务自动执行完毕再切换。

达梦社区地址:https://eco.dameng.com/

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐