MySQL MGR 集群在并发环境下的读写一致性问题详解与解决方案

今天我们来学习一个在并发环境下经常遇到的问题。因为我们日常开发中,几乎所有业务都运行在并发环境中,数据库操作也不例外。

当我们启用了 MySQL MGR(MySQL Group Replication)集群 时,如何在这种环境下保证读取或写入的数据是最新的,就显得非常关键了。如果控制不当,就可能会产生严重的读写不一致问题。

本文将从 MGR 的基本概念出发,逐步深入其复制原理,并详细介绍如何通过参数配置解决读写一致性问题。


一、MGR 集群基础回顾:是什么、为什么

我们先来回顾一下什么是 MGR 集群。

MySQL Group Replication(MGR)是从 MySQL 5.7.17 版本(2016年)开始引入的一种新型的集群复制方案。与传统的主从复制方式相比,MGR 更加智能,设计之初就考虑了高可用性和强一致性。

它的核心设计理念有两个:

1. 节点间强一致性复制(CP)

MGR 集群内的所有节点之间使用的是 强同步复制。也就是说,不同节点之间的数据保持一致,是严格基于 一致性优先(CP模型) 进行设计的。事务在提交之前必须通过组认证协议(Group Certification Protocol),确保不会有冲突,且所有成员都能以相同顺序 apply。

2. 支持多主写入(Multi-Primary)

MGR 与传统主从的最大区别是,它支持多个主节点同时写入。也就是说,客户端无论连接哪个节点进行写操作,理论上都是允许的,并且数据最终在全组成员之间保持一致。

这是 MGR 最重要的特性之一,也带来了读写一致性控制的新问题。


二、并发环境下的旧数据读取问题是怎么产生的?

虽然 MGR 保证了最终一致性,但在并发读写操作中仍会遇到问题,尤其是在启用了多主模式(Multi-Primary)时。

让我们从一个实际场景出发:

  • 假设我们在 MGR 集群的 M1 节点执行了一个写入操作(事务 T1);
  • 然后,在 M3 节点上立即发起另一个读取或写操作(事务 T2);
  • 由于 T1 是一个大事务(例如涉及大量数据变更),并且同步存在延迟;
  • 那么在 T1 的数据还未同步到 M3 时,T2 可能就执行了;
  • 这就会造成 T2 基于“旧数据快照”来进行业务逻辑处理,数据已被修改但未感知

这就是 MGR 在并发环境下常见的读写不一致问题

为什么会这样?

因为 MGR 的事务同步是通过以下过程完成的:

  1. 在 M1 上执行的事务 T1 写入 binlog;
  2. M2、M3 节点将其接收并写入本地 relay log;
  3. relay log 数据通过 apply 机制执行;
  4. 最后由 M1、M2、M3 共同进入 commit 阶段。

问题出在:M3 还没 apply 完 T1,客户端已经在 M3 上发起了新的事务 T2。

由于 apply 是异步过程,T2 获取的数据就是 T1 commit 之前的快照数据


三、MGR 事务同步的详细过程分析

场景说明

  • MGR 启用了多主写入;
  • 我们将数据写入主节点 M1;
  • M1 会将事务变更记录到 binlog;
  • M2、M3 会通过组复制协议接收这个 binlog 日志,写入 relay log;
  • 然后依次 apply 这些 relay log 中的事务;
  • 最终在每个节点上完成事务 commit。

并发问题重现

在上面的场景中,如果 T1 是一个大事务,M3 在收到 T1 的 relay log 但尚未 apply 时,T2 在 M3 上被发起,并读取数据,这时 M3 上的数据尚未更新。

于是:

  • T2 获取了旧数据
  • 在旧数据基础上执行后续逻辑
  • 造成数据不一致

四、解决方案:使用 group_replication_consistency 参数

为了解决这种并发下读写不一致的问题,从 MySQL 8.0.14 开始,官方新增了一个控制读写一致性的参数:

group_replication_consistency

这个参数允许我们定义 MGR 的一致性控制级别,防止读到旧数据或未同步数据。


五、参数使用方式与三种设置粒度

