讲讲MySQL 主从复制的原理和基本流程
MySQL 的主从复制(Master-Slave Replication)是 MySQL 中最核心的高可用和扩展性技术之一。它的主要作用是实现数据备份、读写分离、高可用故障转移。
下面为你详细拆解 MySQL 主从复制的原理和基本流程。
一、 核心原理
MySQL 主从复制的核心原理可以用一句话概括:基于二进制日志(Binlog)的事件重放。
主库(Master)将数据库所有的修改操作(如 INSERT、UPDATE、DELETE 以及 DDL 语句)记录到 Binlog 中。从库(Slave)通过请求获取主库的 Binlog,并在本地重新执行(重放)这些日志中的操作,从而保持与主库数据的一致。
在这个过程中,有 三个核心线程 发挥着关键作用:
- Binlog Dump 线程(位于主库):负责读取主库的 Binlog 并发送给从库。
- I/O 线程(位于从库):负责连接主库,接收 Binlog 数据,并将其写入从库本地的中继日志(Relay Log)。
- SQL 线程(位于从库):负责读取 Relay Log 中的数据,并在从库本地执行这些 SQL 或数据修改事件。
二、 基本工作流程
主从复制的完整流程可以分为以下几个步骤:
plaintext
[客户端] ---> (1.写入数据) ---> [主库 Master] ---> (2.记录Binlog) ---> [本地 Binlog 文件]
| (3.唤醒/推送)
v
[Binlog Dump 线程]
| (4.网络传输)
v
[I/O 线程] ---> (5.写入) ---> [中继日志 Relay Log]
(从库 Slave) | (6.读取)
v
[SQL 线程] ---> (7.执行重放) ---> [从库本地数据]
详细步骤说明:
- 主库执行并记录: 客户端向主库发起写操作(如执行一个事务),主库执行完毕后,在返回给客户端成功信息之前,会将该操作按顺序写入到本地的 Binlog 中。
- 从库建立连接: 从库启动主从复制(执行
START SLAVE)时,会创建一个 I/O 线程,该线程通过指定的账号密码连上主库,并请求从指定 Binlog 文件的指定位置(Position)开始复制。 - 主库发送日志: 主库接收到从库的连接请求后,会为该从库创建一个 Binlog Dump 线程。该线程会读取 Binlog,并将其发送给从库的 I/O 线程。如果主库有新的写入,Dump 线程会被唤醒并继续发送。
- 从库接收并写入中继日志: 从库的 I/O 线程 接收到主库发来的日志数据后,将其保存在从库本地的 中继日志(Relay Log) 中,并记录当前读取到的主库 Binlog 的文件名和位置。
- 从库应用重放: 从库的 SQL 线程 持续监控 Relay Log 的变化。一旦发现有新的事件产生,SQL 线程就会读取这些事件,并在从库的数据库中重放(执行),从而实现主从数据一致。
三、 Binlog 的三种格式
复制的准确性很大程度上取决于 Binlog 记录数据的格式:
- Statement(基于语句): 记录的是执行的 SQL 语句。
- 优点: 日志量小,节省 IO 和网络带宽。
- 缺点: 遇到非确定性函数(如
NOW(),UUID())时,主从执行结果会不一致。
- Row(基于行): 不记录 SQL 语句上下文,只记录哪条数据被修改成了什么样。
- 优点: 非常安全可靠,能保证数据绝对一致。
- 缺点: 遇到批量更新(如
UPDATE table SET status = 1)时,日志量会暴增(如果表有100万行,就会记录100万条修改)。
- Mixed(混合模式): MySQL 自己判断,一般的语句用 Statement,遇到可能引起主从不一致的语句自动切换为 Row。
- (目前主流企业生产环境中,通常强制使用 Row 模式,以保证数据的绝对安全,结合 GTID 使用更佳)。
四、 主从复制的同步模式
默认情况下,MySQL 的主从复制是异步的,这可能导致数据丢失。为了解决这个问题,MySQL 提供了不同的同步模式:
- 异步复制(Asynchronous replication - 默认):
- 主库把事务写入 Binlog 后,直接返回给客户端成功,不管从库是否收到了日志。
- 风险: 如果主库突然宕机,而部分 Binlog 还没来得及传给从库,此时切换主从会导致数据丢失。
- 半同步复制(Semi-synchronous replication):
- 主库执行完事务后,不立刻返回给客户端,而是等待至少一个从库收到 Binlog 并写入 Relay Log 后,再给客户端返回成功。
- 优点: 兼顾了性能与数据安全性。
- 全同步复制 / 组复制(Group Replication - MGR):
- 所有节点之间进行协商,大多数节点成功执行事务才算成功。数据安全性最高,但性能损耗最大。
五、 常见面试/实战问题:主从延迟
问题现象: 主库写入数据后,从库需要过一段时间(几秒甚至几小时)才能查到该数据。
产生原因:
- 单线程瓶颈: 在 MySQL 5.6 之前,从库的 SQL 线程是单线程的。如果主库并发写入极高,从库单线程回放必然跟不上主库多线程写入的速度。
- 大事务/大表 DDL: 主库执行了一个大事务(如一次性 delete 100万条数据)或给大表加索引,从库也需要执行同样的时间,导致阻塞。
- 网络延迟或从库硬件差: 从库机器性能不如主库,或者跨机房网络慢。
解决策略:
- 开启 MTS (Multi-Threaded Slave) 多线程复制(MySQL 5.7+ 默认支持基于 Logical Clock 的并行复制)。
- 业务层面打散大事务,避免长事务。
- 读写分离的业务中,对一致性要求极高的读请求,强制路由到主库查询。
- 确保主从机器硬件配置一致。