暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

MGR 不一样的多数派

原创 大表哥 2022-04-25
1015

image.png
大家好! 这次大表哥带来的还是有关MGR相关的主题。

对于生产数据库来说HA和DR是2个必须的选项。 围绕了这2个选项,诞生了很多复制和迁移同步的组件和相关的技术。

对于MYSQL的经典主从架构来说:Master -> Slave 来说属于典型的share nothing 的架构。

不像 Oracle 的RAC的存储是共享的ASM, 属于share everything的架构。 一个节点挂了,另外一个节点可以继续工作,数据完全不会丢失。(当然ASM存储offline的话,所有节点也就全休假了。。。)

我们这里暂不讨论ORACLE, 未来有时间可以写几篇 ORACLE的文章。
今天这里讨论的如何在数据库进行 failover,switchover 之后,保证数据库的 RPO =0: 数据无损。

Mysql 的主从架构演进 for HA:

Keepalived + Master + slave (master): 这种架构出现在早期的mysql HA版本中, 完全不能保证RPO = 0 , 不过早期的项目数据量并发并不大,而且有的公司是可以接受 data lost. 所以业界早期甚至到现在2022年,仍有公司采用此架构. 对于一些组件类的meatadata 元数据的保存(像是hive metadata),或者信息管理的后台也不是不能接受。
另外, keepalived 经常受网络波动,进行切换。。。 这个也是个坑点。。。 实际的运维中,经常遇到数据库没事,keepalived 总出问题的情况。
大表哥一直认为, 数据库作为有状态的节点(主从角色的区分),不太适合keepalived 这种组件。

Keepalived + Master + slave(semi-sync): 半同步是出现在mysql 5.6的版本中,后来在5.7版本中也有了演进,从而保证至少一个slave节点写入日志成功后,才返回给客户端成功的标志。 这个架构也是很多云上的RDS的产品架构。

MHA : 这个日本小哥开发的组件在国内爆火,可能连他自己也没想到。 基于perl 开发, 原生代码已经很多年没有更新和维护了。
最大的有优点是:slave 节点可以去down掉的master节点拉取没有apply 的binlog日志。最大程度上保证了数据的一致性。

MHA和SEMI-SYNC的共同问题是,一旦发生了触发了HA的选项,类似于failover, MHA的进程和半同步的进程 就会down 掉,或者降级为异步同步。 需要人为的手动维护或者自动化脚本的监控和修复。

MGR:组复制。 通过分布式协议PAXOS,打成多数派的一致性,来保证数据的不丢失。 起始于mysql 5.17版本,支持单主和多主的模式。

如果小伙伴运维过 mongo DB 的复制集, 比如说经典3节点的复制集, 1个 primary + 2 secondary 的架构。

通常是大多数节点之后, 例如关闭掉2个从节点, 那么主库会进行写保护,变成read-only的状态。

由于之前有mongo的运维经验,大表哥刚接触MGR的时候也是这么认为的:

对于mysql 3 节点的MGR来说, 如果2个不可用,那么剩下的节点将不会提供服务???

我们来动手测试一下:

3节点的MGR集群如下:

+---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 519dc1a6-be2b-11ec-9f85-525400743c33 | 82.156.200.136 | 3307 | ONLINE | SECONDARY | 8.0.20 | | group_replication_applier | 9915aff5-bbd6-11ec-9110-525400743c33 | 82.156.200.136 | 3306 | ONLINE | SECONDARY | 8.0.20 | | group_replication_applier | 9aa1cbcd-be2c-11ec-90a8-525400743c33 | 82.156.200.136 | 3308 | ONLINE | PRIMARY | 8.0.20 | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+

接下来,我们正常关闭: 3307,3306 2个节点

mysql> shutdown; Query OK, 0 rows affected (0.00 sec) mysql> shutdown; Query OK, 0 rows affected (0.00 sec)

我们此时再次登录主库查看:

mysql> select * from performance_schema.replication_group_members; +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 9aa1cbcd-be2c-11ec-90a8-525400743c33 | 82.156.200.136 | 3308 | ONLINE | PRIMARY | 8.0.20 | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ 1 row in set (0.00 sec)

我们尝试插入记录:居然完全可以成功!!!

mysql> insert into t_mgr values (5,'just one node live'); Query OK, 1 row affected (0.00 sec)

是的 MYSQL的MGR 和mongo DB的复制集的多数派的概念是不一样的!!!

