MySQL主从复制原理详解
MySQL 主从复制是一种基于日志的异步数据复制技术,它允许将一个 MySQL 数据库服务器(主服务器/Master)的数据自动复制到一个或多个其他 MySQL 服务器(从服务器/Slave)。其核心目标是实现数据冗余、读写分离、负载均衡、高可用性基础以及数据分析或备份。
以下是主从复制的工作原理详解:
核心组件:二进制日志 (Binary Log - binlog)
作用: 这是主从复制的基础。主服务器将所有会修改数据库数据的操作(
INSERT
,UPDATE
,DELETE
,DDL
等)以“事件”的形式顺序记录到 binlog 中。内容: 记录的是逻辑操作(SQL 语句本身)或行更改(修改前后的行数据),具体取决于 binlog 格式 (
STATEMENT
,ROW
,MIXED
)。目的: 为从服务器提供需要重放的数据变更序列。
复制线程 (Replication Threads)
主服务器 - Binlog Dump Thread:
当有从服务器连接时,主服务器会为每个连接的从服务器创建一个
Binlog Dump
线程。该线程负责读取主服务器上的 binlog 中的事件。
根据从服务器请求的位置(或 GTID),将 binlog 事件发送给连接的从服务器。
线程状态可通过
SHOW PROCESSLIST
在主服务器上查看。从服务器 - I/O Thread:
启动复制时 (
START SLAVE;
或START REPLICA;
),从服务器创建一个I/O Thread
。该线程负责连接到主服务器。
向主服务器的
Binlog Dump Thread
发起请求,请求指定 binlog 文件中的指定位置(或 GTID)之后的事件。接收主服务器发送过来的 binlog 事件,并将其写入到从服务器本地的中继日志中。
线程状态可通过
SHOW SLAVE STATUS
或SHOW REPLICA STATUS
查看 (Slave_IO_Running
/Replica_IO_Running
)。从服务器 - SQL Thread:
启动复制时,从服务器创建一个
SQL Thread
。该线程负责读取本地的中继日志。
解析并执行中继日志中包含的事件(即 SQL 语句或行变更操作),将这些变更应用到从服务器自己的数据库中。
执行完成后,会更新从服务器上的复制位置信息(如
Relay_Master_Log_File
,Exec_Master_Log_Pos
或Retrieved_Gtid_Set
,Executed_Gtid_Set
)。线程状态可通过
SHOW SLAVE STATUS
或SHOW REPLICA STATUS
查看 (Slave_SQL_Running
/Replica_SQL_Running
)关键日志文件 - 中继日志 (Relay Log)
作用: 存在于从服务器上,是主从复制的中间缓冲区。
写入: 由从服务器的
I/O Thread
将从主服务器接收到的 binlog 事件写入。读取: 由从服务器的
SQL Thread
读取并执行其中的事件。目的: 解耦接收事件和应用事件的过程,避免
SQL Thread
执行慢影响I/O Thread
接收新事件。同时,如果从服务器重启,可以从本地中继日志的断点继续执行,而不必每次都从主服务器请求完整 binlog复制流程 (Step-by-Step)
配置从服务器: 在从服务器上配置主服务器的地址、端口、复制用户凭证、起始复制位置(文件名和偏移量)或 GTID 集合。执行
CHANGE MASTER TO ...
或CHANGE REPLICATION SOURCE TO ...
。启动从服务器复制线程: 在从服务器上执行
START SLAVE;
或START REPLICA;
。从服务器 I/O Thread 连接主服务器: 从服务器的
I/O Thread
使用配置的用户连接到主服务器。主服务器 Binlog Dump Thread 响应: 主服务器验证连接后,为从服务器创建
Binlog Dump Thread
。请求 binlog 事件: 从服务器
I/O Thread
向主服务器Binlog Dump Thread
发送请求,告知它需要从哪个 binlog 文件的哪个位置(或哪个 GTID)开始读取事件。主服务器发送 binlog 事件: 主服务器
Binlog Dump Thread
读取指定位置之后的 binlog 事件,并通过网络发送给从服务器的I/O Thread
。写入中继日志: 从服务器的
I/O Thread
将接收到的 binlog 事件按顺序写入本地的中继日志文件 (relay-log.*
)。从服务器 SQL Thread 读取中继日志: 从服务器的
SQL Thread
持续检测中继日志文件。应用数据变更:
SQL Thread
读取中继日志中的事件,解析并执行(如果是STATEMENT
格式则执行 SQL 语句;如果是ROW
格式则应用行变更),将变更应用到从服务器的数据库中。更新复制位置:
SQL Thread
成功执行完一个事件后,会更新从服务器上的元数据(如master.info
/relay-log.info
文件或mysql.slave_relay_log_info
/mysql.slave_master_info
表,或 GTID 状态),记录最后一个成功执行的事件在主服务器 binlog 中的位置(或 GTID)。循环往复: 步骤 5-10 持续进行,
I/O Thread
不断获取新事件写入中继日志,SQL Thread
不断读取中继日志并执行重要特性
异步复制 (Asynchronous Replication): 这是默认模式。主服务器在将事件写入 binlog 并发送给
Binlog Dump Thread
后,就认为事务提交成功,不会等待从服务器确认接收或执行。因此,主从数据存在延迟(Replication Lag)。半同步复制 (Semisynchronous Replication): 插件提供。主服务器在提交事务前,会等待至少一个从服务器确认已接收到该事务的事件并写入其中继日志(不要求执行完)。提高了数据一致性,但增加了主库响应时间。
GTID (Global Transaction Identifier): 全局唯一的事务ID。使用 GTID 可以简化复制管理(故障切换、添加新从库时不再依赖 binlog 文件名和位置),并保证事务在主从拓扑中的唯一性和一致性。
复制格式 (binlog_format):
STATEMENT
(SBR):记录 SQL 语句本身。日志量小,但某些非确定性函数(如NOW()
,RAND()
,UUID()
)或依赖上下文操作可能导致主从不一致。ROW
(RBR):记录每行数据是如何被修改的(修改前的行和修改后的行)。日志量大,但最安全可靠,能保证主从严格一致。推荐使用。MIXED
(MBR):混合模式,默认使用STATEMENT
,但对可能导致不一致的操作自动切换到ROW
格式。
总结起来:
1.主库数据变更 2.写入主库 binlog 3.主库 Binlog Dump Thread 发送 -> 从库 I/O Thread 接收 4.写入从库 Relay Log 5.从库 SQL Thread 读取并执行 Relay Log 6.数据在从库生效