# 9. 主从复制怎么做到的

## 主从复制的原理

![](https://3064259429-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MC_ucxnzAClkrgsGdFP%2Fsync%2F8263fb8afa7f1c994c2fa063394186ea52eaeb97.png?generation=1597936087628371\&alt=media)

上图有一个主节点以及一个从节点, 主节点要做的事情非常简单, 只要将自己的写操作记录&#x5230;***Binary Log***&#x91CC;面即可, 从节点需要有两个线程, 来完成两件事:

* 一个IO线程, 负责到主节点里拉binlog来, 拉过来的binlog本质上是一个个的sql语句, 先暂时存到自己&#x7684;***Relay Log***&#x91CC;去
* 另一个SQL线程, 负责从RelayLog里把SQL语句取出来并执行, 主节点的所有写操作在从节点中都能被执行到, 从而保证了主从的一致性

## 主从复制潜在的问题

如果仔细想想就会觉得这其中有问题, 主从同步总是有时间差的, 有没有可能主节点都已经commit了, 但是从节点都还没收到这条消息? 这样搞下去延迟都是小事, 但如果主节点永久性的crash了, 是不是说从节点永远都不会有这条记录了? 即使它已经commit了?

这种主从一致性的问题, 于是我们想到了raft协议, 在raft里只有半数以上的从节点ACK(日志已记录)了, 这条消息才能被commit了, 我们有没有办法把这种思路也给带过来呢?

![](https://3064259429-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MC_ucxnzAClkrgsGdFP%2Fsync%2F8d74cf86a1e5bad1181f0db7140ca4d51f89bb1c.png?generation=1597936086911725\&alt=media)

我们现在要求主节点commit之前必须要求, 大家都要执行这条记录才行, 这种方法叫做半同步复制, 稳吗? 比以前稳, 但还不够稳

1. 所有的从节点都已经同步过binlog了 - 半同步模式
2. 只要有一个从节点复制过binglog就行 - 全同步模式

## 全ACK还不稳?

MySQL的commit叫二段式提交, 在你点击提交这个按钮以后, 先记录binlog, 然后再到引擎层提交事务(二段). 正常情况下一切都没有问题, 但主机宕机了, 重启后就会进入恢复阶段, 先读取redolog发现这个事务没提交, 那这个事务应该回滚吗? 不确定先挂着, 看看binlog, 只要binlog里存在那么就认为要提交.

再回头看看这种提交方式带来的问题, 假设主机现在准备提交, 按照**半同步复制的要求**, 我们记录binlog并同步给从节点, 然而还没同步就挂了, 那么备机的relaylog里是没有这个事务的. 然后备机成为主机, 在原主机恢复以后就会检查自己的binlog, 发现有, 然后就要执行, 这一执行就会直接导致主从数据永久的不一致, 非常的蛋疼!!

## 那么有没有什么办法呢

也是有的, 这里面唯一的问题就是主从的binlog没有同步搞出来的, 我听说阿里搞出了一个"MySQL金融版", 在一个节点加入集群之前, 通过raft协议同步集群内的binlog, 这样就可以避免以上的问题
