MySQL 高可用基础教程之一主从复制方案介绍
大纲
主从复制概述
主从复制用途
实时灾备
:用于故障切换(高可用)读写分离
:提供查询服务(读扩展)数据备份
:避免影响业务(高可用)
主从复制原理
- 主从复制的原理
- (1) Master 节点将数据的改变都记录到二进制 Binlog 日志中,只要 Master 上的数据发生改变,则将其改变写入二进制日志。
- (2) Salve 节点会在一定时间间隔内对 Master 二进制日志进行探测,判断其是否发生改变,如果发生改变,则启动一个 I/O 线程请求 Master 二进制事件。
- (3) 同时 Master 节点会为每个 I/O 线程启动一个 Binlog Dump 线程,用于向其发送二进制事件,让 Slave 节点保存至本地的 Relay-Log (中继日志)中。
- (4) Slave 节点启动 SQL 线程从 Relay-Log (中继日志)中读取二进制日志,并在本地重放,使得其数据和 Master 节点的保持一致。
- (5) 最后 Slave 节点的 I/O 线程 和 SQL 线程将进入睡眠状态,等待下一次被唤醒。
- 主从复制的重点
- (1) Slave 节点会启动两个线程,分别是 I/O 线程和 SQL 线程。
- (2) Slave 节点的 I/O 线程会去请求 Master 节点的 Binlog,并将得到的 Binlog 写入本地的 Relay-Log(中继日志)文件中。
- (3) Master 节点会启动一个 Binlog Dump 线程,用来给 Slave 节点的 I/O 线程传 Binlog。
- (4) Slave 节点的 SQL 线程会读取本地 Relay-Log(中继日志)文件中的日志,并解析成 SQL 语句逐一执行。
主从复制方式
基于语句的复制
: 在主服务器执行的 SQL 语句,在从服务器也执行同样语句,这是 MySQL 默认采用的复制方式。基于行的复制
: 将改变的数据复制给从服务器,而不是让 SQL 语句在从服务器上执行一遍,从 MySQL5.0
版本开始支持。混合类型的复制
: 默认采用基于 SQL 语句的复制(效率较高),一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。
主从复制类型
异步复制
异步复制是 MySQL 默认使用的复制类型。
特别注意
异步复制不能保证 Slave 节点一定能接收到 Binlog 日志,即无法保证数据的一致性,但执行效率是最高的。
整体流程
半同步复制
从 MySQL 5.5
版本开始,MySQL 可以让 Master 节点在某一个时间点等待 Slave 节点的 ACK 消息,接收到 ACK 消息后才进行事务提交,这就是半同步复制。半同步复制可以保证至少有一个 Slave 节点的 Relay Log(中继日志)是完整的数据,即对数据一致性有一定的保障,但执行效率较慢。
- 半同步复制在提交过程中增加了一个延迟,即在提交事务时,在客户端接收到查询结束反馈前必须保证二进制日志已经传输到一台 Slave 节点上。
- 半同步不会阻塞 Master 节点上的事务提交,只有通知客户端被延迟了。
- Slave 节点在接收到事务后发送 ACK 消息,而不是完成事务后再发送。
- 如果 Slave 节点一直没有回应,会超时自动切换为异步复制模式。
整体流程
半同步复制插件
MySQL 的半同步复制是以插件的形式提供的,因此在使用之前需要安装对应的插件,如下所示:
1 | # 主库安装半同步复制插件 |
半同步复制大坑
在极端情况下,半同步复制也无法保证数据的一致性(至少有一个 Slave 节点的数据是完整的),如下图所示:
为了避免出现上述图中数据不一致的问题,强烈建议使用 SET rpl_semi_sync_master_wait_point=AFTER_SYNC
开启了 MySQL 的增强半同步,从 5.7
版本开始默认就是开启的。特别注意,MySQL 5.7
之前的旧版本默认是使用 AFTER_COMMIT
(传统半同步)。
MHA 与半同步复制是绝配
MHA 高可用架构非常适合搭配半同步复制一起使用,详细介绍请看 这里 的教程。
全同步复制
全同步复制属于主从强一致方案,对 Binlog 有一定的要求,且执行效率最慢。MySQL 5.7.17
版本开始引入了组复制技术,因此全同步复制可以配合 MGR 高可用架构 一起使用。MGR 中的组复制协议如下图所示:
主从复制进阶
并行复制
MySQL 从 5.6
版本开始引入了并行复制功能,用于改善复制延迟的问题。这是因为 Slave 节点只有一个 SQL 线程,当主库写压力大时,复制很可能会延迟。
5.6 版本并行复制
MySQL 5.6
版本仅支持基于库的并行复制,也就是多个线程分别执行不同库的复制操作,互不干扰。值得一提的是,单库多表的复制效率并没有提升。
5.7 版本并行复制
MySQL 5.7
版本支持基于组提交的并行复制,不再有库的并行复制限制(即支持单库多表的并行复制)。当事务提交时,通过在主库上的二进制日志中添加组提交信息,并将在单个操作中写入到二进制日志中。如果多个事务能同时提交成功,那么它们意味着没有冲突,因此可以在 Slave 节点上并行执行。InnoDB 事务提交采用的是两阶段提交模式。一个阶段是 Prepare,另一个阶段是 Commit。MySQL 5.7
版本的并行复制基于一个前提,即所有已经处于 Prepare 阶段的事务,都是可以并行提交的。在 MySQL 5.7
版本中,其设计方式是将组提交的信息存放在 GTID 中。为了避免用户没有开启 GTID 功能,MySQL 5.7
又引入了称之为 Anonymous_Gtid
的二进制日志 Event 类型,即日志中具有相同的 last_committed
,表示这些事务都在一组内。
8.0 版本并行复制
MySQL 8.0
版本支持基于 write-set
的并行复制。有一个集合变量来存储事务修改的记录信息(主键哈希值),所有已经提交的事务所修改的主键值经过 Hash 后都会与那个变量的集合进行对比,来判断改行是否与其冲突,并以此来确定依赖关系,没有冲突即可并行,Row 级别的粒度,类似于之前的表锁行锁差异,效率会更高。
日志点与 GTID
MySQL 的主从复制,支持基于日志点或者 GTID 进行复制。
基于日志点复制
- Slave 节点请求 Master 节点的增量日志依赖于日志偏移量。
- 配置主从复制链路时需要指定参数。
- 支持 MMM 和 MHA。
基于 GTID 复制
- GTID(全局事务唯一 ID),其构成是
GTID = source_id:transaction_id
。 - Slave 节点增量同步 Master 节点的数据依赖于其未同步的全局事务 ID。
- 配置主从复制链路时,Slave 节点会根据已经同步的事务 ID 继续自动同步。
- 支持 MHA。
- GTID(全局事务唯一 ID),其构成是
复制方式选择
如何是为了兼容旧版本的 MySQL 和 MMM,建议选择基于日志点复制,其他业务场景可以选择基于 GTID 复制。
主从复制架构
MySQL 常见的主从复制架构如下:
主从复制常见问题
主从复制高延迟
造成 MySQL 主从复制高延迟的常见原因如下:
网络
:如主库或者从库的带宽打满,或者主从之间的网络延迟很大,导致主库上的 Binlog 没有全量传输到从库,造成了延迟。机器性能
:从库的硬件性能较差,比如主库使用 SSD 硬盘,而从库使用 SATA 硬盘。从库高负载
:有很多业务会在从库上做统计,把从库服务器搞成高负载,从而造成从库延迟很大的情况。大事务
:比如在 RBR 模式下,执行带有大量的 Delete 操作,这种通过查看processlist
相关信息以及使用mysqlbinlog
查看 Binlog 中的 SQL 就能快速进行排查。锁
: 锁冲突问题也可能导致从库的 SQL 线程执行慢,比如从库上有一些select ... for update
的 SQL,或者使用了 MyISAM 存储引擎等。
MySQL 主从复制高延迟硬件方面的优化方案如下:
- 采用性能更高的服务器,比如 4U 比 2U 性能明显要更好。
- 数据库存储使用 SSD 硬盘、磁盘阵列或者 SAN 存储网络,提升随机写的性能。
- 主从库之间保证处在同一个交换机下面,并且是万兆环境。
最佳实践
- 全同步复制相对于半同步复制来说,数据的一致性更高,但性能代价也更高。具体选择哪种复制,取决于对数据一致性和性能的需求权衡。
- 在关键业务场景下(对数据一致性的要求较高),可以更倾向于选择全同步复制,而在某些读写分离的场景下,可以考虑半同步复制。