主从配置一般都是和读写分离相结合,主服务器负责写数据,从服务器负责读数据,并保证主服务器的数据及时同步到从服务器。

主从模式

  • 一主一从/一主多从:一主一从和一主多从是最常见的主从架构方式,一般实现主从配置或者读写分离都可以采用这种架构。 如果是一主多从的模式,当 Slave 增加到一定数量时,Slave 对 Master 的负载以及网络带宽都会成为一个严重的问题。
  • 多主一从:MySQL 5.7 开始支持多主一从的模式,将多个库的数据备份到一个库中存储。
  • 双主复制:理论上跟主从一样,但是两个 MySQL 服务器互做对方的从,任何一方有变更,都会复制对方的数据到自己的数据库。双主适用于写压力比较大的业务场景,或者 DBA 做维护需要主从切换的场景,通过双主架构避免了重复搭建从库的麻烦。(主从相互授权连接,读取对方 binlog 日志并更新到本地数据库的过程;只要对方数据改变,自己就跟着改变)
  • 级联复制:级联复制就是主把 binlog 同步到一级从结点,一级从结点把数据同步到二级从结点。级联模式下因为涉及到的 slave 节点很多,所以如果都连在 master 上对主服务器的压力肯定是不小的。所以部分 slave 节点连接到它上一级的从节点上。这样就缓解了主服务器的压力。
    级联复制解决了一主多从场景下多个从库复制对主库的压力,带来的弊端就是数据同步延迟比较大。

主从分离关键流程

(1) 主库将数据库中数据的变化写入到 binlog
(2) 从库连接主库
(3) 从库会创建一个 I/O 线程向主库请求更新的 binlog
(4) 主库会创建一个 binlog dump 线程来发送 binlog ,从库中的 I/O 线程负责接收
(5) 从库的 I/O 线程将接收的 binlog 写入到 relay log 中。
(6) 从库的 SQL 线程读取 relay log 同步数据本地(也就是再执行一遍 SQL )。

主节点

1、当主节点上进行 insert、update、delete 操作时,会按照时间先后顺序写入到 binlog 中; 2、当从节点连接到主节点时,主节点会创建一个叫做 binlog dump 的线程; 3、一个主节点有多少个从节点,就会创建多少个 binlog dump 线程; 4、当主节点的 binlog 发生变化的时候,也就是进行了更改操作,binlog dump 线程就会通知从节点 (Push 模式),并将相应的 binlog 内容发送给从节点;

从结点

当开启主从同步的时候,从节点会创建两个线程用来完成数据同步的工作。

(1)I/O 线程: 此线程连接到主节点,主节点上的 binlog dump 线程会将 binlog 的内容发送给此线程。此线程接收到 binlog 内容后,再将内容写入到本地的 relay log。

(2)SQL 线程: 该线程读取 I/O 线程写入的 relay log,并且根据 relay log 的内容对从数据库做对应的操作。

如何实现主从数据一致性

要保证主从模式的一致性,有三种同步模式:

1、异步复制

主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果 crash 掉了,此时主上已经提交的事务可能并没有传到从库上,如果此时,强行将从提升为主,可能导致“数据不一致”。早期 MySQL(5.5 以前)仅仅支持异步复制。

2、半同步复制

MySQL 在 5.5 中引入了半同步复制,主库在应答客户端提交的事务前需要保证至少一个从库接收成功。

3、全同步复制

主要等到全部从都收到了数据之后,才返回写入成功。

数据库容灾

Slave 挂了怎么恢复同步?

重启,只要同步服务再次启动,那就可以从上次同步的位置继续增量同步了。

单 Master 挂了怎么办?

如果马上启动那就是最好的解决办法。如果由于硬件或者比较棘手的问题导致没办法立即重启,那就要选一个从库升级为主库,选择的标准是数据最接近主库的,也就是最后一次同步时间最晚的。如果有可能(比如主服务只是数据库无法启动,但机器还在)还要到主服务上拉取最新的 bin-log 进行同步。最后进行一系列设置将选中的从库变更为主库配置。

大致步骤:身份调换之前,主服务器会对表上锁,保证调换期间,不会写进新的数据。

从服务器先停止从服务器 IO 线程,此期间,会应用完 RelayLog 中的所有信息,保证主、从数据完全一致。接下来,主、从服务器都会把自身的 Binlog 文件清除掉,建立起新的 Binlog 文件,再将之前两者的交互信息删干净,此时,可以重新建立主从连接了,从服务器俨然成为新一代主服务器,而原主服务器也解开之前的表锁,担起了从服务器的角色。

binlog 的三种形式

bin-log 日志的格式,支持下面三种,推荐使用 mixed 。

  • statement:会将对数据库操作的 sql 语句写入到 binlog 中。记录每一条 SQL 修改 每一条会修改数据的 sql 语句会记录到 binlog 中。优点是并不需要记录每一条 sql 语句和每一行的数据变化,减少了 binlog 日志量,节约 IO,提高性能。
    缺点是在某些情况下会导致 master-slave 中的数据不一致(如 sleep()函数, last_insert_id(),以及 user-defined functions(udf)等会出现问题)
  • row:会将每一条数据的变化写入到 binlog 中。 ROW 模式(RBR)

仅记录修改的内容,不记录具体的 SQL

不记录每条 sql 语句的上下文信息,仅需记录哪条数据被修改了,修改成什么样了。而且不会出现某些特定情况下的存储过程、或 function、或 trigger 的调用和触发无法被正确复制的问题。 缺点是会产生大量的日志,尤其是 altertable 的时候会让日志暴涨。

  • mixed:以上两种模式的混合使用,一般的复制使用 STATEMENT 模式保存 binlog,对于 STATEMENT 模式无法复制的操作使用 ROW 模式保存 binlog,MySQL 会根据执行的 SQL 语句选择日志保存方式。

六、复制

主从复制

主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。

  • binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
  • I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。
  • SQL 线程 :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)。

读写分离

主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。

读写分离能提高性能的原因在于:

  • 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
  • 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
  • 增加冗余,提高可用性。

读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。


参考资料

主从配置示例