《MySQL——如何解决一主多从的读写分离的过期读问题》

目录

    • 两种架构
    • 两种架构特点
    • 强制走主库方案
    • Sleep方案
    • 判断主备无延迟方案
    • 配合semi-sync
    • 等主库位点方案
    • GTID方案

两种架构

基于一主多从的读写分离,如何处理主备延迟导致的读写分离问题。

读写分离的主要目标:分摊主库压力。

有两种架构:

1、客户端主动做负载均衡,把数据库的连接信息放在客户端的连接层。由客户端选择后端数据库进行查询。
在这里插入图片描述

2、MySQL和客户端之间加上一个中间代理层proxy,客户端只连接proxy,由proxy根据请求类型和上下文决定请求的分发路由
在这里插入图片描述

两种架构特点

1、客户端直连方案,少了一层proxy转发,查询性能较好,结构也比较简单。

由于要了解后端部署细节,所以在出现主备切换、库迁移等操作时,客户端都会感知到,并且调整数据库连接信息。客户端再分配一个负责管理后端的组件,让业务端只注重于业务逻辑开发

2、带proxy的架构,使客户端不需要关注后端细节。

连接维护、后端信息维护等工作,都是由proxy完成的。但是架构整体相对复杂

两种架构都会遇到"过期读"问题:

由于主从可能存在延迟,客户端执行完一个更新事务后马上发起查询,如果查询选择的是从库的话,就有可能读到的是事务更新之前的状态。

客户端希望的是查询从库的数据结果和查主库的数据结果是一样的。

下面是解决方案:

强制走主库方案;
sleep方案;
判断主备无延迟方案;
配合semi_sync方案;
等主库位点方案;
等GTID方案;

实际应用中,这几个方案可以混合使用。

比如,现在客户端对请求做分类,区分哪些请求可以接受过期读,哪些请求完全不饿能接受过期读。然后,对于不能接受过期读的语句,再使用等GTID或等位点的方案,

过期读本质上是由一写多读导致的,为了避免过期读,只有两种选择:

1、超时放弃

2、转到主库查询

强制走主库方案

将查询请求做分类:

1、对于必须要拿到最新结果的请求,强制将其发到主库上。

2、对于可以读到旧数据的请求,才将其发到从库上。

这种方案虽然取巧,但是好用。

此方案最大的问题在于:当遇到实时性比较高要求的业务需求,就要放弃读写分离,所有的读写压力都在主库,等同于放弃了扩展性。

Sleep方案

主库更新后,读从库之前先sleep。如执行一条select sleep(1)命令。

方案假设:大多数情况下主备延迟在1s之内,做一个sleep可以有很大概率拿到到最新的数据

该方案不精确:

1、如果这个查询请求0.1s就能在从库拿到正确结果,sleep(1)也会等1s

2、如果延迟超过1s,还是会出现过期读

判断主备无延迟方案

要确保备库无延迟有三种做法:

show slave status结果里的seconds_behind_master参数可以用来衡量主备延迟时间的长短。

第一种方法

每次从库执行查询请求前,先判断seconds_behind_master是否等于0,如果不等于0就要等到这个参数变为0才执行查询操作。

第二种方法

比对位点确保主备无延迟。

  • Master_Log_File 和 Read_Master_Log_Pos,表示的是读到的主库的最新位点;

  • Relay_Master_Log_File 和 Exec_Master_Log_Pos,表示的是备库执行的最新位点;

如果Master_Log_File 和 Relay_Master_Log_File 值相同,且Read_Master_Log_Pos和Exec_Master_Log_Pos相同,说明接受到的日志已经同步完成。

第三种方法

对比GTID集合确保主备无延迟

Auto_Position = 1,表示这对主备关系使用了GTID协议
Retrieved_Gtid_Set,是备库收到的所有日志的GTID集合
Executed_Gtid_Set,是备库所有已经执行完成的GTID集合

如果两个集合相同,表示备库接收到了日志都已同步完成。

一个事务的binlog在主备库之间的状态:

1、主库执行完成,写入binlog,并反馈给客户端;

2、binlog被从主库发送给备库,备库收到

3、在备库执行binlog完成。

我们上面判断主备无延迟的逻辑是"备库收到的日志都执行完成了",但是有一部分日志会处于客户端已经收到提交确认,而备库还没收到日志的状态。
在这里插入图片描述

在主库上执行完成了三个事务trx1、trx2、trx3,前两个已经传到从库并且执行完成了。trx3在主库执行完成,并且已经回复给客户端,但是还没有传到从库中。此时在从库B上执行查询请求,按照上面的三个方法的逻辑,从库会认为已经没有同步延迟,但是还是会查不到trx3.

配合semi-sync

解决上面的问题,要引入半同步复制,即semi-sync replication

semi-sync是这样做的:

1、事务提交的时候,主库把binlog发给从库;

