闲聊MySQL:浅析主从同步
Posted 老宣说
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了闲聊MySQL:浅析主从同步相关的知识,希望对你有一定的参考价值。
写在前面
本篇是2019年的最后一篇文章,这一年磕磕绊绊走过来,在此想特别感谢@文凯@云凯@春意以及身边的小伙们,这一年来给与了我许多的支持与帮助,让我一直坚持下来。
前言
本篇是本系列文章的最后一篇,在前面的系列文章中,
我们对mysql内部组成结构、索引结构、查询解析等进行了分析与了解,本篇,作为本系列文章的终篇,我们来聊聊MySQL中比较重要的一个机制,数据同步机制,也就是我们常说的,主从同步。
本篇基于MySQL 8.x版本。
Replication Between Master and Slave
一说到MySQL的主从同步,你的脑海中肯定第一反应会是binlog
,没有错,我们日常开发中较为场景的主从同步模式,就是基于MySQL的binlog
日志来进行的,但是您可能之前并没有接触过主从同步的场景或者说对这里不太了解,那么我们把问题拉回原点,什么是MySQL的主从同步?
MySQL主从同步机制
MySQL的数据同步机制可以将数据从一个主数据库同步到另一个或多个从数据库,即Master-Slaves
模式,默认的话,同步的过程是异步进行的;从节点不需要与主节点建立永久型的连接。可以通过配置,你可以选择复制全部的数据库或者指定的数据库,亦或者是指定的某个数据库中的某些表。
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
端开启binlog
,Master
把它的二进制日志传递给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存在三种线程模型,用于主从之间的数据同步:
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 thread
与SQL thread
。
结语
本篇,我们对MySQL的主从同步机制进行了简要了解,总结一下,MySQL的主从同步,核心是基于binlog
日志文件进行数据同步的,支持丰富的同步方式与模式 。本篇我仅对主从同步进行了简要的概述,对每个细节点并没有深入的展开介绍,希望您看过本篇,可以对MySQL的主从同步有一个大体的了解,而然后再对具体的实现细节进行深入理解,做到深入浅出。
以上是关于闲聊MySQL:浅析主从同步的主要内容,如果未能解决你的问题,请参考以下文章