mysql主从复制中的并发控制与事务一致性

0次阅读

事务不一致的根本原因是 MySQL 异步复制机制下主库不等待从库执行完成即返回成功,叠加从库 SQL 线程单线程或有限并行导致回放乱序、延迟或跳过。

mysql 主从复制中的并发控制与事务一致性

主从复制中为什么会出现事务不一致?

根本原因在于 MySQL 默认的异步复制机制:主库提交事务后不等待从库执行完成就返回成功,而从库 SQL 线程是单线程(5.6 及以前)或有限并行(5.7+ 基于 slave_parallel_workers),导致事务在从库回放时可能被乱序、延迟甚至跳过。

常见现象包括:

  • 主库已更新某条记录,从库查不到或仍是旧值
  • 主库执行了 INSERT + UPDATE 两条语句,从库上 UPDATE 先于 INSERT 执行,报 ERROR 1032 (HY000): Can't find record in table
  • 主库事务 A 和 B 并发写入不同表,从库因并行回放策略误判依赖关系,造成数据错乱

如何启用基于 WRITESET 的并行复制(MySQL 8.0+)

这是目前最实用的并发控制方案,它通过记录事务修改的行级哈希(WRITESET)来判断是否可安全并行——只要两个事务没修改同一行,就允许并发回放。

需在从库配置以下参数:

CHANGE REPLICATION SOURCE TO   SOURCE_DELAY = 0,   SOURCE_AUTO_POSITION = 1; START REPLICA;

并确保主从都启用:

  • binlog_transaction_dependency_tracking = WRITESET(主库)
  • replica_parallel_type = LOGICAL_CLOCK(从库,MySQL 8.0.22+ 推荐设为 WRITESET
  • replica_parallel_workers = 4(建议设为 CPU 核数的 1–2 倍,但不超过 16)
  • replica_preserve_commit_order = ON(关键!保证事务提交顺序与主库一致)

注意:WRITESET 依赖 binlog_format = ROW,且对未显式指定主键 / 唯一键的表无效(会退化为传统模式)。

READ COMMITTED 隔离级别下主从延迟更隐蔽

当主库使用 READ COMMITTED 时,事务内多次 SELECT 可能读到不同快照;而从库即使延迟几秒,其 SQL 线程仍按 binlog 顺序执行。这会导致一种“逻辑一致但结果不一致”的假象:

BEGIN; UPDATE t SET v = v + 1 WHERE id = 1; SELECT v FROM t WHERE id = 1; -- 返回 101 UPDATE t SET v = v * 2 WHERE id = 1; SELECT v FROM t WHERE id = 1; -- 返回 202 COMMIT;

若从库延迟,在第二次 SELECT 执行前,另一并发事务已在主库把 v 改成 300,那么从库最终值是 202 而非 300 —— 表面看语句都执行了,实际业务语义已破坏。

这类问题无法靠复制参数修复,必须依赖应用层显式加锁(如 SELECT …… FOR UPDATE)或改用 REPEATABLE READ 并接受 MVCC 副作用。

GTID + WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS 实现强一致性读

当业务需要确认某次写入已同步到从库(例如刚下单就查订单),不能只靠 SELECT,得主动等待复制追平:

SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:1-100');

但要注意三点:

  • 该函数阻塞当前连接,超时由 slave_checkpoint_groupslave_checkpoint_period 控制,默认 300 秒
  • 必须在从库执行,且要求 gtid_mode = ONenforce_gtid_consistency = ON
  • 返回值为 -1 表示超时或 GTID 不存在,不是成功信号

生产中更稳妥的做法是:主库写入后,记录返回的 GTID(如 SELECT @@gtid_executed),再在从库轮询 SELECT RECEIVED_TRANSACTION_SET FROM performance_schema.replication_connection_statusSELECT GTID_SUBSET(……) 判断是否已接收并执行。

真正难处理的永远不是参数开关,而是那些没走主键更新、没开 ROW 格式、或在从库手动执行了 STOP REPLICA; INSERT ……; START REPLICA 的操作——它们会让复制状态彻底不可信。

星耀云
版权声明:本站原创文章,由 星耀云 2026-03-14发表,共计1815字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources