闲聊MySQL(十):浅析主从同步

前言

在前面的系列文章中,我们对MySQL内部组成结构、索引结构、查询解析等进行了分析与了解,本篇,作为本系列文章的终篇,我们来聊聊MySQL中比较重要的一个机制,数据同步机制,也就是我们常说的,主从同步。

本篇基于MySQL 8.x版本。

Replication Between Master and Slave

一说到MySQL的主从同步,你的脑海中肯定第一反应会是binlog,没有错,我们日常开发中较为场景的主从同步模式,就是基于MySQL的binlog日志来进行的,但是您可能之前并没有接触过主从同步的场景或者说对这里不太了解,那么我们把问题拉回原点,什么是MySQL的主从同步?

MySQL主从同步机制

MySQL的数据同步机制可以将数据从一个主数据库同步到另一个或多个从数据库,即Master-Slaves模式,默认的话,同步的过程是异步进行的;从节点不需要与主节点建立永久型的连接。可以通过配置,你可以选择复制全部的数据库或者指定的数据库,亦或者是指定的某个数据库中的某些表。
MySQL同步

MySQL主从同步的高级特性

Scale-out solutions:可以叫做一主多从的模式,在该模式下,全部的写入与更新操作都只会操作主库。读操作,可以使用一个从库或者多个从库。这种模型下可以提升数据写入性能,在通过多个从库的模式下,读操作的性能也会大大提升。

Data security:由于数据可以由主库同步给从库,从库可以随时去暂停同步的进程,因此可以在从库上运行备份服务而不必担心损坏主库的数据。

Analytics:在主库上不断的会产生新的数据,数据分析的操作可以在从库上执行,而不会影响主库的性能。

Long-distance data distribution:你可以利用数据同步功能,创建一个远端数据的备份,从而无需一直访问主库。

MySQL同步类型

在MySQL8.0中,支持三种类型的同步方式:

1、异步复制方式(asynchronous replication)

这种同步方式是最为传统的复制方式,也就是我们常说的基于binlog日志的同步方式,当主库发生数据变化时,会将数据的更改写入日志文件中,异步同步给从库,从库再进行对应的同步操作。
异步复制

2、半同步方式(semisynchronous replication)

默认情况下,MySQL复制是异步的。主进程将事件写入binlog,但不知道slave什么时候处理了这些事件。使用异步复制,如果主服务器崩溃,它提交的事务可能没有传输到任何slave上。在这种情况下,从master到slave的故障转移可能会导致数据的丢失。

而使用半同步方式,在一个事务中,在主库上的写入或更新的操作,会在从库收到同步事件并发出确认或者超时之前,一直阻塞着,如果超时发生时没有任何从库确认消息,则master将恢复到异步复制。当至少一个semi-sync的slave赶上时,返回到半同步复制。

更多详细信息,请参见MySQL官方文档:Semisynchronous Replication

https://dev.mysql.com/doc/refman/8.0/en/replication-semisync.html

3、延迟同步方式(delayed replication)

在MySQL8.0中,也支持了延迟同步的方式,可以设定从库与主库之间数据同步的延迟时长。

请参见MySQL官方文档:Delayed Replication

https://dev.mysql.com/doc/refman/8.0/en/replication-delayed.html

MySQL主从同步方式

在最新版本的MySQL中(MySQL 8.0),可以支持多种模式的数据同步。

一、基于binlog日志文件同步

最传统的方式是基于基于主库的二进制Log日志文件,也就是我们最常说的binlog数据异步同步。

MySQL binlog是二进制格式的日志文件,但是不能把binlog文件等同于OS系统某目录下的具体文件,这是狭隘的。binlog是用来记录MySQL内部对数据库的改动(只记录对数据的修改操作),主要用于数据库的主从复制以及增量恢复。

它的核心作用:

1、复制:MySQL Replication在Master端开启binlogMaster把它的二进制日志传递给Slave并回放来达到master-slave数据一致的目的。

2、数据恢复:可以通过mysqlbinlog工具恢复数据。

