mysql-主从模式


本篇文章是我的学习比较,内容主题来自 丁奇老师的《mysql45讲》

为什么要做主从?

1、避免单点故障

2、读写分离提升性能
读操作:主库、从库都可以接收;从库缓解了主库的读压力,提高了主库的I/O性能,使数据库能支撑更大的并发
写操作:只由主服务器负责,然后主库会将写操作同步给从库。

为什么写操作只能在主库上呢?
为了避免同时写多个实例的数据不一致问题
如果客户端对同一个数据前后修改了三次,每一次的修改请求都发送到不同的实例上,在不同的实例上执行,那么,这个数据在这三个实例上的副本就不一致了(分别是v1、v2和v3)
主从库模式一旦采用了读写分离,所有数据的修改只会在主库上进行,不用协调三个实例。主库有了最新的数据后,会同步给从库,这样,主从库的数据就是一致的

主从同步(复制)

因为写请求只走主库,从库和主库的数据就不一致了。
解决办法:主从同步(也叫主从复制)

主从复制是指将主数据库的数据通过binlog传到从数据库上,然后在从数据库上对这些日志进行重新执行,从而使从数据库和主数据库的数据保持一致

主从复制的实现:

MySql通过三个线程来完成主从库间的数据复制

  • 其中主库上的Binlog Dump线程负责生成Binlog文件并传输给从库
  • 从库上的I/O线程和SQL线程负责重新执行binlog实现数据同步;

主从复制的基本流程:
主库会把数据记录在Binlog中,以供从库复制;
当在从库上启动复制时,首先创建I/O线程连接主库,主库随后创建Binlog Dump线程binlog送给I/O线程,I/O线程将数据更新到从库的中转日志Relay Log中去,之后从库上的SQL线程重新执行中转日志,达到和主库一样的数据状态。

详细过程如下图(引用自丁奇老师的《mysql45讲》):
在这里插入图片描述
可以看到:主库接收到客户端的更新请求后,执行内部事务的更新逻辑,同时写 binlog。

备库 B 跟主库 A 之间维持了一个长连接。主库 A 内部有一个线程,专门用于服务备库 B 的这个长连接。一个事务日志同步的完整过程是这样的:

  • 在备库 B 上通过 change master 命令,设置主库 A 的 IP、端口、用户名、密码,以及要从哪个位置开始请求 binlog,这个位置包含文件名和日志偏移量。

  • 在备库 B 上执行 start slave 命令,这时候备库会启动两个线程,就是图中的 io_thread 和 sql_thread。其中 io_thread 负责与主库建立连接。

  • 主库 A 校验完用户名、密码后,开始按照备库 B 传过来的位置,从本地读取 binlog,发给 B。

  • 备库 B 拿到 binlog 后,写到本地文件,称为中转日志(relay log)。

  • sql_thread 读取中转日志,解析出日志里的命令,并执行。

主从复制策略

主从复制主要有同步、异步、半同步三种策略,另外使用的比较少的还有多源复制和延迟复制
在这里插入图片描述

同步复制

同步复制技术是指,当用户请求更新数据时,主数据库必须要同步到备数据库之后才可给用户返回,即如果主数据库没有同步到备数据库,用户的更新操作会一直阻塞。这种方式保证了数据的强一致性,但牺牲了系统的可用性。
适合对一致性有严格要求的场合,比如金融、交易之类的场景。
在这里插入图片描述

异步复制

异步复制技术是指,当用户请求更新数据时,主数据库处理完请求后可直接给用户响应,而不必等待备数据库完成同步,即备数据库会异步进行数据的同步,用户的更新操作不会因为备数据库未完成数据同步而导致阻塞。显然,这种方式保证了系统的可用性,但牺牲了数据的一致性。

异步复制技术适用于互联网场景,一般对用户请求响应时延要求很高

MySQL 集群默认的数据复制模式采用的就是异步复制技术
Redis 集群中,采用的也是异步复制技术,因此性能较高
在这里插入图片描述

半同步复制

