MySQL 主从复制 —— 全同步复制、异步复制、半同步复制

2,202 阅读4分钟

主从复制原理

MySQL 主从复制.png

  1. 当 master 节点接收到一个写请求时,这个写请求可能是增删改操作,此时会把写请求的更新操作都记录到 binlog 日志中。
  2. master 节点会把数据复制给 slave 节点,这个过程,需要每个 slave 节点连接到 master 节点上,master 节点就会为每一个 slave 节点分别创建一个 binlog dump 线程,用于向各个 slave 节点发送 binlog 日志。
  3. binlog dump 线程会读取 master 节点上的 binlog 日志,然后将 binlog 日志发送给 slave 节点上的 I/O 线程。当主库读取事件的时候,会在 binlog 上加锁,读取完成之后,再将锁释放掉。
  4. slave 节点上的 I/O 线程接收到 binlog 日志后,会将 binlog 日志先写入到本地的 relaylog 中,relaylog 中就保存了 binlog 日志。
  5. slave 节点上的 SQL 线程,会来读取 relaylog 中的 binlog 日志,将其解析成具体的增删改操作,把这些在 master 节点上进行过的操作,重新在 slave 节点上也重做一遍,达到数据还原的效果,这样就可以保证 master 节点和 slave 节点的数据一致性了。

过程中 binlog 和 relay log 都是 顺序读写

主从同步的数据内容其实是二进制日志(Binlog),存储的是一个又一个的事件(Event),这些事件分别对应着数据库的更新操作,比如 INSERT、UPDATE、DELETE 等。

另外我们还需要注意的是,不是所有版本的 MySQL 都默认开启了服务器的二进制日志,在进行主从同步的时候,我们需要先检查服务器是否已经开启了二进制日志。

二进制日志,它是一个文件,在进行网络传输的过程中就一定会存在一些延迟,比如200ms,这样就可能造成用户在从库上读取的数据不是最新的数据,也就会造成主从同步中的数据不一致的情况发生。比如我们对一条记录进行更新,这个操作是在主库上完成的,而在很短的时间内,比如100ms,又对同一个记录进行读取,这时候从库还没有完成数据的同步,那么,我们通过从库读取到的数据就是一条旧的数据。这时候就要了解数据复制方式了。

全同步复制

MySQL 全同步复制.png

全同步复制,就是当主库执行完一个事务之后,要求所有的从库也都必须执行完该事务,才可以返回处理结果给客户端。因此,虽然全同步复制数据一致性得到保证了,但是主库完成一个事务需要等待所有从库也完成,性能会比较低。

异步复制

MySQL 异步复制.png

异步复制,就是当主库提交事务后,会通知 binlog dump 线程发送 binlog 日志给从库,一旦 binlog dump 线程将 binlog 日志发送给从库之后,不需要等到从库也同步完成事务,主库就会将处理结果返回给客户端。

因为主库只管自己执行完事务,就可以将处理结果返回给客户端,而不用关心从库是否执行完事务,这就可能导致短暂的主从数据不一致的问题了,比如刚在主库插入的新数据,如果马上在从库查询,就可能查询不到。

而且,当主库提交事物后,如果宕机挂掉了,此时可能 binlog 还没来得及同步给从库,这时候如果为了恢复故障切换主从节点的话,就会出现数据丢失的问题,所以异步复制虽然性能高,但数据一致性上是最弱的。

MySQL 主从复制,默认采用的复制策略就是异步复制。

半同步复制

MySQL 半同步复制.png

MySQL 5.5版本之后开始支持半同步复制的方式。原理是在客户端提交事务之后不直接将结果返回给客户端,而是等待至少有一个从库收到了 Binlog,并且写入到中继日志中,再返回给客户端。这样做的好处就是提高了数据的一致性,当然相比于异步复制来说,至少多增加了一个网络连接的延迟,降低了主库写的效率。

增强半同步复制

MySQL 增强半同步复制.png

增强半同步复制,是 MySQL 5.7.2后的版本对半同步复制做的一个改进,原理上几乎是一样的,主要是解决幻读的问题。主库配置了参数 rpl_semi_sync_master_wait_point = AFTER_SYNC 后,主库在存储引擎提交事务前,必须先收到从库数据同步完成的确认信息后,才能提交事务,以此来解决幻读问题。

总结

实际项目中具体问题具体分析,数据库优化 可以先从 SQL 优化,索引优化以及 Redis 缓存等方面来考虑,然后再考虑是否采用主从架构实现 读写分离