内容简介:深坑!!!请注意!在Mysql group replication发现的”丢失数据”的场景
之所以想使用基于paxos协议的group replication,目的是为了更好的保障数据库的数据安全,包括数据一致性以及数据零丢失。目前虽然采用半同步,可以保障数据的安全,但在极端情况下,出现数据库主从误切的时候,出现老主库跟新主库同时都有写入的场景时,就破坏了数据一致性。为了避免这个状况,基于paxos协议支持多节点写入的技术开始在 mysql 各种版本上使用。 mysql官方也采用的group replicaiton 插件来实现这个功能。
在进行group replication的测试过程中,惊奇地发现以下现象:
特别说明一下,group replication的模式为single primary。 因为一些原因,导致原来primary节点被驱逐,集群内部重新选举了新的primary 节点, 切换之后不再有 sql 操作。
新primary节点的gtid 如下:
gtid_executed | aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-9578875, d5e35917-4cde-11e7-9791-1c98ec1cbc64:1-6
原来的primary节点重起之后,查看一下其gtid的信息。
gtid_executed | aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-9578876, d5e35917-4cde-11e7-9791-1c98ec1cbc64:1-6
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-9578876 比
aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-9578875 多一个事务。 也就是老的primary节点比新的primary节点多了一个事务? 为什么有最后1个事务没有传送到新的主库? 原因作者目前也不知道。 我们来看一下最后一个事务是什么事务:
# at 626 #170612 11:03:20 server id 128283359 end_log_pos 687 GTID last_committed=1 sequence_number=2 SET @@SESSION.GTID_NEXT= 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:9578876'/*!*/; # at 687 #170612 11:03:20 server id 128283359 end_log_pos 746 Query thread_id=6 exec_time=499 error_code=0 SET TIMESTAMP=1497236600/*!*/; BEGIN /*!*/; # at 746 #170612 11:03:20 server id 128283359 end_log_pos 925 View_change_log_event: view_id=14972366013867880:2 # at 925 #170612 11:03:20 server id 128283359 end_log_pos 990 Query thread_id=6 exec_time=499 error_code=0 SET TIMESTAMP=1497236600/*!*/; COMMIT /*!*/;
我们看到,是一个view change 事件产生的gtid, view change发生在group replication组内节点的加入或者离去的过程中。因此,这个丢失的事务,不是一个业务sql产生的事务。 因此,新主库没有丢失数据。 但是,这是否就没有问题了?继续看后面的内容。
现在我们试图把原来的primary节点加入到group replication复制组中去, 执行start group_replication命令,但该命令会提示错误。查看错误日志文件,得到的信息如下:
2017-06-12T11:09:54.263840+08:00 0 [Note] Plugin group_replication reported: 'A new primary was elected, enabled conflict detection until the new primary applies all relay logs' 2017-06-12T11:09:54.263936+08:00 0 [ERROR] Plugin group_replication reported: 'This member has more executed transactions than those present in the group. Local transactions: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-9578876, d5e35917-4cde-11e7-9791-1c98ec1cbc64:1-6 > Group transactions: aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-9578875, d5e35917-4cde-11e7-9791-1c98ec1cbc64:1-6'2017-06-12T11:09:54.263980+08:00 0 [ERROR] Plugin group_replication reported: 'The member contains transactions not present in the group. The member will now exit the group.'
错误日志 中输出的信息表达得很清楚,就是准备加进来的节点执行的事务比组内的事务还多, 拒绝加入 。
但dba很多时候,“往往不信邪”,第一次执行失败之后,会尝试第二次(作者当时也是如此)。 但是,执行第二次的,却 “妥妥滴”成功了 。 真的是妥妥的吗? 为什么第二次却可以是成功的呢?原因是因为: 执行第一次start group_replication的时候, 因为有view change 事务产生,primary节点的
gtid_executed将增加1个事物,所以新旧primary节点的gtid_executed就完全相等了 ,所以第二次启动的时候不再抱错。 但问题就解决了吗?
假如在新的primary上执行一个业务的sql,使其gtid_excuted增加1, 然后再将老的primary节点加入组复制,结果会是怎么?
我们继续进行试验,实验场景一样,老primary节点的gtid_executed比新的primary 节点gtid_executed多一个事务,但这次我们是先在新的primary节点上执行一个sql,然后再将老的primary节点加入group replication组复制。
此时,我们在新的主库执行一个事务: mysql> select * from xcy_test; +---+------+ | a | b | +---+------+ | 1 | 1 | | 2 | 1 | | 3 | 1 | +---+------+ 3 rows in set (0.00 sec) mysql> insert into xcy_test values(4,5); Query OK, 1 row affected (0.01 sec) mysql> select * from xcy_test; +---+------+ | a | b | +---+------+ | 1 | 1 | | 2 | 1 | | 3 | 1 | | 4 | 5 | +---+------+ 4 rows in set (0.00 sec)
然后在老的primary节点上执行start group_replication 加入复制组,命令没有报错。然后在该节点上查询刚刚插入的记录。 刚刚被插入的数据被没有复制到该节点,数据丢失。好恐怖。。。。
mysql> start group_replication; Query OK, 0 rows affected (2.16 sec) mysql> select * from xcy_test; +---+------+ | a | b | +---+------+ | 1 | 1 | | 2 | 1 | | 3 | 1 | +---+------+ 3 rows in set (0.00 sec)
在作者的暴力测试中,居然发现新的primary节点的执行的事务数比老的primary节点的事务数少,而少的这个事务目前发现是发生选举新主库时产生的view change 事务,虽然不造成新primary丢失业务数据, 但是当老primary再次加入组复制时,该节点将可能丢失数据,不再是一个完整的复制副本 。
组复制的逻辑还是比较复杂,细节也非常多,目前尚未弄清出现这种状况的原因,后续期待大牛跟官方能够提供支持,确认是否是bug?
但测试过程中出现现象也同样值得我们敬畏 。 首先抛开该问题是否是bug,是否可以采用合理的操作步骤来避免这些观念, 仅仅从测试过程出现的现象本身来看,至少可以确认的一点是: “group replication虽然是为了解决主从数据一致性而生,但是,并不代表它完全不会带来破坏数据一致性的缺陷,在这个方面依然需要关注,谨慎甚至敬畏“ 。 从作者的测试过程中发现,排除数据库可能存在的bug, 在隐含的不正确的场景下,进行了看似合理的操作,也将可能引发产生主从数据不一致的现象。 正是因为这些现象, 刷新了作者之前的关注点 ——因为group replication目的就是为了解决数据一致性而引进的,之前的关注点都在它因为有新功能而引进了哪些其他方面的限制。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 高并发场景下,如何保证生产者投递到消息中间件的消息不丢失?【石杉的架构笔记】
- MySQL root 密码丢失重置
- kafka consumer防止数据丢失
- MongoDB 副本集丢失数据的测试
- 苹果CloudKit出现问题:部分应用数据丢失
- React中this丢失的解决方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。