3、增量备份

binlog文件内容

默认情况下binlog日志是二进制格式,无法直接查看。可使用两种方式进行查看:

第一种:通过mysqlbinlog工具来查看

mysqlbinlog是MySQL官方提供的一个binlog查看工具,可以查看本地的binlog文件,也可以使用–read-from-remote-server从远程服务器读取二进制日志,还可使用--start-position --stop-position、--start-time= --stop-time精确解析binlog日志。

使用mysqlbinlog工具解析出来的binlog文件内容大致如下:

***************************************************************************************
        # at 1190   //事件的起点
        #171223 21:56:26 server id 123  end_log_pos 1190 CRC32 0xf75c94a7 	Intvar
        SET INSERT_ID=2/*!*/;
        #171223 21:56:26 server id 123  end_log_pos 1352 CRC32 0xefa42fea 	Query	thread_id=4	exec_time=0	error_code=0
        SET TIMESTAMP=1514123786/*!*/;              //开始事务的时间起点 (每个at即为一个event)
        insert into tb_person  set name="name__2", address="beijing", sex="man", other="nothing"  //sql语句
        /*!*/;
        # at 1352
        #171223 21:56:26 server id 123  end_log_pos 1383 CRC32 0x72c565d3 	Xid = 5 //执行时间,及位置戳,Xid:事件指示提交的XA事务
      ***************************************************************************************

第二种:通过命令行解析

可以通过MySQL命令行,直接解析binlog文件,语法如下:

SHOW BINLOG EVENTS
   [IN 'log_name']
   [FROM pos]
   [LIMIT [offset,] row_count]

解析内容如下:

*************************** 13. row ***************************
Log_name: mysql-bin.000007
Pos: 1190
Event_type: Query  //事件类型
Server_id: 123
End_log_pos: 1352   //结束pose点,下个事件的起点
Info: use `test`; insert into person set name="zhangsan", address="beijing", sex="male", other="nothing"
*************************** 14. row ***************************
Log_name: mysql-bin.000007
Pos: 1352
Event_type: Xid
Server_id: 123
End_log_pos: 1383
Info: COMMIT /* xid=51 */

各字段含义如下:

Log_name:日志文件列表。(The name of the file that is being listed. )

Pos:事件在binlog文件中的开始位置。(The position at which the event occurs. )

Event_type:事件的类型。(An identifier that describes the event type. )

Server_id:标识哪一个server产生的binlog日志。(The server ID of the server on which the event originated. )

End_log_pos:事件在binlog文件中的结束位置。(The position at which the next event begins, which is equal to Pos plus the size of the event.)

Info:log的一些备注信息,可以直观的看出进行了什么操作。(More detailed information about the event type. The format of this information depends on the event type.)

更加详细的信息,可以参见MySQL的官方文档:https://dev.mysql.com/doc/refman/8.0/en/show-binlog-events.html

二、GTIDs同步

从MySQL5.6版本以后,开始支持新的同步模式,即基于全局事务标识global transaction identifiers (GTIDs)模型,这种模式下,可以在集群全局范围标识事务,用于取代过去通过binlog文件偏移量定位复制位置的传统方式,从而来简化的数据同步的过程。

借助GTID,在发生主备切换的情况下,MySQL的其它Slave可以自动在新Master上找到正确的同步位置,这大大简化了复杂复制拓扑下集群的维护,也减少了人为设置复制位置发生误操作的风险。另外,基于GTID的同步可以忽略已经执行过的事务,减少了数据发生不一致的风险。

对于GTIDs,本篇就不做太多详细的介绍,其实现机制较为的复杂,推荐两篇个人认为对GTIDs介绍比较好的文章,当然,最推荐的还是MySQL的官方文档。

与MySQL传统复制相比,GTID有哪些独特的复制姿势?

https://dbaplus.cn/news-11-857-1.html

MySQL5.7杀手级新特性:GTID原理与实战

https://keithlan.github.io/2016/06/23/gtid/

