MySql主从复制

101 阅读8分钟

主从复制

主从复制是 MySQL 的一种重要机制,用于将主数据库上的数据变化(写操作)复制到从数据库,以实现数据同步、负载均衡、读写分离以及高可用性等目标。

1. 主从复制的基本流程

主从复制基于以下三个核心步骤:

  1. 主库记录 Binlog

    • 主数据库将所有数据更改操作(如 INSERTUPDATEDELETE)记录到 Binary Log(Binlog) 中。
    • Binlog 是一种追加写的日志文件,记录了所有成功提交的事务操作。
  2. 从库获取 Binlog

    • 从库通过 I/O 线程从主库拉取 Binlog,并将其存储为本地的 Relay Log(中继日志)。
  3. 从库重放 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. 主从复制的步骤详解

  1. 主库记录事务操作到 Binlog

    • 用户在主库执行写操作(如 INSERT)。
    • 主库记录操作到 Binlog 中,并刷新到磁盘。
  2. 从库请求 Binlog

    • 从库的 I/O 线程向主库的 Binlog Dump 线程发送请求,指定从哪里开始读取 Binlog(通过 log_filelog_pos 定位)。
  3. 主库发送 Binlog

    • 主库的 Binlog Dump 线程读取指定位置的 Binlog,并发送给从库。
  4. 从库写入 Relay Log

    • 从库的 I/O 线程接收 Binlog 并写入 Relay Log。
  5. 从库执行 Relay Log

    • 从库的 SQL 线程读取 Relay Log,解析其中的操作,并在从库执行。

6. 主从复制的关键参数

  • log_bin:是否启用 Binlog(主库必须开启)。
  • server_id:主从库的唯一标识,必须不同。
  • relay_log:从库中继日志的存储路径。
  • binlog_format:Binlog 格式(STATEMENTROWMIXED)。
  • 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 logcommit 的情况下,事务并未真正完成。
  • 从库会接收到事务的 binlog,但不会立即应用该事务。因为事务的应用需要完整的提交标记。

从库会依赖 binlog 的 GTID 或事务结束标记 来判断事务是否完整。如果没有看到完整的提交标记,从库不会将事务的操作应用到自己的数据中。

3. 为什么需要二阶段提交

MySQL 的 redo logbinlog 是独立的日志系统,为了保证数据的 一致性可靠性,需要二阶段提交来协调二者:

  • 在事务提交时,binlogredo log 的状态需要一致。
  • 如果 binlog 已刷盘但 redo logcommit,主库在崩溃恢复时会发现该事务未提交,redo log 不会重放,事务的数据也不会对外可见。

4. 总结

binlog 已刷盘但 redo logcommit 的情况下:

  • 主库会将 binlog 推送给从库。
  • 从库会接收 binlog,但由于缺少提交标记,事务的更改不会被真正应用。
  • 此时事务在主库和从库都属于未提交状态,数据不会被外部查询到。

通过二阶段提交机制,binlogredo 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 logbinlog 的二阶段提交协调,MySQL 能够在崩溃后正确恢复事务状态。

4. 从库如何依赖事务提交标记

在主从复制中:

  • 从库的 SQL 线程会解析 binlog
  • 当遇到 COMMIT EVENT 时,从库会将该事务的所有操作应用到自己的数据中,确保事务的一致性和完整性。

5. 总结

  • binlog 的事务提交标记(COMMIT EVENT 是在事务完成二阶段提交之后追加的,标志事务的最终完成。
  • 它的写入时机保证了 binlogredo log 的一致性,避免数据不一致的情况。
  • 从库依赖该标记来正确识别和应用事务。