半万字长文学习 MySQL 主从复制原理,面试必问,建议收藏!

Posted 陆海潘江小C

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了半万字长文学习 MySQL 主从复制原理,面试必问,建议收藏!相关的知识,希望对你有一定的参考价值。


数据的复制作为高可用、可扩展和备份的基础,目前的各种数据库几乎都有复制这项功能,最终目的就是备份数据,以防数据丢失造成重大损失。

mysql的主从复制就是一个典型的方案,实现一个主库的数据复制到一个或多个备库,这个方案属于“水平扩展”的架构。

这篇文章将带大家学习整个MySQL主从复制的内容,比如现在你会提问:MySQL是怎么实现主从复制的?主从复制有什么用?怎么保证主库和备库的同步复制,数据一致性?如果出现网络延迟等原因,查询数据不一致怎么办?

这些问题也是在面试中经常会问到的,接下来会详细分析,完整清晰,建议收藏!

一、主从复制到底是啥

1、主库上把数据更新记录写进二进制日志(Binary Log),简称binlog
2、备库将主库的日志复制到自己的中继日志(Relay Log)中。
3、备库读取中继日志的事件。将其重放到备库数据之上。

1、一张图过程

下图是MySQL主从复制工作细节

  1. 首先,备库会启动一个I/O线程,跟主库建立一个普通的客户端连接,将主库的binlog复制到本地的中继日志。
  2. 然后主库启动一个binlog dump线程,读取主库上binlog事件,且不会对事件进行轮询。如果线程读取完最新的更新事件,则进入睡眠,直到主库发送信号量通知有新事件产生才被唤醒,备库I/O线程会将收到的事件记录到本地log。
  3. 备库SQL线程执行最后一步,读取Relay Log日志并执行数据更新。

主库上记录二进制日志,每次准备提交事务完成数据个更新之前,主库将数据更新事件写进binlog。

Mysql按事务提交的顺序而非每条语句的执行顺序记录binlog。完成记录后,主库告诉存储引擎可以提交事务。

复制架构实现了获取事件和重放事件的解耦,两个过程异步执行。也看得出,备库重放事件是SQL线程的单线程执行。

2、新的备库与主库同步方法

前面的整个主从复制过程,是假设主备库都是默认刚安装好的情况,两台服务器上的数据相同。而大多数情况,我们的主库是运行一段时间了,然后将一台新的服务器数据库跟主库进行同步。

这样,有3种方法来初始化新的备库。

1、从主库复制

2、从另一台备库克隆数据

3、使用最近一次备份启动备库

因为初始时主备库数据不同步,需要有3个条件使得主库和备库保持同步。

1、在某个时间点的主库的数据快照

2、主库当前二进制日志文件和获得数据快照时在该binlog中的偏移量,通过这两个坐标确定二进制日志文件的位置。

3、从快照时间到现在的binlog。

下面几种备份方式可以实现数据克隆。

  1. 冷备份
    关闭主库,把数据复制到备库,重启主库后,会使用新的binlog日志文件。缺点很明显,关闭主库,通常是实现高可用性,这种方案不推荐。
  2. 热备份
    仅仅使用MyISAM表时,可以在主库运行时使用mysqlhotcopyrsync来复制数据;
    只包含InnoDB表时,可以使用以下命令来转储主库数据并将其加载到备库。
mysqldump --single-transaction --all-databases --master-data = 1 --host = serverName | mysql --host = seeverName2

--single-transaction使得转储的数据是事务开始前的数据。

3.快照
根据二进制日志坐标,使用主库的快照来初始化备库,然后使用change master to指定二进制日志的坐标。

  1. 热备份工具Percona Xtrabackup
    使用开源工具也是比较好的选择,可以在不阻塞服务器的情况下克隆主库来建立备库。

3、复制配置

在主库上的binlog最重要的选项是sync_binlog = 1表示每次提交事务前会将日志同步到磁盘,保证崩溃时不会丢失数据。而在备库,设置为0来减少不必要的开销。

MySQL5.5可以选择控制崩溃时将事件刷新到磁盘,配置如下:

sync_master_info = 1
sync_relay_log = 1
sync_relay_log_info = 1

二、主从复制有什么用

1、数据备份

很明显,第一个想到的就是作数据备份,MySQL复制不会对带宽造成很大的压力。即使有网络延迟,复制工作仍然可以进行。

2、负载均衡

主从服务器都可以分摊读操作,在读密集型的应用,可以通过负载均衡将操作分布到不同服务器上。

3、高可用性和故障切换

复制能帮助避免MySQL单点失败,作为实现高可用的基础。

4、MySQL升级测试

使用一个高版本MySQL作为备库,保证升级全部数据库之前,查询能够在备库执行。

三、复制原理有2个

前面介绍了MySQL复制的大致过程,现在已经对复制由一个整体的理解,接下来就是具体内部实现复制的细节了。

复制主要由两种模式:基于语句的复制模式、基于行的复制模式;还有一个同时使用两种模式的混合模式。

我总结下来,不同的模式的原理和优缺点如下。

1、基于语句的复制:

binlog_format = statement

该模式下,主库会记录造成数据更改的语句,当备库读取并重放这些事件时,只需要把这些SQL再执行一遍

优点:实现简单,只需要简单记录和执行这些语句。二进制日志文件更加紧凑,占用较小带宽。