MySQL GTID 简介

https://jin-yang.github.io/post/mysql-gtid.html

MySQL官方文档:Replication with Global Transaction Identifiers

https://dev.mysql.com/doc/refman/8.0/en/replication-gtids.html

MySQL同步模式

在MySQL数据同步中,核心的同步模式有两种。

SBR(Statement Based Replication)模式

基于SQL语句的同步的SBR(statement based replication)模式,该种模式下,当主库发生数据变更时,只将变更的SQL语句写入binlog日志中,同步给从库。

主要优点:

  • binlog记录的数据量较小,占用磁盘空间小
  • 需要同步的消息小,带宽占用少
  • 方便审计,binlog中记录的就是原始的SQL请求

主要缺点:

  • 一些SQL会导致主备不一致,例如“INSERT … SELECT with no ORDER BY“SELECT返回行的顺序会不一致,如果有AUTO_INCREMENT列就会导致主备不一致
  • 依赖机器环境信息、存储过程或触发器的语句可能在主备上的结果不一致,例如依赖uuid()、now()等。
  • 相对Row Based的方式,Statement Based方式同步“INSERT … SELECT”类语句时会有大量的行级锁,而导致性能问题
RBR(Row Based Replication)模式

基于数据行同步的RBR(Row Based Replication)模式,该种模式下,当主库发生数据变更时,所有变更涉及到的数据行的变化,都会被写入binlog日志中,同步给从库。

主要优点:

  • 所有的写请求都能同步,不会出现主备不一致的情况
  • 锁粒度更小,并发度更高
  • 更新较少行的请求在从库上执行较快

主要缺点:

  • 更新非常多行的SQL会写大量的日志,占用磁盘资源,同步时又占用网络资源
  • 日志中没有原始的SQL请求,不利于审计

同时,也支持第三种模式,即混合模式MBR(mixed based replication),该种模式是基于上面两种模式的,MySQL会自动选择合适的同步模式进行数据同步。

在一般情况下,推荐使用基于行模式RBR(Row Based Replication)同步。

关于两种模式的优劣对比,可以参考此篇:

MySQL 语句复制(SBR)的缺陷列举

https://cloud.tencent.com/developer/article/1004542

MySQL同步实现细节概述

上面我们对MySQL的主从同步的机制进行了简要概述,那么,MySQL是如何去实现同步的?

MySQL数据同步线程模型

如上图所示,MySQL存在三种线程模型,用于主从之间的数据同步:

1、Binlog dump thread

当从库与主库建立一个连接时,主库中会创建出一个线程(Binlog dump thread),该线程用于当binlog日志的内容发生变化时,该线程会通知从库,并将相应的binlog内容发送给从库。

2、Slave I/O thread

当主从同步开启的时候,从库上会创建2个线程。

第一个就是I/O线程(Slave I/O thread),该线程连接到主库,主库上的binlog dump线程会将binlog的内容发送给该I/O线程。该I/O线程接收到binlog内容后,再将变更的内容写入到本地的relay log

3、Slave SQL thread

I/O线程将变更的内容写入到本地的relay log后,SQL线程(Slave SQL thread)会对relay log进行读取,并且根据relay log的内容对从库做相应的操作。

需要注意的是,当一个主库有多个从库时,在主库上会为每个从库都创建一个Binlog dump thread,而每个从库都会创建属于自己的I/O threadSQL thread

MySQL同步线程模型

结语

本篇,我们对MySQL的主从同步机制进行了简要了解,总结一下,MySQL的主从同步,核心是基于binlog日志文件进行数据同步的,支持丰富的同步方式与模式 。本篇我仅对主从同步进行了简要的概述,对每个细节点并没有深入的展开介绍,希望您看过本篇,可以对MySQL的主从同步有一个大体的了解,而然后再对具体的实现细节进行深入理解,做到深入浅出。

更多精彩文章, 请关注我的个人公众号:老宣说
让我们一起共同学习成长!
感谢您的支持!
老宣说公众号地址

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值