文档中心MogDBMogDB StackUqbar
v3.1

文档:v3.1

支持的版本:

其他版本:

数据库集群脑裂手动故障恢复

故障场景

数据库集群双主脑裂手动故障恢复场景中,将基于既定规则停止一个主实例使其处于手动停止状态,确保仅有一个主实例处于运行状态。可以通过如下两方面判定是否属于双主脑裂故障。

  • 错误日志

    此时在cm_server primary实例的日志中会存在包含字符串(split brain failure in db service)的ERROR级别的日志,示例如下:

    CM_AGENT ERROR: [Primary], line 1529: split brain failure in db service, more dynamic primary and their term(7504) are the most(7504). Due to auto crash recovery is disabled, no need send restart msg to instance(6002) that had been restarted, waiting for manual intervention.

    或者

    CM_AGENT ERROR: line 570: split brain failure in db service, instance 6002 local term(7403) is not max term(7504). Due to auto crash recovery is disabled, will not restart current instance, waiting for manual intervention.
  • 集群状态

    cm_ctl query -Cvp -z ALL 执行集群状态查询,结果如下图所示:

    img

    说明:极端场景可能会出现两个数据库实例均被停止,此时可选择将instance ID较小的实例直接启动,如图中节点6001,以提供持续服务能力。对应的启动指令如下:

    cm_ctl start -n <nodeid> -D <datapath>

原因分析

网络分区故障发生时数据库集群可能由于以下原因而触发备实例的failover流程升主,以在满足多数派的分区内继续提供持续服务能力。

  • cms primary无法感知数据库集群的主实例的状态;
  • 数据库集群的备实例无法与主实例通信,如流复制异常;
  • 数据库集群的备实例与VIP的连通性(VIP已配置)检测异常;

此后,一旦网络分区故障消失,数据库集群将出现双主脑裂。同时,由于数据库集群自动故障恢复功能被禁用(cms_enable_db_crash_recovery=off/no/false),数据库集群将不会进行双主决策,而是通过停止某一个主实例的方式将系统维持在一个单主可用状态,等待专业DBA手动处理,以此确保数据库集群的数据一致性。

处理办法

工具下载

首先,访问MogDB官网下载中心:MogDB: MogDB Downloads,切换到”介质下载”选项卡,依次选择“版本” > “操作系统” > “CPU”,而后选择“插件和工具包”中的ToolKits- <version>-<platform-cpuarch>.tar.gz,如下图所示:

img

将上述软件包放置到MogDB安装路径的bin目录并解压,其内的mog_xlogdump工具将被用于数据校验,解压效果如下图所示:

img

该工具主要依赖下图所示参数:

img

如图所示,mog_xlogdump主要依赖事务ID(-x),数据表的OID(-o)以及xlog文件信息(-p)。

工具用法

数据库集群双主脑裂故障会导致从某一个时间点开始,两个数据库实例的日志分叉,如果持续时间较长的话,该分叉可能会导致单表或者多表中成千上万条数据的不一致(线上环境中,数据分叉即便出现,其持续的时间一般较短且完全可控),此时需要DBA借助专业工具mog_xlogdump来确定分叉数据的范围,以便于进行数据合并。

实验数据表

实验数据表为test_example_01。

(1) 在主实例上创建数据表并插入5条数据

create table test_example_01(id integer primary key, user_name varchar(10), register_time timestamp);

insert into test_example_01 values(1, 'zhangsan', '2022-09-22 10:57:10');

insert into test_example_01 values(2, 'lisi', '2022-09-22 10:58:10'); 

insert into test_example_01 values(3, 'wangwu', '2022-09-22 17:03:10');

insert into test_example_01 values(4, 'mazi', '2022-09-22 17:05:10');

insert into test_example_01 values(5, 'laoliu', '2022-09-22 17:09:10');

(2) 网络分区故障前查看数据表信息

\d+ test_example_01; //查看表结构

img

select pg_relation_filenode('test_example_01'); // 查看表的filenode,也即oid

select oid from pg_class where relname='test_example_01'; // 查看表的oid

img

select xmin, xmax, * from test_example_01; // 查看表的事务号,也即xmin
select pg_current_xlog_location(); // 主库上查看表对应的wal日志文件,下图为000000010000000000000004
  • 节点wrz-cm-test-01:

    img

基于起止LSN确定数据的变更

针对无法明确哪些表的数据不一致场景,工具mog_xlogdump可以根据指定的-s, -e起始和结束的lsn位置,将所有的差异数据都解析出来,下述指令二选一:

mog_xlogdump -c数据库连接 -s 起始lsn -e 结束lsn 主库wal日志文件

mog_xlogdump -c数据库连接 -p xlog日志目录 -s 起始lsn -e 结束lsn

说明

  1. 数据库连接字符串规则为:postgres://<db_user>:<db_pwd>@<host_ip>:<port>/<db_name>,本地执行时无需指定。

  2. 因未指定表oid,故此类方法获取的数据量包括系统所有表的数据,后续数据合并难度很大。

基于特定表确定数据的变更(推荐)

针对特定数据表数据不一致场景,工具mog_xlogdump可以根据指定的-o, -R参数来解析指定oid的表数据,也可以增加-s, -e参数指定起止LSN。下述指令二选一:

mog_xlogdump -c数据库连接 -o 表oid -R 表列的类型 -s 起始lsn -e 结束lsn 主库wal日志文件

