首页 > 编程知识 正文

数据库读写分离的原理,mysql读写分离方案

时间:2023-05-03 16:14:58 阅读:48997 作者:3508

在访问量较大的业务场景中,MySQL读写分离尤为重要。

MySQL读写分离通常意味着修改操作在主库中执行,查询操作在从库中执行。 主要目的是分担主库的压力。

但是,读写分离也有问题。 例如,主从延迟时,读取的库数据不是最新的。 对应的业务场景例如:

你在网上购买的一个商品,在支付结束后,由于主从延迟,第一时间查不到订单。 即使可以等一会儿再看订单,我相信很多用户也不会接受。

本节介绍读写分离应注意的问题。

读写分离通常依赖于主从副本,因此,首先查看主从副本的原理也有助于理解为什么会发生主从延迟。

1主从复制原理

1.1 MySQL异步复制

传统的MySQL主从复制是异步的,因此也称为异步复制。 MySQL异步复制的原理如下:

如果主库打开了binlog

如果主库中有添加/删除语句,则将其记录在binlog中

主库通过IO线程从库的中继日志(relay log )传递binlog的内容

主库向客户端返回commit成功(此处不管理是否从库收到事务binlog ) )。

从库的SQL线程读取relay log中的信息,并将其从库数据库中应用

实现原理如下图所示。

在上图中,有一点不容忽视。

在主库中并行运行的更新SQL只能在从库中串行运行,因为从库中只有一个SQL线程消化relay log。 这也往往是主从延迟发生的原因。

当然,从5.6开始,MySQL可以通过为每个库配置单独的SQL线程来清除relay log,5.7添加了基于组提交的并行复制,大大改善了主从延迟问题。

1.2 MySQL半同步复制

除了MySQL异步复制外,还出现了一种改进的复制方法,称为半同步复制。 其原理如下。

如果主库打开了binlog

如果主库中有添加/删除语句,则将其记录在binlog中

主库通过IO线程从库的中继日志(relay log )传递binlog的内容

从库收到binlog后,向主库发送ACK,表示已收到

在主库收到此ACK之前,不能向客户端返回commit成功

从库的SQL线程读取relay log中的信息,并将其从库数据库中应用

实现原理如下图所示。

与传统的异步复制相比,半同步复制确保向客户端发送提交确认的所有事务都已经从库中收到此日志。

2常见读写分离方式

2.1、通过程序

通过开发配置程序,决定修改操作从主库中进行,查询操作从库中进行。 用这种方式直接连接数据库,具有性能好的优点,存在配置麻烦的缺点。

但是,请注意,必须从库中设置为read_only,以防止由于配置错误而从库中写入数据。

请注意这里:

建议程序连接的用户不要授予super权限。 因为具有super权限的用户即使在整个库中设置了read_only,也可以写入数据。

2.2、通过中间件

中间件读写分离是目前主流的方式。 以MyCAT为例:

方案. XML文件中dataHost标记balance属性的值决定是否启用读/写隔离。

balance的各值和对应的读写方法如下。

0 :不打开读写分离,读取操作发送到writehost

1 :所有readhost和stand by writehost都参与选择语句的负载平衡

2 )所有读取操作均随机通过writehost、readhost分发

3 )所有读请求都是随机分发到与writerhost相对应的readhost中执行的,writehost不承担读压力

因此,可以根据情况选择上述适当的读写分离策略。

3主从延迟发生在什么情况?

本节开头就读写分离场景说,最大的问题是主从延迟。 那么,在什么情况下会发生主从延迟呢? 这里大致总结一下可能导致主从延迟的场景:

1 .现实中的铃DDL

2 .大型事务

3 .主库DML的并发大小

4 .来自库的配置不好

5 .表中无主键等

因此,在有读写分离的情况下,必须避免上诉情况成为业务上有吸引力的香烟。

当然,不能完全消除主从延迟。 因此,介绍读写分离场景下的几种延时对策方法。

4如何应对读写分离主从延迟

读写分离场景应该如何应对主从延迟呢? 这里讨论几种应对主从延迟的常用方法。

4.1判断主从有无延迟

根据业务场景

所有请求都落在主库,主库压力会很大,但是在读写分离的情况,又不希望主从存在延迟的时候去读取从库。这种情况,就可以考虑查询时,先判断主从是否存在延迟,如果存在延迟,则查询落在主库,如果没延迟,则查询语句落在从库。

这里介绍几种判断主从延迟的方法:

第一种方法:判断 Seconds_Behind_Master 是否等于 0。

如果 Seconds_Behind_Master =0,则查询从库,如果大于 0,则查询主库。

这里补充一下 Seconds_Behind_Master。

Seconds_Behind_Master 是在从库上执行 show slave status 时返回的其中一项,表示从库延迟的秒数。

其计算方法是:

从库服务器当前的时间戳与二进制日志中的事件的时间戳(在主库上的写入时间)相对比得到的。

但是某些情况下,Seconds_Behind_Master 并不一定准确。比如网络中断时,Seconds_Behind_Master = 0 ,并不能代表主从无延迟。因此,有比这个更准确的一种方法:对比位点或 GTID。

第二种方法:对比位点或 GTID如果 Master_Log_File 跟 Relay_Master_Log_File 相等,

并且 Read_Master_Log_Pos 跟 Exec_Master_Log_Pos 相等,

则可以把读请求放到从库,否则读请求放到主库。补充一下上面几个参数的意义:

几个参数均是通过 show slave status 返回的参数,用来查询主从复制的状态。

Master_Log_File:IO 线程正在读取的主库 binlog 文件名

Relay_Master_Log_File:SQL 线程最近执行的事务对应的主库 binlog 文件名

Read_Master_Log_Pos :IO 线程正在读取的主库 binlog 文件中的位点

Exec_Master_Log_Pos :SQL 线程最近读取和执行的事务对应的主库 binlog 文件中的位点

如果开启了 GTID 复制,则可以对比 Retrieved_Gtid_Set 和 Executed_Gtid_Set 是否相等,相等则把读请求放到从库,有差异则读请求放到主库。

同样补充下两个参数的意义:前提是需要开启 GTID 两个参数才会有值,解释如下:

Retrieved_Gtid_Set:从库收到的所有日志的 GTID 集合

Executed_Gtid_Set:从库已经执行完的 GTID 集合

4.2 采用半同步复制

在本节的前面,我们讲解了半同步复制的原理,跟传统的异步复制相比,半同步复制保证了所有给客户端发送过确认提交的事务,从库都已经收到这个日志了。因此出现延迟的概率会小很多,当然实际生产应用时,建议结合上面讲的位点或 GTID 判断。

4.3 等待同步完成

依然采用 4.1 中介绍的几种判断是否有延迟的方法,只是应对方式不一样,比如存在延迟,则将情况反馈给程序,在前端页面提醒用户数据未完全同步,如果没有延迟,则查询从库。

有人可能会觉得:这种方式谁会用啊?实际可以应用在内部人员看的报表业务上。因为报表可能涉及的 SQL 都比较复杂,存在延迟就考虑去查询主库,可能会对其它线上业务有影响,因此可以等待从库同步完成,再查询从库。

补充:读写分离,由于能分担主库的压力,很多情况会考虑读写分离。但是在使用时,就应该考虑到一些问题,其中最主要的就是主从延迟。这个就看业务是否能接受延迟了。如果不能接受延迟,建议采用半同步复制并且加上延迟判断。存在延迟则把读请求放到主库,没延迟就读从库。如果业务能接受延迟,可以等数据同步完成,再去从库进行查询。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。