主从复制
主从复制是 MySQL 的一种重要机制,用于将主数据库上的数据变化(写操作)复制到从数据库,以实现数据同步、负载均衡、读写分离以及高可用性等目标。
1. 主从复制的基本流程
主从复制基于以下三个核心步骤:
-
主库记录 Binlog:
- 主数据库将所有数据更改操作(如
INSERT、UPDATE、DELETE)记录到 Binary Log(Binlog) 中。 - Binlog 是一种追加写的日志文件,记录了所有成功提交的事务操作。
- 主数据库将所有数据更改操作(如
-
从库获取 Binlog:
- 从库通过 I/O 线程从主库拉取 Binlog,并将其存储为本地的 Relay Log(中继日志)。
-
从库重放 Relay Log:
- 从库通过 SQL 线程读取 Relay Log 中的日志内容,并在本地执行日志中的操作,达到与主库数据一致的目的。
2. 主从复制的三大线程
主从复制过程中涉及以下线程:
主库:Binlog Dump 线程
- 当主库接收到从库的复制请求后,会开启一个 Binlog Dump 线程。
- 该线程将主库的 Binlog 按顺序发送给从库。
从库:I/O 线程
- 从库启动后,会创建一个 I/O 线程。
- 该线程向主库发送请求以获取 Binlog,将接收到的日志写入本地的 Relay Log。
从库:SQL 线程
- 从库还会创建一个 SQL 线程。
- 该线程读取 Relay Log,将日志中的内容解析为 SQL 语句并在从库执行。
3. 主从复制的模式
同步复制
- 主库上的事务只有在从库完成复制后才会提交。
- 数据一致性较高,但性能较差。
- 通常用于一些对一致性要求极高的场景。
异步复制(默认)
- 主库提交事务后立即返回,不等待从库完成复制。
- 高性能,适合读多写少的场景。
- 存在延迟风险,主从之间可能短时间数据不一致。
半同步复制
- 主库提交事务时,至少等待一个从库确认接收到 Binlog。
- 在性能和一致性之间提供一种平衡。
4. 主从复制的关键组件
Binlog(Binary Log)
-
记录主库的所有数据变更操作。
-
支持两种格式:
- STATEMENT:记录每个 SQL 语句(体积小,但可能有非确定性问题)。
- ROW:记录每行数据的变化(体积大,但更精确)。
- MIXED:混合模式,根据情况选择。
Relay Log(中继日志)
- 从库本地存储从主库拉取的 Binlog。
- I/O 线程将 Binlog 写入 Relay Log,SQL 线程再读取 Relay Log 并重放操作。
5. 主从复制的步骤详解
-
主库记录事务操作到 Binlog:
- 用户在主库执行写操作(如
INSERT)。 - 主库记录操作到 Binlog 中,并刷新到磁盘。
- 用户在主库执行写操作(如
-
从库请求 Binlog:
- 从库的 I/O 线程向主库的 Binlog Dump 线程发送请求,指定从哪里开始读取 Binlog(通过
log_file和log_pos定位)。
- 从库的 I/O 线程向主库的 Binlog Dump 线程发送请求,指定从哪里开始读取 Binlog(通过
-
主库发送 Binlog:
- 主库的 Binlog Dump 线程读取指定位置的 Binlog,并发送给从库。
-
从库写入 Relay Log:
- 从库的 I/O 线程接收 Binlog 并写入 Relay Log。
-
从库执行 Relay Log:
- 从库的 SQL 线程读取 Relay Log,解析其中的操作,并在从库执行。
6. 主从复制的关键参数
log_bin:是否启用 Binlog(主库必须开启)。server_id:主从库的唯一标识,必须不同。relay_log:从库中继日志的存储路径。binlog_format:Binlog 格式(STATEMENT、ROW、MIXED)。sync_binlog:控制 Binlog 的刷盘策略。
7. 主从复制的常见问题
主从延迟
-
主从复制是异步的,写操作在主库提交后,从库可能需要时间重放 Relay Log。
-
延迟的原因可能包括:
- 网络带宽限制。
- 从库性能较低。
- 大事务操作。
主从不一致
- 可能由于网络中断、主库宕机、操作系统错误等导致。
- 使用半同步复制或强同步复制可以缓解。
8. 主从复制的应用场景
- 读写分离:主库负责写操作,从库负责读操作,提高系统性能。
- 数据备份:从库作为主库的实时备份,用于灾难恢复。
- 高可用性:在主库宕机时,从库可以快速提升为主库,保证业务连续性。
- 分布式架构:多主多从模式或级联复制,支持更复杂的分布式部署。
问题:binlog和redo log的二阶段提交中,binlog已经刷盘,而redo log还未commit,此时binlog会按照主从同步,将其同步到从库吗?
在 MySQL 的 二阶段提交机制 中,binlog 已经刷盘但 redo log 还未 commit 时,主库的行为如下:
1. 当前事务状态分析
在二阶段提交中:
- 第一阶段:
binlog已刷盘成功。 - 第二阶段:
redo log的状态更新为commit。
如果在第一阶段结束后发生了异常,比如在 redo log 还未完成 commit 时,事务并未真正完成。这时事务是未提交的(Uncommitted),因此数据并不算最终一致,事务的完整性无法保证。
2. 主从复制中的行为
在主从复制中,从库同步数据的依据是 binlog。主库的 binlog 刷盘成功后,Binlog Dump 线程会将 binlog 的内容推送到从库。但关键在于:
- 在事务未提交时,即
redo log未commit的情况下,事务并未真正完成。 - 从库会接收到事务的
binlog,但不会立即应用该事务。因为事务的应用需要完整的提交标记。
从库会依赖 binlog 的 GTID 或事务结束标记 来判断事务是否完整。如果没有看到完整的提交标记,从库不会将事务的操作应用到自己的数据中。
3. 为什么需要二阶段提交
MySQL 的 redo log 和 binlog 是独立的日志系统,为了保证数据的 一致性 和 可靠性,需要二阶段提交来协调二者:
- 在事务提交时,
binlog和redo log的状态需要一致。 - 如果
binlog已刷盘但redo log未commit,主库在崩溃恢复时会发现该事务未提交,redo log不会重放,事务的数据也不会对外可见。
4. 总结
在 binlog 已刷盘但 redo log 未 commit 的情况下:
- 主库会将
binlog推送给从库。 - 从库会接收
binlog,但由于缺少提交标记,事务的更改不会被真正应用。 - 此时事务在主库和从库都属于未提交状态,数据不会被外部查询到。
通过二阶段提交机制,binlog 和 redo log 的状态能够被有效协调,以保证数据一致性和崩溃后的恢复能力。
问题:binlog的事务提交标记,是发生在什么时候?
在 MySQL 中,binlog 的事务提交标记 是一个特殊的事件,用来标识一个事务的结束,确保从库在主从复制时能够正确识别事务边界。该提交标记的写入时机与 二阶段提交 密切相关。
1. 事务提交标记(COMMIT EVENT)
binlog 的事务提交标记(COMMIT EVENT)是 binlog 日志中记录的最后一个事件,用来明确一个事务已经成功提交。只有在事务完成二阶段提交后,COMMIT EVENT 才会写入到 binlog。
2. 事务提交标记的写入时机
事务提交标记写入 binlog 的具体流程如下:
第一阶段:预提交 redo log
- 当事务即将提交时,先将所有的变更写入到 Redo Log 中,但此时标记为 “Prepare 状态” ,并刷盘。此为二阶段提交的第一阶段。
第二阶段:预写 binlog
- 在事务提交之前,
binlog的事务内容(SQL 语句或行级变更)会被先行写入binlog文件,并 刷盘 确保持久化。 - 此时,事务的变更内容已经在
binlog中,但并未写入提交标记。
第三阶段:写入 COMMIT EVENT
- 接着,
redo log被标记为commit状态,这标志着事务提交在存储引擎层完成。 - 在存储引擎完成
redo log的提交后,MySQL 在binlog中追加一个COMMIT EVENT。 - 此时事务的所有内容(包括提交标记)已经完整写入
binlog,从库可以通过该标记识别事务边界。
3. 为什么事务提交标记要在二阶段提交后写入?
- 数据一致性保证:如果
binlog提交标记在redo log提交之前写入,而系统在这期间崩溃,则事务在binlog看起来像是已提交,但redo log中没有提交,数据会不一致。 - 崩溃恢复:通过
redo log和binlog的二阶段提交协调,MySQL 能够在崩溃后正确恢复事务状态。
4. 从库如何依赖事务提交标记
在主从复制中:
- 从库的 SQL 线程会解析
binlog。 - 当遇到
COMMIT EVENT时,从库会将该事务的所有操作应用到自己的数据中,确保事务的一致性和完整性。
5. 总结
binlog的事务提交标记(COMMIT EVENT) 是在事务完成二阶段提交之后追加的,标志事务的最终完成。- 它的写入时机保证了
binlog和redo log的一致性,避免数据不一致的情况。 - 从库依赖该标记来正确识别和应用事务。