mog_xlogdump -c数据库连接 -p xlog日志目录 -o 表oid -R 表列的类型 -s 起始lsn -e 结束lsn

说明:数据库连接字符串规则为:postgres://<db_user>:<db_pwd>@<host_ip>:<port>/<db_name>,本地执行时无需指定。

模拟网络分区故障

(1) 查询集群状态确保其正常运转

img

(2) 利用防火墙模拟主备节点之间网络隔离

在集群中任意一个节点上执行如下命令,隔离其和另一个节点之间的网络连接

iptables -I OUTPUT -d 192.168.122.232 -j DROP; iptables -I INPUT -s 192.168.122.232 -j DROP

(3) 查询集群状态,确保每个分区的cms和数据库实例角色均为primary

  • 节点wrz-cm-test-01

    img

  • 节点wrz-cm-test-02

    img

不同分区的主实例中执行写入/更新/删除操作

(1) 在节点wrz-cm-test-01上执行写入操作

insert into test_example_01 values(6, 'xiaoming', '2022-09-22 17:09:10'); // ID重复数据

img

(2) 在节点wrz-cm-test-02上执行写入操作

insert into test_example_01 values(6, 'xiaoming', '2022-09-22 17:10:10'); // ID重复数据

insert into test_example_01 values(7, 'huluwa', '2022-09-22 17:12:10');

img

消除网络分区故障

(1) 清理防火墙

在对应的节点(模拟网络分区故障(2)中的节点)上执行如下指令:

iptables -I OUTPUT -d 192.168.122.232 -j ACCEPT; iptables -I INPUT -s 192.168.122.232 -j ACCEPT

(2) 查询集群状态,确保其正常运行

集群状态和故障场景(2)一致,也即其中一个数据库实例处于Manually stopped状态。

img

脑裂故障数据恢复及合并

该步骤依赖于日志信息,一旦日志丢失则无法执行数据恢复。此处假设仅有一个数据表(test_example_01)的数据在网络分区后发生数据分叉。

(1) 明确网络分区故障前和双主脑裂故障发生时的LSN信息

  • 判定集群出现网络分区故障的时间点

    由于基于集群初始状态(模拟网络分区故障(1)中的节点)可知,网络分区故障后,节点wrz-cm-test-01上的cms和数据库实例的角色均会变更为primary。故可以在节点wrz-cm-test-01的cm_server日志中找到cms升主的时间点,然后基于该时间点获取集群正常运转状态时主备实例最后一次数据同步时对应的lsn信息(mog_xlogdump解析日志的起始时间-s)。

    CMS升主对应的日志信息如下:

    /cm_server-2022-09-23_104436-current.log:2022-09-23 15:16:23.005 tid=1245295  LOG: [DccNotifyStatus] g_dbRole is 1, roleType is 1.

    CMS升主之前所在节点的CMA上报的LSN信息如下:

    2022-09-23 14:59:27.495 tid=1245411 CM_AGENT LOG: [InstanceIsUnheal], current report instance is 6001, node 1, instId[6001: 6002], node[1: 2], staticRole[2=Standby: 1=Primary], dynamicRole[2=Standby: 5=Down], term[703: 604], lsn[0/4016230: 0/4007840], dbState[2: 0], buildReason[2=Disconnected: 7=Unknown], doubleRestarting[0: 0], disconn_mode[3=prohibit_connection: 1=polling_connection], disconn[:0, :0], local[192.168.122.231:27001, 192.168.122.232:27001], redoFinished[1: 1], arbiTime[104: 100], syncList[cur: (sync list is empty), exp: (sync list is empty), vote: (dynamic status is empty)], groupTerm[604], sync_standby_mode[0: 0: 0].
  • 判定集群出现脑裂故障的时间点

    基于脑裂故障的处理机制,集群双主脑裂故障的时间点所对应的LSN可以使用被停止的数据库实例(状态为Manully stopped)的xlog位置代替(mog_xlogdump解析日志的终止时间-e)。

    在网络隔离条件下,启动被停止的数据库实例,并使用gsql登录,然后执行下述sql指令获取xlog位置:

    select pg_current_xlog_location();

(2) 利用防火墙孤立数据库实例被停止的节点,并启动其上的数据库实例

img

获取表test_example_01的数据及双主脑裂故障时的LSN信息

img

(3) 利用mog_xlogdump确定分叉数据,并导出分叉数据

节点wrz-cm-test-01上数据变更如下:

img

节点wrz-cm-test-02上数据变更如下:

img

生成待合并到当前数据库集群主实例的数据信息:

insert into test_example_01 values(6, 'xiaoming', '2022-09-22 17:10:10'); // ID冲突,选择时间最新的
insert into test_example_01 values(7, 'huluwa', '2022-09-22 17:12:10');

确认完成待合并数据之后,需要关闭当前数据库实例。

(4) 将分叉数据导入到数据库集群的主实例

利用gsql登录当前的主实例,执行前述的两条插入语句

查询数据合并之后的数据库记录

(5) 被停止的数据库实例加入数据库集群

基于前述步骤(2),首先必须确保该节点上的数据库实例处于关闭状态;然后取消防火墙,消除网络隔离;最后,启动该节点上的数据库实例(cm_ctl start -n nodeid -D datapath)。该实例将以standby模式加入数据库集群。

(6) 查询集群状态,此时一切正常

Copyright © 2011-2024 www.enmotech.com All rights reserved.