一、主从复制架构概述
不论任何技术栈,但凡一提高可用、高性能、高稳定这些词汇,必然会牵扯到集群、主从架构的概念,如MQ、Redis、ES、MongoDB、Zookeeper.....
任何技术栈中都会有,而MySQL
中同样不例外,官方也提供了主从架构的支持,通过调整多个MySQL
节点的配置信息,即可将一个节点的数据同步给另一个或多个节点,但这种方式同步的是所有数据!
有人也许会疑惑:为什么要同步所有数据呀?难道不能对数据作分片,不同的节点同步不同的数据嘛?这实际上属于历史遗留性的问题,在早些年由于分布式技术还未完善,所以大多技术栈在设计高可用方案时,基本上都选用主从架构,也就是各节点之间都同步所有数据,从而对外提供高可用的保障。
主从架构中必须有一个主节点,以及一个或多个从节点,所有的数据都会先写入到主,接着其他从节点会复制主节点上的增量数据,从而保证数据的最终一致性,使用主从复制方案,可以进一步提升数据库的可用性和性能:
- ①在主节点宕机或故障的情况下,从节点能自动切换成主节点的身份,从而继续对外提供服务。
- ②提供数据备份的功能,当主节点的数据发生损坏时,从节点中依旧保存着完整数据。
- ③可以基于主从实现读写分离,主节点负责处理写请求,从节点处理读请求,进一步提升性能。
但无论任何技术栈的主从架构,都会存在致命硬伤,同时也会存在些许问题需要解决:
- ①硬伤:木桶效应,一个主从集群中所有节点的容量,受限于存储容量最低的哪台服务器。
- ②数据一致性问题:由于同步复制数据的过程是基于网络传输完成的,所以存储延迟性。
- ③脑裂问题:从节点会通过心跳机制,发送网络包来判断主机是否存活,网络故障情况下会产生多主。
上述提到的三个问题中,第一个问题只能靠加大服务器的硬件配置解决,第二个问题相对来说已经有了很好的解决方案(后续讲解),第三个问题则是部署方式决定的,如果将所有节点都部署在同一网段,基本上不会出现集群脑裂问题。
上面简单了解了主从复制架构的一些基本概念后,接着来聊一聊MySQL
中的主从复制。
二、MySQL中的主从复制技术
MySQL
本身提供了主从复制的技术支持,所以无需通过第三方技术来协助实现,MySQL
数据复制的过程就是基于该日志完成的,但MySQL
复制数据的过程并非同步,而是异步的方式,啥是同步、异步方式呢?如下:
上图中,上面是同步复制的过程,也就是当主节点接收到一个客户端的写请求后,先会往自身写入数据,接着会去要求其他从节点也写入数据,当从节点的数据写入完成后,最终才会向客户端返回写入成功。
而异步复制的过程恰恰相反,当主节点接收到一个客户端的写请求后,先会往自身写入数据,自身数据写入成功后,就会立马向客户端返回写入成功的信息,对于从节点的数据,会在其他的时间内再异步复制过去。
对比同步复制和异步复制的过程,显然同步复制的过程极其影响效率,因为需要等到所有从节点写完之后才返回数据。而异步复制的过程则快很多了,基本和MySQL
单机版的写入效率差距不大,只要主节点自身写入成功,则立马返回写入成功,性能自然会快很多,而MySQL
主从的数据复制,就是基于这种异步方案实现。
有人也许会好奇:同步复制方案效率那么低,一般没有谁用吧?实则不然,比如大名鼎鼎的
Zookeeper
中,就采用的是同步复制方案,这是为什么呢?因为同步复制方案能够确保数据100%
不丢失,和数据的强一致性。如果采用异步复制方案,那么当一个数据写入后,主节点立马宕机或故障了,从机顶替上线,这时的从机是不一定有最新数据的,而同步方案则不需要担心这个问题(Zookeeper
采用的是半同步模式,后续再展开细聊~)。
2.1、MySQL数据同步的原理
前面搞清楚了MySQL
同步数据的方式,接着聊一聊它的同步原理,前面简单提到过一句:MySQL
是基于它自身的Bin-log
日志来完成数据的异步复制,因为Bin-log
日志中会记录所有对数据库产生变更的语句,包括DML
数据变更和DDL
结构变更语句,数据的同步过程如下:
上述即是主从同步数据的原理图,但在讲解之前先来了解一下两种数据同步的方式:
- 主节点推送:当主节点出现数据变更时,主动向自身注册的所有从节点推送新数据写入。
- 从节点拉取:从节点定期去询问一次主节点是否有数据更新,有则拉取新数据写入。
那MySQL
究竟采用的是什么方式呢?其实是「从拉」的方案,但对其稍微做了一些优化,传统的「从拉」方案是需要从节点一直与主节点保持长连接,从节点定时或持续性的对主节点做轮询,查看主机的数据是否发生了变更,而MySQL
的数据同步原理如下:
- ①客户端将写入数据的需求交给主节点,主节点先向自身写入数据。
- ②数据写入完成后,紧接着会再去记录一份
Bin-log
二进制日志。 - ③配置主从架构后,主节点上会创建一条专门监听
Bin-log
日志的log dump
线程。 - ④当
log dump
线程监听到日志发生变更时,会通知从节点来拉取数据。 - ⑤从节点会有专门的
I/O
线程用于等待主节点的通知,当收到通知时会去请求一定范围的数据。 - ⑥当从节点在主节点上请求到一定数据后,接着会将得到的数据写入到
relay-log
中继日志。 - ⑦从节点上也会有专门负责监听
relay-log
变更的SQL
线程,当日志出现变更时会开始工作。 - ⑧中继日志出现变更后,接着会从中读取日志记录,然后解析日志并将数据写入到自身磁盘中。
阅读上述流程后,相信大家能感受出MySQL
主从复制时做的优化,在主从数据同步的过程中,从节点并不会无限制的询问主机,这样实在太影响效率了,在MySQL
中引入了惰性的思想,只有当主节点真正出现数据变更时,才会通知从节点拉取数据!
2.2、从节点拉取的数据到底是什么格式?
前面从整体角度出发,简单讲述了主从同步数据的过程,但从节点复制的数据到底是什么格式的呢?这里要根据主节点的Bin-log
日志格式来决定,它会有三种格式,如下:
Statment
:记录每一条会对数据库产生变更操作的SQL
语句(默认格式)。Row
:记录具体出现变更的数据(也会包含数据所在的分区以及所位于的数据页)。Mixed
:Statment、Row
的结合版,可复制的记录SQL
语句,不可复制的记录具体数据。
一般在搭建主从架构时&#x