MySQL 的高可用方案建立在主备数据的一致性之上。通过 Binlog(归档日志)的同步与重放,备库可以持续获取主库的变更并维持相同的数据状态。以下是主备同步机制的物理流程、GTID 的核心作用以及异常处理机制。
一、 主备同步原理与线程架构
MySQL 的同步是一个典型的"生产者-消费者"模型,由备库驱动,主库响应。整个过程涉及主从两端的三个关键线程:
- Binlog Dump Thread(主库):当备库连接时,主库会为其创建一个专用的 dump 线程 。该线程负责读取主库的 binlog 并通过长连接发送给备库 。
- I/O Thread(备库) :负责与主库建立长连接,接收主库推送的 binlog,并将其写入备库本地的中转日志(relay log) 。
- SQL Thread(备库):负责读取并解析 relay log,在备库本地执行这些命令,从而实现数据的更新 。
二、 GTID 的定义与作用
GTID (Global Transaction Identifier) 是全局事务标识符。其标准格式为 server_uuid:gno。其中 server_uuid 是实例的唯一标识,gno 是在该实例上提交事务时递增的序列号 。
GTID 的核心价值:
- 全局唯一性:确保同一个事务在整个主从集群中只有一个身份证。
- 自动幂等性:备库在执行事务前会检查该 GTID 是否已存在于本地集合。如果已存在(表示已执行过),则直接跳过该事务,防止重复执行导致主键冲突 。
- 简化运维:在主备切换或断线重连时,不再需要人工寻找物理位点(文件名和偏移量),系统通过 GTID 集合自动寻址 。
三、 物理同步过程详解
同步过程可以划分为两个关键阶段:
1. 协商阶段 (Negotiation Phase)
该阶段发生在备库刚连接到主库或断线重连的瞬间:
- 发送集合 :备库通过
MASTER_AUTO_POSITION=1协议将自己本地已执行的 GTID 集合(Executed_Gtid_Set) 发送给主库 。 - 计算差集:主库接收后,将其与自己 binlog 中记录的 GTID 集合对比,计算出备库缺失的事务差集 。
- 确定起点:主库根据差集定位到 binlog 文件的具体物理位置,准备开始推送。
2. 推送阶段 (Push Phase)
一旦起点确定,同步进入持续的流水线模式:
- 实时推送 :主库的
dump_thread持续读取 binlog 事件发送。如果主库产生新日志,会触发信号唤醒等待中的dump_thread进行推送 。 - 示例 :主库执行
INSERT INTO t VALUES(1,1);。该事务被分配 GTIDUUID:101。dump_thread将该事务及其 GTID 头部信息发往备库。 - 更新状态 :备库执行完该事务后,会将其 GTID
UUID:101加入本地的Executed_Gtid_Set内存块中,并定期持久化到磁盘。
四、 长连接断开的处理机制
在生产环境中,网络闪断或主库维护会导致长连接断开。MySQL 依靠 GTID 的断点续传(Breakpoint Resumption) 实现自动恢复:
- 自动重连:备库发现连接异常后会持续尝试重连。
- 重新协商 :连接成功后,备库再次发起"协商阶段",将最新的、已更新的
Executed_Gtid_Set发送给主库 。 - 精准续传:主库重新计算差集,发现备库已经跑到了最新的位置,于是只推送断开瞬间之后产生的那些新事务。
这种机制保证了无论链路如何断开,只要 binlog 依然存在且 GTID 集合逻辑完整,数据同步就能准确无误地恢复,无需人工介入干预物理位点 。