2、从库收到binlog以后,发回给主库一个ack,表示收到了

3、主库收到这个ack以后,才能给客户端返回"事务完成"的确认

也就是说,如果启用了semi-sync,就说明所有给客户端发送过确认的事务备库都已经收到了日志。

semi-sync+位点的判断方案,在一主一备场景是成立的,在一主多从场景中,主库只要等到一个从库的ack,就开始给客户端返回确认。

但是这样会出现问题:

1、查询落到没有收到最新日志的从库上,产生过期读。

2、业务更新高峰期,主库的位点或者GTID集合更新很快,两个位点的等值判断一直不成立,很可能出现从库上迟迟无法响应查询请求的情况

等主库位点方案

select master_pos_wait(file, pos[, timeout]);

这个命令逻辑如下:

1、在从库执行

2、参数file和pos指的是主库的文件名和位置

3、timeout可选,设置为正整数N表示这个函数最多等待N秒

4、返回正整数M,表示从命令开始执行,到应用完file和pos表示的binlog位置执行了多少事务

返回值还有一下异常结果:

1、NULL,执行期间,备库同步线程发生异常。

2、-1,等待时间超过N秒

3、0,这个位置已经执行过了

使用该方法步骤:

1、事务trx1更新完后,马上执行show master status得到当前主库执行到的File和Position

2、选定一个从库执行查询语句

3、在从库上执行select master_pos_wait(File,Position,1)

4、如果返回值是>=0的正整数,则在这个从库执行查询语句

5、否则到主库执行查询语句。

假设,每条select最多在从库上等待1s,如果1s内master_pos_wait返回一个>=0的整数,就确保了从库上执行的这个查询结果一定包含trx1数据。

如果每个从库都延迟超过了1s,查询压力都会跑到主库上去。

但是为了不允许过期读,只有两种方法:1、超时放弃 2、转到主库查询

GTID方案

 select wait_for_executed_gtid_set(gtid_set, 1);

命令逻辑是:

1、等待,直到这个库执行的事务中包含传入的gtid_set,返回0

2、超时返回1

等GTID的执行流程为:

1、事务trx1更新后,从返回包直接获取这个事务GTID,记为gtid1

2、选定一个从库执行查询语句

3、在从库上执行select wait_for_executed_gtid_set(gtid1,1)

4、如果返回值为0,在这个从库中执行查询语句

5、否则,到主库执行查询语句

tips:使MySQL在执行事务后,返回包中带上GTID:

( 1. session_track_gtids设置为OWN_GTID 2. 通过API接口获取mysql_session_track_get_first解析出gtid的值 )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

json/ 发送形式_24/7的完整形式是什么?

json/ 发送形式24/7:二十四 (24/7: Twenty-Four Seven) 24/7 or 24-7 service, which generally marked "twenty-four seven" is service that is existing at any time and typically, every day in trade business and industry. Substitute orthograph…

《MySQL tips:并发查询与并发连接区别》

并发连接与并发查询,并不是一个概念。 在执行show processlist的结果里,看到了几千个连接,指的是并发连接。 而"当前正在执行"的语句,才是并发查询。 并发连接数多影响的是内存。 并发查询太高对CPU不利。一个机器的…

对上拉下拉电阻的作用作个总结(想了解的过来看看)(转载)

转自:http://www.amobbs.com/thread-5475279-1-3.html 一、定义:上拉就是将不确定的信号通过一个电阻嵌位在高电平!电阻同时起限流作用!下拉同理!上拉是对器件注入电流,下拉是输出电流;弱强只是…

给用户传入的变量进行转义操作