同步复制技术会满足数据的强一致性,但会牺牲一定的可用性;
异步复制技术会满足高可用,但一定程度上牺牲了数据的一致性。
半同步在二者之间取了一个平衡,既可以保证绝大多数情况下的数据一致性,同时将不可用时间减少到用户可以接受的范围内。

半同步复制技术的原理:
用户发出写请求后,主数据库会执行写操作,并给备数据库发送同步请求,但主数据库不用等待所有备数据库回复数据同步成功便可响应用户,只需等待一部分备数据库同步完成后即可响应用户写操作执行成功。

有损半同步复制
在半同步复制中,有损半同步复制是 MySQL 5.7 版本前的半同步复制机制,这种半同步复制在Master 发生宕机时,Slave 会丢失最后一批提交的数据,若这时 Slave 提升为Master,可能会发生已经提交的事情不见了,发生了回滚的情况。

有损半同步复制原理如下图所示:
在这里插入图片描述
可以看到,有损半同步是在 Master 事务提交后,即步骤 4 后,等待 Slave 返回 ACK,表示至少有 Slave 接收到了二进制日志,如果这时二进制日志还未发送到 Slave,Master 就发生宕机,则此时 Slave 就会丢失 Master 已经提交的数据。

无损半同步复制
MySQL 5.7 的无损半同步复制解决了这个问题,其原理如下图所示:
在这里插入图片描述
从上图可以看到,无损半同步复制 WAIT ACK 发生在事务提交之前,这样即便 Slave 没有收到二进制日志,但是 Master 宕机了,由于最后一个事务还没有提交,所以本身这个数据对外也不可见,不存在丢失的问题。

所以,对于任何有数据一致性要求的业务,如电商的核心订单业务、银行、保险、证券等与资金密切相关的业务,务必使用无损半同步复制。这样数据才是安全的、有保障的、即使发生宕机,从机也有一份完整的数据。

多源复制

无论是异步复制还是半同步复制,都是 1 个 Master 对应 N 个 Slave。其实 MySQL 也支持 N 个 Master 对应 1 个 Slave,这种架构就称之为多源复制。

多源复制允许在不同 MySQL 实例上的数据同步到 1 台 MySQL 实例上,方便在 1 台 Slave 服务器上进行一些统计查询,比如把订单库、库存库、供应商库,通过多源复制同步到了一台 MySQL 实例上,然后对其进行数据处理。

延迟复制

以上复制策略都希望尽可能的减少数据复制同步的时间,但是延迟复制却故意延缓数据同步,比如24小时之后再做复制,主要用于防止误操作比如有程序员删库跑路了,至少还有24小时之前的备份。

我们可以通过以下命令设置延迟复制:

CHANGE MASTER TO master_delay = 3600

这样就人为设置了 Slave 落后 Master 服务器1个小时。

延迟复制在数据库的备份架构设计中非常常见,比如可以设置一个延迟一天的延迟备机,这样本质上说,用户可以有 1 份 24 小时前的快照。

那么当线上发生误操作,如 DROP TABLE、DROP DATABASE 这样灾难性的命令时,用户有一个 24 小时前的快照,数据可以快速恢复。

对金融行业来说,延迟复制是你备份设计中,必须考虑的一个架构部分。

主从复制的问题

复制的延迟问题

主从数据同步过程中,数据是不一致的,怎么办?
——将库表主键三个信息拼装一个key设置到cache里,设置这条记录的超时时间为“主从同步时延”,假设预计主从延时最多为1s,这个key的cache超时时间就设置为1s。
当读请求发生时,到cache里去查询,如果,

  • cache里有这个key,说明1s内刚发生过写请求,数据库主从同步可能还没有完成,此时就应该去主库查
  • cache里没有这个key,说明最近没有发生过写请求,此时就可以去从库查询

双M模式下的循环复制问题

上面的分析都是基于主从模式,但实际生产上使用比较多的是双 M 结构即双Master模式,也就是下图所示的主备切换流程。
在这里插入图片描述
双M模式的优点:
双 M 结构和 M-S 结构,其实区别只是多了一条线,即:节点 A 和 B 之间总是互为主备关系。这样在切换的时候就不用再修改主备关系。