我们来参考一下官方文档: https://dev.mysql.com/doc/refman/8.0/en/group-replication-fault-tolerance.html

image.png

这里的重点是 if a second server fails involuntarily, 当server 不是自愿的离开组的时候,写入多数节点返回成功才会生效。

显然上面的实验,我们是手动shutdown的数据库,属于是正常的运维行为。所以MYSQL认为是自愿的维护行为。

如果我们来观察 mysql 日志的话: 每当我们正常关闭一个数据库实例的话, MGR的试图 view 会dynamic group reconfiguration.

初始化的试图版本:16508700462301212:3

2022-04-25T15:02:53.803172+08:00 0 [Note] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to 82.156.200.136:3307, 82.156.200.136:3306, 82.156.200.136:3308 on view 16508700462301212:3.'

当我们关闭 3307的时候:试图版本reconfig : view 16508700462301212:4

2022-04-25T15:03:24.117778+08:00 0 [Warning] [MY-011499] [Repl] Plugin group_replication reported: 'Members removed from the group: 82.156.200.136:3307' 2022-04-25T15:03:24.117857+08:00 0 [Note] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to 82.156.200.136:3306, 82.156.200.136:3308 on view 16508700462301212:4.'

当我们关闭 3308的时候:试图版本reconfig : view 16508700462301212:5

2022-04-25T15:03:33.113923+08:00 0 [Warning] [MY-011499] [Repl] Plugin group_replication reported: 'Members removed from the group: 82.156.200.136:3308'
2022-04-25T15:03:33.113977+08:00 0 [Note] [MY-011503] [Repl] Plugin group_replication reported: 'Group membership changed to 82.156.200.136:3306 on view 16508700462301212:5.'

我们可以看到MGR的试图版本的变化: 16508700462301212:3 -》 16508700462301212:4 -》16508700462301212:5

或者我们可以这样理解MGR的多数派: 在每一次正常的关闭节点或者stop group_replication后, 会触发MGR的成员重组,并标记版本号在view中。

所以我们的MGR节点数的变化为: 3节点-》 2节点 -》 1节点

这样就很容易理解上面的实验为什么1个节点也可以写入的问题了。 根本原因在于MGR节点退出重组,最后的MGR试图只有1个节点,对于1个节点来说,自己本身就是大多数。所以可以正常写入!

下面我们再看一下 server 不自愿离开的实验: involuntarily

网络问题或者是OOM导致的节点失联或者是进程失败 都是属于节点 involuntarily 离开MGR复制组。

我们回归最初始的集群:

mysql> select * from performance_schema.replication_group_members; +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 519dc1a6-be2b-11ec-9f85-525400743c33 | 82.156.200.136 | 3307 | ONLINE | SECONDARY | 8.0.20 | | group_replication_applier | 9915aff5-bbd6-11ec-9110-525400743c33 | 82.156.200.136 | 3306 | ONLINE | SECONDARY | 8.0.20 | | group_replication_applier | 9aa1cbcd-be2c-11ec-90a8-525400743c33 | 82.156.200.136 | 3308 | ONLINE | PRIMARY | 8.0.20 | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.00 sec)

这个时候我们直接kill掉2个从节点:

[jason@VM-24-9-centos ~]$ kill -9 15452 21291 20754

我们再次登录存活的主节点:这个时候 2个从节点的状态变成了 UNREACHABLE

mysql> select * from performance_schema.replication_group_members; +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 519dc1a6-be2b-11ec-9f85-525400743c33 | 82.156.200.136 | 3307 | UNREACHABLE | SECONDARY | 8.0.20 | | group_replication_applier | 9915aff5-bbd6-11ec-9110-525400743c33 | 82.156.200.136 | 3306 | UNREACHABLE | SECONDARY | 8.0.20 | | group_replication_applier | 9aa1cbcd-be2c-11ec-90a8-525400743c33 | 82.156.200.136 | 3308 | ONLINE | PRIMARY | 8.0.20 | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.00 sec)

MGR是基于多数派的机制, 3节点的集群当可用数量小于2个的时候,集群只能读,不可写入,
写入的动作会直接hang住,直到超时:

mysql> create database mgrdb; 2022-04-18T22:25:53.052946+08:00 0 [ERROR] [MY-011495] [Repl] Plugin group_replication reported: 'This server is not able to reach a majority of members in the group. This server will now block all updates. The server will remain blocked until contact with the majority is restored. It is possible to use group_replication_force_members to force a new group membership.'

