主从同步的原理是怎样的
提到主从同步的原理,我们就需要了解在数据库中的一个重要日志文件,那就是 Binlog 二
进制日志,它记录了对数据库进行更新的事件。实际上主从同步的原理就是基于 Binlog 进
行数据同步的。在主从复制过程中,会基于 3 个线程来操作,一个主库线程,两个从库线
程。
二进制日志转储线程(Binlog dump thread)是一个主库线程。当从库线程连接的时候,
主库可以将二进制日志发送给从库,当主库读取事件的时候,会在 Binlog 上加锁,读取完
成之后,再将锁释放掉。
从库 I/O 线程会连接到主库,向主库发送请求更新 Binlog。这时从库的 I/O 线程就可以读
取到主库的二进制日志转储线程发送的 Binlog 更新部分,并且拷贝到本地形成中继日志
(Relay log)。
从库 SQL 线程会读取从库中的中继日志,并且执行日志中的事件,从而将从库中的数据与
主库保持同步。
所以你能看到主从同步的内容就是二进制日志(Binlog),它虽然叫二进制日志,实际上
存储的是一个又一个事件(Event),这些事件分别对应着数据库的更新操作,比如
INSERT、UPDATE、DELETE 等。另外我们还需要注意的是,不是所有版本的 MySQL 都
默认开启服务器的二进制日志,在进行主从同步的时候,我们需要先检查服务器是否已经开
启了二进制日志。进行主从同步的内容是二进制日志,它是一个文件,在进行网络传输的过程中就一定会存在
延迟(比如 500ms),这样就可能造成用户在从库上读取的数据不是最新的数据,也就是
主从同步中的数据不一致性问题。比如我们对一条记录进行更新,这个操作是在主库上完成
的,而在很短的时间内(比如 100ms)又对同一个记录进行了读取,这时候从库还没有完
成数据的更新,那么我们通过从库读到的数据就是一条旧的记录。
这种情况下该怎么办呢?
如何解决主从同步的数据一致性问题
可以想象下,如果我们想要操作的数据都存储在同一个数据库中,那么对数据进行更新的时
候,可以对记录加写锁,这样在读取的时候就不会发生数据不一致的情况,但这时从库的作
用就是备份,并没有起到读写分离,分担主库读压力的作用。
因此我们还需要继续想办法,在进行读写分离的同时,解决主从同步中数据不一致的问题,
也就是解决主从之间数据复制方式的问题,如果按照数据一致性从弱到强来进行划分,有以
下 3 种复制方式。
方法 1:异步复制
异步模式就是客户端提交 COMMIT 之后不需要等从库返回任何结果,而是直接将结果返回
给客户端,这样做的好处是不会影响主库写的效率,但可能会存在主库宕机,而 Binlog 还
没有同步到从库的情况,也就是此时的主库和从库数据不一致。这时候从从库中选择一个作
为新主,那么新主则可能缺少原来主服务器中已提交的事务。所以,这种复制模式下的数据
一致性是最弱的。
方法 2:半同步复制
MySQL5.5 版本之后开始支持半同步复制的方式。原理是在客户端提交 COMMIT 之后不
直接将结果返回给客户端,而是等待至少有一个从库接收到了 Binlog,并且写入到中继日
志中,再返回给客户端。这样做的好处就是提高了数据的一致性,当然相比于异步复制来
说,至少多增加了一个网络连接的延迟,降低了主库写的效率。
在 MySQL5.7 版本中还增加了一个
rpl_semi_sync_master_wait_for_slave_count参数,我们可以对应答的从库数量
进行设置,默认为 1,也就是说只要有 1 个从库进行了响应,就可以返回给客户端。如果
将这个参数调大,可以提升数据一致性的强度,但也会增加主库等待从库响应的时间。
方法 3:组复制
组复制技术,简称 MGR(MySQL Group Replication)。是 MySQL 在 5.7.17 版本中推
出的一种新的数据复制技术,这种复制技术是基于 Paxos 协议的状态机复制。
我刚才介绍的异步复制和半同步复制都无法最终保证数据的一致性问题,半同步复制是通过
判断从库响应的个数来决定是否返回给客户端,虽然数据一致性相比于异步复制有提升,但
仍然无法满足对数据一致性要求高的场景,比如金融领域。MGR 很好地弥补了这两种复制
模式的不足。
下面我们来看下 MGR 是如何工作的(如下图所示)。
首先我们将多个节点共同组成一个复制组,在执行读写(RW)事务的时候,需要通过一致
性协议层(Consensus 层)的同意,也就是读写事务想要进行提交,必须要经过组里“大
多数人”(对应 Node 节点)的同意,大多数指的是同意的节点数量需要大于
(N/2+1),这样才可以进行提交,而不是原发起方一个说了算。而针对只读(RO)事务
则不需要经过组内同意,直接 COMMIT 即可。
在一个复制组内有多个节点组成,它们各自维护了自己的数据副本,并且在一致性协议层实
现了原子消息和全局有序消息,从而保证组内数据的一致性。
MGR 将 MySQL 带入了数据强一致性的时代,是一个划时代的创新,其中一个重要的原因
就是 MGR 是基于 Paxos 协议的。Paxos 算法是由 2013 年的图灵奖获得者 Leslie
Lamport 于 1990 年提出的,有关这个算法的决策机制你可以去网上搜一下。或者点击
这里查看具体的算法,另外作者在 2001 年发布了一篇简化版的文章,你如果感兴趣的
话,也可以看下。
事实上,Paxos 算法提出来之后就作为分布式一致性算法被广泛应用,比如 Apache 的
ZooKeeper 也是基于 Paxos 实现的。