双M模式的缺点:循环复制问题
什么是循环复制问题?
业务逻辑在节点 A 上更新了一条语句,然后再把生成的 binlog 发给节点 B,节点 B 执行完这条更新语句后也会生成 binlog。
那么,如果节点 A 同时是节点 B 的备库,相当于又把节点 B 新生成的 binlog 拿过来执行了一次,然后节点 A 和 B 间,会不断地循环执行这个更新语句,也就是循环复制了。这个要怎么解决呢?

我们知道,MySQL 在 binlog 中记录了这个命令第一次执行时所在实例的 server id。因此,我们可以用下面的逻辑,来解决两个节点间的循环复制的问题:

  • 规定两个库的 server id 必须不同,如果相同,则它们之间不能设定为主备关系;

  • 一个备库接到 binlog 并在重放的过程中,生成与原 binlog 的 server id 相同的新的 binlog;

  • 每个库在收到从自己的主库发过来的日志后,先判断 server id,如果跟自己的相同,表示这个日志是自己生成的,就直接丢弃这个日志。

按照这个逻辑,如果我们设置了双 M 结构,日志的执行流就会变成这样:

  • 从节点 A 更新的事务,binlog 里面记的都是 A 的 server id;

  • 传到节点 B 执行一次以后,节点 B 生成的 binlog 的 server id 也是 A 的 server id;

  • 再传回给节点 A,A 判断到这个 server id 与自己的相同,就不会再处理这个日志。所以,死循环在这里就断掉了

主从切换的两种策略

当主库崩溃之后,需要将从库升级为主库,即主从切换。

一般有两种主从切换策略:

  • 可靠性优先:保证可靠性就是保证数据一致性,数据一致之前不对外提高服务,所以会造成一定时间的不可用
  • 可用性优先:保证可用性就是尽量减少不可用时间,在数据没有同步完成之前就提高服务,所以会造成一定的数据不一致。

两种策略有利有弊,需要根据具体的业务场景选择那种更好。
在实际的应用中,大多数还是使用可靠性优先的策略。毕竟保证数据准确,应该是数据库服务的底线。在这个基础上,通过减少主备延迟,减少系统的不可用时间

下面具体介绍下两种策略

可靠性优先策略

采用可靠性优先策略进行主从切换的过程如下图:
在这里插入图片描述
备注:图中的 SBM,是 seconds_behind_master 参数的简写。即备库完成备份仍需的时间

可以看到流程是这样的:

  • 首先判断备库 B 现在的 seconds_behind_master,如果小于某个值(比如 5 秒)继续下一步,否则持续重试这一步;

  • 把主库 A 改成只读状态,即把 readonly 设置为 true;

  • 判断备库 B 的 seconds_behind_master 的值,直到这个值变成 0 为止;

  • 把备库 B 改成可读写状态,也就是把 readonly 设置为 false;

  • 把业务请求切到备库 B。

在步骤 2 之后,主库 A 和备库 B 都处于 readonly 状态,也就是说这时系统处于不可写状态 即不可用,直到步骤 5 完成后才能恢复。

在这个不可用状态中,比较耗费时间的是步骤 3,可能需要耗费好几秒的时间。这也是为什么需要在步骤 1 先做判断,确保 SBM的值足够小。

试想如果一开始主备延迟就长达 30 分钟,而不先做判断直接切换的话,系统的不可用时间就会长达 30 分钟,这种情况一般业务都是不可接受的。

当然,系统的不可用时间,是由这个数据可靠性优先的策略决定的。你也可以选择可用性优先的策略,来把这个不可用时间几乎降为 0。

可用性优先策略

如果我强行把步骤 4、5 调整到最开始执行,也就是说不等主备数据同步,直接把连接切到备库 B,并且让备库 B 可以读写,那么系统几乎就没有不可用时间了。

我们把这个切换流程,暂时称作可用性优先流程。这个切换流程的代价,就是可能出现数据不一致的情况。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值