这个时候集群的状态,就是整体不可用了,也就是我们常说的 MGR crash 掉了。

我们要尝试重启一下异常关闭的2个节点

[jason@VM-24-9-centos ~]$ nohup /opt/mysql/8/bin/mysqld_safe --defaults-file=/data/mysql_mgr3307/my3307.cnf > /dev/null --user=jason 2>&1 &
[1] 27476
[jason@VM-24-9-centos ~]$ nohup /opt/mysql/8/bin/mysqld_safe --defaults-file=/data/mysql3306/my3306.cnf > /dev/null --user=jason 2>&1 &
[2] 28892

然而这2个基点依然是 UNREACHABLE的

mysql> select * from performance_schema.replication_group_members; +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 519dc1a6-be2b-11ec-9f85-525400743c33 | 82.156.200.136 | 3307 | UNREACHABLE | SECONDARY | 8.0.20 | | group_replication_applier | 9915aff5-bbd6-11ec-9110-525400743c33 | 82.156.200.136 | 3306 | UNREACHABLE | SECONDARY | 8.0.20 | | group_replication_applier | 9aa1cbcd-be2c-11ec-90a8-525400743c33 | 82.156.200.136 | 3308 | ONLINE | PRIMARY | 8.0.20 | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.00 sec)

这个时候,我们在从节点运行 start group_replication 依然会hang死.

mysql> start group_replication;

最后会报错:

mysql> start group_replication; ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log.

查看后台的日志是 之前的命令hang住的原因是在等待加入组的超时

2022-04-19T14:30:09.304961+08:00 23 [ERROR] [MY-011640] [Repl] Plugin group_replication reported: ‘Timeout on wait for view after joining group’
2022-04-19T14:30:09.304998+08:00 23 [Note] [MY-011649] [Repl] Plugin group_replication reported: ‘Requesting to leave the group despite of not being a member’
2022-04-19T14:30:09.305019+08:00 23 [ERROR] [MY-011735] [Repl] Plugin group_replication reported: ‘[GCS] The member is leaving a group without being on one.’

再次join 组 rejoin 是由参数group_replication_autorejoin_tries 代表重试的次数 * 每次失败重试的间隔是5分钟
所以总共等待的超时时间是15分钟。

mysql> select @@group_replication_autorejoin_tries*5; +----------------------------------------+ | @@group_replication_autorejoin_tries*5 | +----------------------------------------+ | 15 | +----------------------------------------+ 1 row in set (0.00 sec)

目前这个案例属于整个集群都crash 掉, 我们需要在之前的主节点上 重新引导复制组:

我们注意到关闭 stop group_replication 的耗时还是比较长的

mysql> set global group_replication_bootstrap_group =ON; Query OK, 0 rows affected (0.00 sec) mysql> stop group_replication; Query OK, 0 rows affected (1 min 22.28 sec) mysql> start group_replication; Query OK, 0 rows affected (3.17 sec) mysql> set global group_replication_bootstrap_group =OFF; Query OK, 0 rows affected (0.00 sec)

这时我们在重启一下2个从节点:start group_replication

mysql> start group_replication; Query OK, 0 rows affected (3.49 sec) mysql> start group_replication; Query OK, 0 rows affected (3.93 sec)

我们再次查询MGR的view: 发现一切回归正常

mysql> select * from performance_schema.replication_group_members; +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ | group_replication_applier | 519dc1a6-be2b-11ec-9f85-525400743c33 | 82.156.200.136 | 3307 | ONLINE | SECONDARY | 8.0.20 | | group_replication_applier | 9915aff5-bbd6-11ec-9110-525400743c33 | 82.156.200.136 | 3306 | ONLINE | SECONDARY | 8.0.20 | | group_replication_applier | 9aa1cbcd-be2c-11ec-90a8-525400743c33 | 82.156.200.136 | 3308 | ONLINE | PRIMARY | 8.0.20 | +---------------------------+--------------------------------------+----------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.00 sec)

最后我们来总结一下:

MGR 组成员的退出分为2种方式:

  1. involuntarily : 网络问题,OOM造成的节点失联或者进程crash -> 维持原始MGR成员的试图
  2. voluntarily: 主动shutdown 进程, 计划内的维护 -> MGR试图每次成员会更新,关闭的节点会记为正常的离开

总体来说,都是基于当前MGR试图成员的来进行多数派的写一致性。

如果整个集群都crash 掉,需要从主节点重新引导MGR组的 group_replication_bootstrap_group 。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论