group_replication_consistency 可以设置为:

  • SESSION 会话级别(推荐开发或调试时使用):

    SET SESSION group_replication_consistency = 'BEFORE';
    
  • GLOBAL 全局级别(影响整个实例):

    SET GLOBAL group_replication_consistency = 'BEFORE';
    
  • 多值组合(例如 'BEFORE,AFTER'):

    SET SESSION group_replication_consistency = 'BEFORE_AND_AFTER';
    

六、四种一致性控制模式详解

1. EVENTUAL(默认值)

  • 行为: 不做任何一致性控制;
  • 读取行为: 可能读到旧数据;
  • 性能: 最优;
  • 适用场景: 日志、监控等对一致性容忍的场景。

2. BEFORE

  • 行为: 当前事务会等待本节点上所有已接收但尚未提交的事务先完成;

  • 机制细节:

    • T2 在 M3 上执行时,会先判断是否有 T1 正在 apply;
    • 如果有,T2 会阻塞,直到 T1 commit;
  • 优点:

    • 只关注当前节点顺序,控制轻量;
    • 能有效避免读取旧数据;
  • 适用场景: 推荐大部分业务使用;

  • 性能: 优于 AFTER,劣于 EVENTUAL。


3. AFTER

  • 行为: 当前事务提交后,必须等待其变更在所有节点上同步完成;

  • 机制细节:

    • T1 提交后,M1 广播事务到 M2、M3;
    • M2、M3 应答后才允许最终 commit;
  • 优点: 提交之后保证全组一致;

  • 缺点:

    • 存在广播与应答开销;
    • 网络状况直接影响延迟;
  • 适用场景: 金融、库存、订单等对一致性极度敏感的核心业务;

  • 性能: 明显下降,适合关键路径。


4. BEFORE_AND_AFTER

  • 行为: 同时启用 BEFORE 和 AFTER;

  • 机制细节:

    • T2 会等待本地事务完成(BEFORE);
    • 自身 commit 后也会等待全组确认(AFTER);
  • 优点: 理论上安全性最高;

  • 缺点: 性能最差,极少使用;

  • 适用场景: 极端场景、测试验证。


七、具体事务执行控制流程解析

BEFORE 模式下:

  • T2 在 M3 上执行;
  • 发现 T1 未提交,阻塞等待;
  • 等 T1 commit 后,T2 再执行;
  • 确保在节点 M3 内部顺序一致。

AFTER 模式下:

  • T1 提交时触发全组广播;
  • 等待 M2、M3 收到并确认 apply;
  • 所有节点 commit 后,T1 才完成;
  • T2 无法进入,直到 T1 完整结束。

BEFORE_AND_AFTER 模式:

  • T2 既等 T1 结束(BEFORE);
  • 自己 commit 时又要广播(AFTER);
  • 等待过程最长,性能最低,但一致性最强。

八、性能测试对比数据

下表为四种模式的性能对比,含 TPS、QPS 和 95% 响应时间:

模式TPSQPS95% 响应时间
EVENTUAL最高595123ms
BEFORE较高538731ms
AFTER明显下降412361ms
BEFORE_AND_AFTER最低356778ms

从中可以看出,虽然 AFTER 和 BEFORE_AND_AFTER 保证了强一致性,但带来的性能开销巨大,应谨慎使用。


九、总结与最佳实践建议

结论总结如下:

  • EVENTUAL:性能好但可能读取旧数据,不建议用于有写入的场景;
  • BEFORE:兼顾一致性与性能,是默认推荐设置
  • AFTER:适用于金融、订单、库存等对一致性非常高要求的系统;
  • BEFORE_AND_AFTER:主要用于极端测试环境,生产环境下慎用。

推荐配置建议:

场景建议模式
绝大多数业务系统BEFORE
核心交易逻辑AFTER
写少读多场景BEFORE
日志或统计分析EVENTUAL
高一致性验证系统BEFORE_AND_AFTER

十、结语

MySQL MGR 提供了强大的一致性保障能力,但也需要开发者合理理解其行为模式,并选择最合适的参数设置。

使用 group_replication_consistency 参数,可以有效地避免并发环境下的数据读取偏差问题。但它不是“开了就好”,而是要在系统性能与一致性之间做出平衡。

建议开发者:

  • 在上线前进行不同模式的 负载压测
  • 根据业务需求选择合适的模式;
  • 对关键路径进行事务隔离保护和防重复逻辑设计;
  • 配合中间件层做进一步防并发控制(如幂等、分布式锁等机制)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值