缺点:传输二进制日志时,额外要记录当前时间戳,但可能无法正确复制SQL。比如CURRENT_USER()函数、存储过程和触发器在使用该模式也会出现问题。备库更新只能串行。

2、基于行的复制:

binlog_format = row

该模式下会将实际数据记录在二进制日志中。

优点:无须重放更新主库数据的查询,可以更高效地复制数据,占用更少的CPU。

缺点: 做全表更新时,复制开销会很大,因为每一行数据都会被记录到二进制日志,文件非常庞大。并且会主库上记录日志和复制增加额外的负载,更慢的日志记录则会降低并发度。

3、Mysql权衡动态切换

binlog_format = mixed

默认使用基于语句的复制方式,如果语句无法正确复制,就切换基于行的复制模式。

以上模式通过设置会话级别的变量binlog_format来控制二进制日志格式。

4、statement和row模式的区别

1、基于row复制模式

存储过程、函数、触发器,都是将执行之后的数据行,传给slave。

2、在基于statement 的复制时,存储过程、函数、触发器可能会数据不一致的情况

存储过程和函数在定义时,有 确定性函数和非确定性函数的。比如uuid(),now()这些函数都是非确定性函数,因为它们每次执行的值是不确定的。

在master和slave上分别执行会导致数据不一致,所以在基于语句复制的环境中,函数都必须是确定性的。否则只能采用row复制格式。

四、Mysql主从同步延迟分析及解决方案

这就是开头所讲的如何保证主从复制数据的一致性。大多数情况,受网络延迟、服务器性能等影响,会存在一些不理想的情况。

1、主从复制存在的问题

  1. 主库宕机后,数据可能丢失;

  2. 主从同步延迟。

2、延迟原因

MySQL主库对所有DDL和DML产生的日志写进binlog,由于binlog是顺序写,所以效率很高。

而备库SQL线程复制都是单线程的操作,当主库的并发较高时,产生的DML数量超过slave的SQL Thread所能处理的速度,或者当slave中有大型query语句产生了锁等待那么延时就产生了。

原因总结为这几个:
Master负载过高、Slave负载过高、网络延迟、机器性能太低、MySQL配置不合理。

3、主从延时排查方法

通过监控show slave status 命令输出的Seconds_Behind_Master参数的值来判断:

  • NULL,表示io_thread或是sql_thread有任何一个发生故障;
  • 该值为零,表示主从复制良好;
  • 正值,表示主从已经出现延时,数字越大表示从库延迟越严重。

MySQL并没有内建的方法来比较两台服务器的数据是否相同。所以需要使用第三方工具Percona Toolkit,其中pt-table-checksum命令可以确认主备数据是否一致。

其工作原理就是在主库执行insert ... select查询,将结果插入一个表,传递到备库,备库执行一遍后将结果进行比较,这种方法能够与复制工作同时进行。

pt-table-checksum --replicate = test.checksum <master_host>

4、解决方案

  1. 半同步复制

从MySQL5.5开始,MySQL已经支持半同步复制了,半同步复制介于异步复制和同步复制之间,主库在执行完事务后不立刻返回结果给客户端,需要等待至少一个从库接收到并写到relay log中才返回结果给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一个TCP/IP往返耗时的延迟。

  1. 主库配置sync_binlog = 1innodb_flush_log_at_trx_commit = 1

sync_binlog的默认值是0,MySQL不会将binlog同步到磁盘,其值表示每写多少binlog同步一次磁盘。备库配置值为零。

innodb_flush_log_at_trx_commit = 1表示每一次事务提交或事务外的指令都需要把日志flush到磁盘。

注意:将以上两个值同时设置为1时,写入性能会受到一定限制,只有对数据安全性要求很高的场景才建议使用,比如涉及到钱的订单支付业务,而且系统I/O能力必须可以支撑!

另外,还有几个方法。

  1. 优化网络
  2. 升级Slave硬件配置
  3. 升级MySQL版本到5.7,使用并行复制

五、总结

本文主要介绍了MySQL主从复制,认真看完这篇文章将会对主从复制有一个比较系统的理解,其他数据库相关原理也是类似架构,这篇作为基础可以掌握,复制原理基础知识已经完全足够。

MySQL是怎么实现主从复制的?主从复制有什么用?怎么保证主库和备库的同步复制,数据一致性?如果出现网络延迟等原因,查询数据不一致怎么办?

这些问题是否能回答了呢?
欢迎大佬们讨论指点~
那本篇文章就介绍到这里了,面试必问系列,记得收藏~


本篇内容首发我的CSDN博客:半万字长文学习《MySQL》主从复制原理,面试必问,建议收藏

以上是关于半万字长文学习 MySQL 主从复制原理,面试必问,建议收藏!的主要内容,如果未能解决你的问题,请参考以下文章

⭐Redis分布式——主从复制Sentinel集群彻底吃透⭐(看完这篇万字长文,你的Redis水平将会上升一个层次)

⭐Redis分布式——主从复制Sentinel集群彻底吃透⭐(看完这篇万字长文,你的Redis水平将会上升一个层次)

「mysql优化专题」主从复制面试宝典!面试官都没你懂得多!(11)

万字长文!全网最全最细MySQL sql语句大全(建议收藏)

❤️BitmapsHyperLogLogGeospatial❤️——Redis三大特殊数据类型详述(万字长文原理讲解,大厂面试高频知识点,一文尽收囊中)

万字长文,最常问的MySQL面试题集合