先看代码实现: /* 对用户传入的变量进行转义操作。*/ if (!get_magic_quotes_gpc()) {if (!empty($_GET)){$_GET addslashes_deep($_GET);}if (!empty($_POST)){$_POST addslashes_deep($_POST);}$_COOKIE addslashes_deep($_COOKIE);$_REQUEST addslashes_…

《MySQL——外部检测与内部统计 判断 主库是否出现问题》

目录select1判断查表判断更新判断外部检测弊端内部统计一主一备的双M架构里,主备切换只需要把客户端流量切换到备库。 在一主多从的架构里,主备切换要把客户端流量切换到备库,也需要把从库接到新主库上。 切换有两种场景:1、主动…

NIM的完整形式是什么?

NIM:无内部消息 (NIM: No Internal Message) NIM is an abbreviation of "No Internal Message". NIM是“无内部消息”的缩写。 It is an expression, which is commonly used in the Gmail platform. It is written in the subject of the mail, if the…

[Json] C#ConvertJson|List转成Json|对象|集合|DataSet|DataTable|DataReader转成Json (转载)...

点击下载 ConvertJson.rar 本类实现了 C#ConvertJson|List转成Json|对象|集合|DataSet|DataTable|DataReader转成Json|等功能大家先预览一下 请看代码 /// <summary> /// 类说明&#xff1a;Assistant /// 编 码 人&#xff1a;苏飞 /// 联系方式&#xff1a;361983679 …

let 只能在严格模式下吗_LET的完整形式是什么?

let 只能在严格模式下吗LET&#xff1a;今天早早离开 (LET: Leaving Early Today) LET is an abbreviation of "Leaving Early Today". LET是“ Leaveing Today Today”的缩写 。 It is an expression, which is commonly used in the Gmail platform. It is writt…

js 遮罩层 loading 效果

//调用方法 //关闭事件<button οnclickLayerHide()>关闭</button>&#xff0c;在loadDiv(text)中&#xff0c;剔除出来 //调用LayerShow(text)&#xff0c;text为参数&#xff0c;可以写入想要写入的提示语 //本方法在调用时会自动生成一个添加到body的div&#x…

centos6.5安装配置LDAP服务[转]

centos6.5安装配置LDAP服务[转] 安装之前查一下 1find / -name openldap*centos6.4默认安装了LDAP&#xff0c;但没有装ldap-server和ldap-client 于是yum安装 1su root2yum install -y openldap openldap-servers openldap-clients不建议编译源码包&#xff0c;有依赖比较麻烦…

《MySQL——恢复数据-误删行、表、库》

目录误删行事前预防误删行数据方法误删表/库延迟复制备库事前预防误删库/表方法传统的架构不能预防误删数据&#xff0c;因为主库的一个drop table命令&#xff0c;会通过binlog传给所有从库和级联从库&#xff0c;进而导致整个集群的实例都会执行这个命令。 MySQL相关的误删除…

python图例位置_Python | 图例位置

python图例位置Legends are one of the key components of data visualization and plotting. Matplotlib can automatically define a position for a legend in addition to this, it allows us to locate it in our required positions. Following is the list of locations…

Freemarker中遍历List实例

Freemarker中如何遍历List摘要&#xff1a;在Freemarker应用中经常会遍历List获取需要的数据&#xff0c;并对需要的数据进行排序加工后呈现给用户。那么在Freemarker中如何遍历List&#xff0c;并对List中数据进行适当的排序呢&#xff1f;通过下文的介绍&#xff0c;相信您一…

工作总结:文件对话框的分类(C++)

原文地址&#xff1a;http://www.jizhuomi.com/software/173.html 文件对话框分为打开文件对话框和保存文件对话框&#xff0c;相信大家在Windows系统中经常见到这两种文件对话框。例如&#xff0c;很多编辑软件像记事本等都有“打开”选项&#xff0c;选择“打开”后会弹出一个…

《MySQL——Innodb改进LRU算法》

Innodb改进LRU.算法&#xff0c;实质上将内存链表分成两段。 靠近头部的young和靠近末尾的old&#xff0c;取5/12段为分界。 新数据在一定时间内只能在old段的头部&#xff0c;当在old段保持了一定的时间后被再次访问才能升级到young。 实质上是分了两段lru&#xff0c;这样做的…

nfc/nfc模式_NFC的完整形式是什么?

nfc/nfc模式NFC&#xff1a;没有进一步评论 (NFC: No Further Comment) NFC is an abbreviation of "No Further Comment". NFC是“没有进一步评论”的缩写 。 It is an expression, which is commonly used in messaging or chatting on social media networking s…

dx小记(2)

1.构造一个平截台体&#xff08;Frustum&#xff09; 最近距离-projMatirx.43/projMatrix.33 projMatrix。33 深度/&#xff08;深度-最近距离&#xff09; projMatrix。44-最近距离*&#xff08;深度/&#xff08;深度-最近距离&#xff09;&#xff09; FrustumMatrix proje…

jQuery: 整理4---创建元素和添加元素

1.创建元素&#xff1a;$("内容") const p "<p>这是一个p标签</p>" console.log(p)console.log($(p)) 2. 添加元素 2.1 前追加子元素 1. 指定元素.prepend(内容) -> 在指定元素的内部的最前面追加内容&#xff0c;内容可以是字符串、…

Design a high performance cache for multi-threaded environment

如何设计一个支持高并发的高性能缓存库 不 考虑并发情况下的缓存的设计大家应该都比较清楚&#xff0c;基本上就是用map/hashmap存储键值&#xff0c;然后用双向链表记录一个LRU来用于缓存的清理。这篇文章 应该是讲得很清楚http://timday.bitbucket.org/lru.html。但是考虑到高…

《MySQL——join语句优化tips》

目录要不要用joinJoin驱动表选择Multi-Range Read优化Batched Key Access &#xff08;BKA&#xff09;对NLJ进行优化BNL算法性能问题BNL转BKA要不要用join 1、如果使用的是Index Nested-Loop Join算法&#xff0c;即可以用上被驱动表的索引&#xff0c;可以用 2、如果使用的…