随着业务的增加,如果单单靠一台服务器的话,负载过重,就容易造成宕机。

这样我们保存在 MySQL 数据库的数据就会丢失,那么该怎么解决呢?

其实在 MySQL 本身就自带有一个主从复制的功能,可以帮助我们实现负载均衡和读写分离。

对于主服务器(Master)来说,主要负责写,从服务器(Slave)主要负责读,这样的话,就会大大减轻压力,从而提高效率。

从机和备机的区别在于,它是对外提供服务的,一般而言主从就是读写分离,写请求指派到主机,读请求指派到从机。

读写分离还有个操作就是主库不建查询的索引,从库建查询的索引

因为索引是需要维护的,比如你插入一条数据,不仅要在聚簇索引上面插入,对应的二级索引也得插入,修改也是一样的。

所以将读操作分到从库了之后,可以在主库把查询要用的索引删了,减少写操作对主库的影响

主从复制可以分为:

  • 主从同步:当用户写数据主服务器必须和从服务器同步了才告诉用户写入成功,等待时间比较长。
  • 主从异步:只要用户访问写数据主服务器,立即返回给用户。
  • 主从半同步:当用户访问写数据主服务器写入并同步其中一个从服务器就返回给用户成功。

原理

MySQL 主从复制是基于主服务器在二进制日志跟踪所有对数据库的更改。因此,要进行复制,必须在主服务器上启用二进制日志。

每个从服务器从主服务器接收已经记录到日志的数据。当一个从服务器连接到主服务器时,它通知主服务器从服务器日志中读取最后一个更新成功的位置。

从服务器接收从那时发生起的任何更新,并在主机上执行相同的更新。然后封锁等待主服务器通知的更新。

从服务器执行备份不会干扰主服务器,在备份过程中主服务器可以继续处理更新。

工作过程

MySQL 的主从复制工作过程大致如下:

从库:

  1. 生成两个线程,一个 I/O 线程,一个 SQL 线程;
  2. I/O 线程去请求主库的 binlog,并将得到的 binlog 日志写到 relay log(中继日志) 文件中;
  3. SQL 线程会读取 relay log 文件中的日志,并解析成具体操作,来实现主从的操作一致,而最终数据一致;

主库

  1. 主库会生成一个 log dump 线程,用来给从库 I/O 线程传 binlog;

工作过程

请求流程

MySQL 建立请求的主从的详细流程如下:

  1. 当从服务器连接主服务器时,主服务器会创建一个 log dump 线程,用于发送 binlog 的内容。在读取 binlog 的内容的操作中,会对象主节点上的 binlog 加锁,当读取完成并发送给从服务器后解锁。
  2. 当从节点上执行 start slave 命令之后,从节点会创建一个 IO 线程用来连接主节点,请求主库中更新 binlog。IO 线程接收主节点 binlog dump 进程发来的更新之后,保存到 relay-log 中。
  3. 从节点 SQL 线程负责读取 realy-log 中的内容,解析成具体的操作执行,最终保证主从数据的一致性。

类型

异步复制

一个主库,一个或多个从库,数据异步同步到从库。

异步复制

这种模式下,主节点不会主动推送数据到从节点,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理。

这样就会有一个问题,主节点如果崩溃掉了,此时主节点上已经提交的事务可能并没有传到从节点上,如果此时,强行将从提升为主,可能导致新主节点上的数据不完整。

同步复制

在 MySQL cluster 中特有的复制方式。

当主库执行完一个事务,然后所有的从库都复制了该事务并成功执行完才返回成功信息给客户端。

因为需要等待所有从库执行完该事务才能返回成功信息,所以全同步复制的性能必然会收到严重的影响。

半同步复制

在异步复制的基础上,确保任何一个主库上的事物在提交之前至少有一个从库已经收到该事物并日志记录下来。

半同步复制介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到 relay log 中才返回成功信息给客户端(只能保证主库的 Binlog 至少传输到了一个从节点上),否则需要等待直到超时时间然后切换成异步模式再提交。

相对于异步复制,半同步复制提高了数据的安全性,一定程度的保证了数据能成功备份到从库,同时它也造成了一定程度的延迟,但是比全同步模式延迟要低,这个延迟最少是一个 TCP/IP 往返的时间。所以,半同步复制最好在低延时的网络中使用。

半同步模式不是 MySQL 内置的,从 MySQL 5.5 开始集成,需要 master 和 slave 安装插件开启半同步模式。

延迟复制

在异步复制的基础上,人为设定主库和从库的数据同步延迟时间,即保证数据延迟至少是这个参数。

方式

MySQL 主从复制支持两种不同的日志格式,这两种日志格式也对应了各自的复制方式。当然也有二者相结合的混合类型复制。

1、语句复制

基于语句的复制相当于逻辑复制,即二进制日志中记录了操作的语句,通过这些语句在从数据库中重放来实现复制。

这种方式简单,二进制文件小,传输带宽占用小。但是基于语句更新依赖于其它因素,比如插入数据时利用了时间戳。

因此在开发当中,我们应该尽量将业务逻辑逻辑放在代码层,而不应该放在 MySQL 中,不易拓展。

特点:

  • 传输效率高,减少延迟。
  • 在从库更新不存在的记录时,语句赋值不会失败。而行复制会导致失败,从而更早发现主从之间的不一致。
  • 设表里有一百万条数据,一条sql更新了所有表,基于语句的复制仅需要发送一条sql,而基于行的复制需要发送一百万条更新记录

2、行数据复制

基于行的复制相当于物理复制,即二进制日志中记录的实际更新数据的每一行。

这样导致复制的压力比较大,日志占用的空间大,传输带宽占用大。但是这种方式比基于语句的复制要更加精确。

特点:

  • 不需要执行查询计划。
  • 不知道执行的到底是什么语句。
  • 例如一条更新用户总积分的语句,需要统计用户的所有积分再写入用户表。如果是基于语句复制的话,从库需要再一次统计用户的积分,而基于行复制就直接更新记录,无需再统计用户积分。

3、混合类型的复制

一般情况下,默认采用基于语句的复制,一旦发现基于语句无法精确复制时,就会采用基于行的复制。