MySQL 主从复制简介
实现数据库主从复制是实现读写分离,提高吞吐量的好办法,下面介绍一下 MySQL 主从复制
前言
说到主从复制,一个最朴素的想法应该是手动将主库倒一个备份出来,然后将这个备份写入到从库中,这样便让主库和从库有了同样的数据,实现了主从复制。但不用我说,你也肯定知道,这会让主库停机,因为在整个过程中,如果主库的内容有变化,我们导出的这份备份就没用了。而且还有一点特别重要,这种操作是全量的,也就说如果之后主库的内容有变化,我们是无法及时的将变化的部分导入到从库,只能再停机,重复上面的操作,这显然不行。
要解决这个问题其实也不难,我们在每条数据上加一个时间戳,这样就能区分出哪些数据是新的,用一个程序隔一段时间去主库上把新的数据给捞出来写入从库。通过这种方法,我们确实实现了一个简单的主从复制,但这无疑会急剧增加主库的负担,因为这种方法需要频繁的到主库去执行 SQL 操作。
其实 MySQL 中已经自带了主从复制的功能,而且还不会增加主库的负担,下面就简单介绍一下 MySQL 自带的主从复制是如何工作的。
MySQL 主从复制核心原理
我们都知道,MySQL 为了实现事务等 redo / undu 功能,需要将执行的每条 SQL 语句都写入日志。要想实现主从复制的功能,肯定需要一个方法获得数据库中的新数据,这样才能实现增量复制。既然直接去数据库中捞太费资源,那么可以直接从这些日志下手,因为从库去读取日志是不会影响主库的性能的,MySQL 主从复制的基本思想也是这样。
在 MySQL 中,主从复制的核心原理就是基于 log 文件:
- 主库执行完 SQL 操作后,将其写入 binlog
- 从库连接上主库后,从 binlog 中读取主库执行的操作,将其写入从库的 relay log
- 从库读取 relay log,将其中的操作写入从库
这样,就实现了主从复制
从图中可以看出,从库使用了多个线程来执行同步操作
- dump 线程读取主库 binlog ,将其发送到从库
- I/O 线程将发送过来的数据写入从库的 relay log
- SQL 将 relay log 中的操作写入数据库
使用 relay log 的目的是为了防止 SQL 语句执行起来太慢,导致从库跟不上主库的进度,这时如果主库宕机,会导致大量数据丢失。因此使用单独的线程先尽量把主库的 binlog 搬运过来,再让 SQL 线程慢慢执行其中的操作,可以最大程度地保证不丢数据。
MySQL 主从复制分类
异步复制
异步复制基本就是刚才所说的原理,它是 MySQL 中最早出现的复制方式
从图中可以看出,异步复制没有提供任何确认机制,主库并不知道从库的进度,如果有网络故障发生,它不能保证数据的一致性
还有一点需要说明,在之前提到的那个不成熟的方法中,我们用在数据中放置时间戳的方式来区分哪些是新的数据,只要某条数据的时间戳比当前已经同步的时间戳更晚,那这条数据就是新数据。尽管在 MySQL 的主从复制中,读取的是 binlog,但也需要有一种方式标记哪些是新的 binlog,MySQL 提供了两种方式:
- 一种是需要我们指定具体的 log 文件与位置
- 另一种是通过一种全局事务 ID -> GTID 来自动找到具体位置,用起来比较方便
全同步复制
其实 MySQL 并没有全同步复制的技术,我写这个只是想说,如果有一种方式让主库能在提交事务之前,确认一下所有的从库都跟上了自己的进度,不就能保证即使主库宕机,从库也不会丢失数据了吗?
这样的确能保证数据的一致性,但是如果从库往往有好几个,如果主库每次执行事务都必须得到所有的从库确认,这太慢了,那么多从库肯定有一个两个出了点网络抖动或者其他什么问题。
MySQL 实际上采用了一种折中的办法:半同步复制
半同步复制
从图中可以看出,在半同步复制中,主库在执行完一个任务后,只要得到任意一个从库的回应,它就将该事务提交。可见这种方法平衡了数据一致性和速度这两个需求。
组复制
在较新版本的 MySQL 中,还提供了一种叫做「组复制」的技术,这种技术基于一种分布式协议来保证数据一致性
这种技术主要是提高容错性,当组内有成员出现故障时,只要不是全部或大多数组成员(组内超过半数的成员)出现故障,则系统仍然可用。
结语
如果你想动手搭建自己的 MySQL 主从复制的话,可以看看我的其他文章
参考链接
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!