主从复制原理
- 当 master 节点接收到一个写请求时,这个写请求可能是增删改操作,此时会把写请求的更新操作都记录到 binlog 日志中。
- master 节点会把数据复制给 slave 节点,这个过程,需要每个 slave 节点连接到 master 节点上,master 节点就会为每一个 slave 节点分别创建一个
binlog dump
线程,用于向各个 slave 节点发送 binlog 日志。 binlog dump
线程会读取 master 节点上的 binlog 日志,然后将 binlog 日志发送给 slave 节点上的I/O
线程。当主库读取事件的时候,会在 binlog 上加锁,读取完成之后,再将锁释放掉。- slave 节点上的
I/O
线程接收到 binlog 日志后,会将 binlog 日志先写入到本地的 relaylog 中,relaylog 中就保存了 binlog 日志。 - slave 节点上的
SQL
线程,会来读取 relaylog 中的 binlog 日志,将其解析成具体的增删改操作,把这些在 master 节点上进行过的操作,重新在 slave 节点上也重做一遍,达到数据还原的效果,这样就可以保证 master 节点和 slave 节点的数据一致性了。
过程中 binlog 和 relay log 都是 顺序读写
。
主从同步的数据内容其实是二进制日志(Binlog),存储的是一个又一个的事件(Event),这些事件分别对应着数据库的更新操作,比如 INSERT、UPDATE、DELETE 等。
另外我们还需要注意的是,不是所有版本的 MySQL 都默认开启了服务器的二进制日志,在进行主从同步的时候,我们需要先检查服务器是否已经开启了二进制日志。
二进制日志,它是一个文件,在进行网络传输的过程中就一定会存在一些延迟,比如200ms,这样就可能造成用户在从库上读取的数据不是最新的数据,也就会造成主从同步中的数据不一致的情况发生。比如我们对一条记录进行更新,这个操作是在主库上完成的,而在很短的时间内,比如100ms,又对同一个记录进行读取,这时候从库还没有完成数据的同步,那么,我们通过从库读取到的数据就是一条旧的数据。这时候就要了解数据复制方式了。
全同步复制
全同步复制,就是当主库执行完一个事务之后,要求所有的从库也都必须执行完该事务,才可以返回处理结果给客户端。因此,虽然全同步复制数据一致性得到保证了,但是主库完成一个事务需要等待所有从库也完成,性能会比较低。
异步复制
异步复制,就是当主库提交事务后,会通知 binlog dump
线程发送 binlog 日志给从库,一旦 binlog dump
线程将 binlog 日志发送给从库之后,不需要等到从库也同步完成事务,主库就会将处理结果返回给客户端。
因为主库只管自己执行完事务,就可以将处理结果返回给客户端,而不用关心从库是否执行完事务,这就可能导致短暂的主从数据不一致的问题了,比如刚在主库插入的新数据,如果马上在从库查询,就可能查询不到。
而且,当主库提交事物后,如果宕机挂掉了,此时可能 binlog 还没来得及同步给从库,这时候如果为了恢复故障切换主从节点的话,就会出现数据丢失的问题,所以异步复制虽然性能高,但数据一致性上是最弱的。
MySQL 主从复制,默认采用的复制策略就是异步复制。
半同步复制
MySQL 5.5版本之后开始支持半同步复制的方式。原理是在客户端提交事务之后不直接将结果返回给客户端,而是等待至少有一个从库收到了 Binlog,并且写入到中继日志中,再返回给客户端。这样做的好处就是提高了数据的一致性,当然相比于异步复制来说,至少多增加了一个网络连接的延迟,降低了主库写的效率。
增强半同步复制
增强半同步复制,是 MySQL 5.7.2后的版本对半同步复制做的一个改进,原理上几乎是一样的,主要是解决幻读的问题。主库配置了参数 rpl_semi_sync_master_wait_point = AFTER_SYNC 后,主库在存储引擎提交事务前,必须先收到从库数据同步完成的确认信息后,才能提交事务,以此来解决幻读问题。
总结
实际项目中具体问题具体分析,数据库优化 可以先从 SQL 优化,索引优化以及 Redis 缓存等方面来考虑,然后再考虑是否采用主从架构实现 读写分离。