solidSpoon / solidSpoon.github.io.old

欢迎来到 Hide 博客!这里是 solidSpoon 的个人空间,分享技术心得、生活点滴和有趣事物。
https://solidspoon.xyz
0 stars 0 forks source link

MySQL 主从复制简介 #30

Closed solidSpoon closed 3 years ago

solidSpoon commented 3 years ago

实现数据库主从复制是实现读写分离,提高吞吐量的好办法,下面介绍一下 MySQL 主从复制

前言

说到主从复制,一个最朴素的想法应该是手动将主库倒一个备份出来,然后将这个备份写入到从库中,这样便让主库和从库有了同样的数据,实现了主从复制。但不用我说,你也肯定知道,这会让主库停机,因为在整个过程中,如果主库的内容有变化,我们导出的这份备份就没用了。而且还有一点特别重要,这种操作是全量的,也就说如果之后主库的内容有变化,我们是无法及时的将变化的部分导入到从库,只能再停机,重复上面的操作,这显然不行。

要解决这个问题其实也不难,我们在每条数据上加一个时间戳,这样就能区分出哪些数据是新的,用一个程序隔一段时间去主库上把新的数据给捞出来写入从库。通过这种方法,我们确实实现了一个简单的主从复制,但这无疑会急剧增加主库的负担,因为这种方法需要频繁的到主库去执行 SQL 操作。

其实 MySQL 中已经自带了主从复制的功能,而且还不会增加主库的负担,下面就简单介绍一下 MySQL 自带的主从复制是如何工作的。

MySQL 主从复制核心原理

我们都知道,MySQL 为了实现事务等 redo / undu 功能,需要将执行的每条 SQL 语句都写入日志。要想实现主从复制的功能,肯定需要一个方法获得数据库中的新数据,这样才能实现增量复制。既然直接去数据库中捞太费资源,那么可以直接从这些日志下手,因为从库去读取日志是不会影响主库的性能的,MySQL 主从复制的基本思想也是这样。

在 MySQL 中,主从复制的核心原理就是基于 log 文件:

这样,就实现了主从复制

image

从图中可以看出,从库使用了多个线程来执行同步操作

使用 relay log 的目的是为了防止 SQL 语句执行起来太慢,导致从库跟不上主库的进度,这时如果主库宕机,会导致大量数据丢失。因此使用单独的线程先尽量把主库的 binlog 搬运过来,再让 SQL 线程慢慢执行其中的操作,可以最大程度地保证不丢数据。

MySQL 主从复制分类

异步复制

异步复制基本就是刚才所说的原理,它是 MySQL 中最早出现的复制方式

image

从图中可以看出,异步复制没有提供任何确认机制,主库并不知道从库的进度,如果有网络故障发生,它不能保证数据的一致性

还有一点需要说明,在之前提到的那个不成熟的方法中,我们用在数据中放置时间戳的方式来区分哪些是新的数据,只要某条数据的时间戳比当前已经同步的时间戳更晚,那这条数据就是新数据。尽管在 MySQL 的主从复制中,读取的是 binlog,但也需要有一种方式标记哪些是新的 binlog,MySQL 提供了两种方式:

全同步复制

其实 MySQL 并没有全同步复制的技术,我写这个只是想说,如果有一种方式让主库能在提交事务之前,确认一下所有的从库都跟上了自己的进度,不就能保证即使主库宕机,从库也不会丢失数据了吗?

这样的确能保证数据的一致性,但是如果从库往往有好几个,如果主库每次执行事务都必须得到所有的从库确认,这太慢了,那么多从库肯定有一个两个出了点网络抖动或者其他什么问题。

MySQL 实际上采用了一种折中的办法:半同步复制

半同步复制

image

从图中可以看出,在半同步复制中,主库在执行完一个任务后,只要得到任意一个从库的回应,它就将该事务提交。可见这种方法平衡了数据一致性和速度这两个需求。

组复制

在较新版本的 MySQL 中,还提供了一种叫做「组复制」的技术,这种技术基于一种分布式协议来保证数据一致性

image

这种技术主要是提高容错性,当组内有成员出现故障时,只要不是全部或大多数组成员(组内超过半数的成员)出现故障,则系统仍然可用。

结语

如果你想动手搭建自己的 MySQL 主从复制的话,可以看看我的其他文章


参考链接