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

MySQL 高可用方案--MGR 第04期:原理

2355
在前面几篇文章中,我们聊到了 MGR 的大致介绍部署常见操作。这一节来聊聊 MGR 的一些原理,由于水平有限,如果发现有不正确的地方,欢迎在文末留言指出。

1 故障检测

MGR 的成员之间会互相发送检测消息,当服务器 A 在给定的时间内没有接收到服务器 B 的消息时,会发生超时并产生怀疑。
之后,如果小组同意怀疑可能是真的,那么小组就会认定某个服务器确实出了故障,这意味着组中其他成员采取协调一致的决定来驱逐给定的成员。
在网络不稳定的情况下,成员之间可能会多次断开和重连,极端情况,一个组最终可能会将所有成员标记为驱逐,之后组不复存在,必须重建。
为了应对这种情况,从 MySQL 8.0.20 开始,组通信系统(GCS)跟踪已经被标记为驱逐的成员,然后决定是否有大多数成员将其标记为怀疑。这样可以确保至少有一个成员留在主中,当被剔除的成员实际上已经从组中删除时,GCS 将删除该成员被剔除的记录,以便该成员可以在恢复之后重新加入组。

2 选举算法

单主模式下,主出现故障,会考虑下面的因素选择新的主:
  1. 考虑的第一个因素是哪个成员运行的是最低的 MySQL 版本。如果所有成员都运行 MySQL 8.0.17 或更高版本,那么组成员将首先按照发布的补丁版本进行排序。如果任何成员运行 MySQL 8.0.16 或更低的版本,成员将首先按其发布的主要版本排序,并忽略补丁版本。低版本优先是考虑到高版本同步到低版本,高版本可能有一些新特性,无法在从库正常回放,导致同步出现问题。
  2. 如果有多个成员运行最低的 MySQL 版本,则要考虑的第二个因素是每个成员的权重,由参数 group_replication_member_weight 指定。如果 MySQL 的版本为 5.7,则该参数不可用,将不考虑这个因素。系统变量 group_replication_member_weight 指定一个范围为 0-100 的数字。值越大,权重越高。
  3. 如果前面两个因素都一样,则考虑的是,每个成员生成的服务器 UUID 的词法顺序,如果 server_uuid 系统变量都指定了,则选择 UUID 排序最靠前的成员作为主。

多主模式下,如果一个成员出现故障,连接到它的客户端可以重定向或故障转移到处于读写模式的任何其他成员。Group Replication 本身并不处理客户端故障转移,因此需要使用中间件框架,比如 MySQL Route。

3 故障转移

从节点提升为主前,要处理积压的事务,通常有两种选择:
  • 可靠性优先:如果有积压的事务,需要等积压的事务全被应用完,才能在新主上进行读写操作。
  • 可用性优先:不管是否有积压的事务,直接在新主上进行读写操作。
如果将 group_replication_consistency(该参数会在 MGR 专题后面的文章详细讲解) 设置为 BEFORE_ON_PRIMARY_FAILOVER,则表示设置了可靠性优先。

4 视图

Group Replication 每个成员都有一个一致性视图,显示哪些服务器是在工作的。
成员离开或者加入组时,都会触发视图的更新。有时服务器可能会意外离开组,在这种情况下,故障检测机制会检测到这一点,并通知组视图已更改。

5 流控

在多主模式中,速度较慢的成员还可能积累过多的事务以进行认证和应用,可能会导致冲突、认证失败或者读到过期数据等风险。为了解决这些问题,可以激活和调优 Group Replication 的流控制机制,以最小化快成员和慢成员之间的差异。
参数 group_replication_flow_control_mode 控制流控是否开启,如果为 QUOTA,表示开启,DISABLED 表示关闭。
两种情况会触发流控:
  • 证书队列中等待的事务数超过 group_replication_flow_control_certifier_threshold 配置的值时。
  • 应用程序队列中等待的事务数超过 group_replication_flow_control_applier_threshold 配置的值时

6 事务执行流程

我们来回顾在第 1 节所提到的组复制过程图:
一个事务在 MGR 中的执行流程大致如下:
  1. 事务写 Binlog 之前会进入到 MGR 层;
  2. 事务消息通过 Paxos 广播到各个节点;
  3. 在各个节点上进行冲突检测(冲突检测详细过程会在稍后介绍);
  4. 认证通过后本地节点写 Binlog 完成提交;
  5. 其他节点写 Relay Log 后并完成回放。

7 冲突检测

在 MGR 中,为了防止多个节点同时更新了同一条记录,设置了冲突检测机制,具体步骤如下:
  • 首先计算出对 write set(write set 的组成是:索引名 + DB 名+ DB 名长度 + 表名 + 表名长度 + 构成索引唯一性的每个列的值 + 值长度) 做 murmur hash 算法的值,判断这个值在 certification_info 是否有相同的记录,有则表示冲突,事务回滚,没有则会把 write set 写入 certification_info ,并进行下一步。
  • 然后判断事务执行时执行节点的 gtid_executed 和 certification_info 里面对应的 gtid_set。
  • 如果 gtid_executed 是 gtid_set 的子集,说明该节点的事务执行时,其他节点已经对事务操作的数据进行了更改,则不能进行更新,事务回滚。
  • 如果 gtid_executed 不是 gtid_set 的子集,表示其他节点没有对事务操作的数据有修改操作,则事务可以正常提交。
write set 的计算方式可参考下面例子(参考 MySQL 8.0.25 源码文件:sql/rpl_write_set_handler.cc):
创建一张表:
    CREATE TABLE db1.t1 (i INT NOT NULL PRIMARY KEY, j INT UNIQUE KEY, k INT UNIQUE KEY);

    写入一条数据:
      INSERT INTO db1.t1 VALUES(123);

      这里 write set 将有三个值:
        i -> PRIMARYdb13t1211 => PRIMARY 是主键名 (由主键生成的 write set)
        j -> jdb13t1221 => 'j' 是索引名 (由第一个唯一索引生成的 write set)
        k -> kdb13t1231 => 'k' 是所有名 (由第二个唯一索引生成的 write set)

        从上面例子可以看出,会基于记录的主键索引、唯一索引生成不同的 write set,那么仅仅只用主键索引生成一个 write set 是否可以呢?
        其实是不可以的,因为不仅主键冲突需要检测,唯一索引的冲突也需要检测。只有主键索引的 write set 无法判断出唯一索引是否违反了唯一性约束。

        这一节内容就聊到这里,MGR 系列文章持续更新中,欢迎关注:

        文章推荐
        MySQL 高可用方案--MGR 第03期:操作
        MySQL 高可用方案--MGR 第02期:部署
        MySQL 高可用方案--MGR 第01期:初探
        MySQL 常用高可用方案
        MySQL 常见面试题
        MySQL 删库到恢复


        好书推荐
        下面这几本书都是小编之前在学习 MySQL 的过程中,觉得不错的书籍。
        推荐理由:主要讲 SQL 的写法,MySQL 入门必看。

        推荐理由:比较全面的讲解了 MySQL 的基础知识,也涉及了一些优化。

        推荐理由:讲解了很多 MySQL 原理,强力推荐给想深入学习 MySQL 的同学




        我们创建了一个 MySQL 交流社群,围绕开发、运维、DBA、架构师和其他需要用到 MySQL 的群体,群内会分享一些读书笔记、面试技巧等,同时也用于大家交流使用 MySQL 过程中遇到的问题!
         
        入群请加下方群秘二维码,回复 MySQL,等待群秘邀你入群。

        文章转载自MySQL数据库联盟,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论