《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,一经查实,立即删除!

相关文章

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

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

[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 …

《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…

工作总结:文件对话框的分类(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;这样做的…

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。但是考虑到高…

LinkChecker 8.1 发布,网页链接检查

LinkChecker 8.1 可对检查时间和最大的 URL 数量进行配置&#xff1b;当使用 HTTP 请求时发送 do-not-track 头&#xff1b;生成 XML 的 sitemap 用于搜索引擎优化&#xff1b;检测 URL 长度和重复的页面内容&#xff1b;修复了很多检查的 bug。 LinkChecker 是一个网页链接检查…

c语言语言教程0基础_C语言基础

c语言语言教程0基础Hey, Folks here I am back with my second article on C language. Hope you are through with my previous article C language - History, Popularity reasons, Characteristics, Basic structure etc. In this one, I will cover some fundamental conce…

《MySQL——临时表》

内存表与临时表区别 临时表&#xff0c;一般是人手动创建。 内存表&#xff0c;是mysql自动创建和销毁的。 内存表&#xff0c;指的是使用Memory引擎的表&#xff0c;建表语法&#xff1a;create table ... engine memeory 表的数据存在内存里&#xff0c;系统重启后会被清…

drei

模拟9 T3 &#xff08;COGS上也有&#xff0c;链接http://218.28.19.228/cogs/problem/problem.php?pid1428&#xff09; 题目描述 输入a&#xff0c;p&#xff0c;求最小正整数x&#xff0c;使得a^x mod p 1。 分析 神奇的欧拉定理&#xff08;对于gcd&#xff08;a&#xf…

css中变量_CSS中的变量

css中变量CSS | 变数 (CSS | Variables) CSS variables allow you to create reusable values that can be used throughout a CSS document. CSS变量允许您创建可在CSS文档中使用的可重用值。 In CSS variable, function var() allows CSS variables to be accessed. 在CSS变…

SuperSpider——打造功能强大的爬虫利器

SuperSpider——打造功能强大的爬虫利器 博文作者&#xff1a;加菲 发布日期&#xff1a;2013-12-11 阅读次数&#xff1a;4506 博文内容&#xff1a; 1.爬虫的介绍 图1-1 爬虫&#xff08;spider) 网络爬虫(web spider)是一个自动的通过网络抓取互联网上的网页的程序&#xf…

《MySQL——关于grant赋权以及flush privileges》

先上总结图&#xff1a; 对于赋予权限或者收回权限还是创建用户&#xff0c;都会涉及两个操作&#xff1a; 1、磁盘&#xff0c;mysql.user表&#xff0c;用户行所有表示权限的字段的值的修改 2、内存&#xff0c;acl_users找到用户对应的对象&#xff0c;将access值修改 g…

《MySQL 8.0.22执行器源码分析(1)——execute iterator一些记录》

目录一条语句的函数调用栈顺序8.0使用迭代器模式改进executorint *handler*::ha_rnd_next(*uchar* **buf*)int *TableScanIterator*::Read()int FilterIterator :: Read&#xff08;&#xff09;int HashJoinIterator::Read()int NestedLoopIterator :: Read&#xff08;&#…

strcspn函数

函数原型&#xff1a;extern int strcspn(char *str1,char *str2) 参数说明&#xff1a;str1为参照字符串&#xff0c;即str2中每个字符分别与str1中的每个字符比较。 所在库名&#xff1a;#include <string.h> 函数功能&#xff1a;以str1为参照&#xff0c…

MongoDB源码概述——内存管理和存储引擎

数据存储&#xff1a; 之前在介绍Journal的时候有说到为什么MongoDB会先把数据放入内存&#xff0c;而不是直接持久化到数据库存储文件&#xff0c;这与MongoDB对数据库记录文件的存储管理操作有关。MongoDB采用操作系统底层提供的内存文件映射&#xff08;MMap&#xff09;的方…

SharePoint 2010 Form Authentication (SQL) based on existing database

博客地址 http://blog.csdn.net/foxdaveSharePoint 2010 表单认证&#xff0c;基于现有数据库的用户信息表本文主要描述本人配置过程中涉及到的步骤&#xff0c;仅作为参考&#xff0c;不要仅限于此步骤。另外本文通俗易懂&#xff0c;适合大众口味儿。I. 开启并配置基于声明的…

小狐狸ChatGPT系统 不同老版本升级至新版数据库结构同步教程

最新版2.6.7下载&#xff1a;https://download.csdn.net/download/mo3408/88656497 小狐狸GPT付费体验系统如何升级&#xff0c;该系统更新比较频繁&#xff0c;也造成了特别有用户数据情况下升级时麻烦&#xff0c;特别针对会员关心的问题出一篇操作教程&#xff0c;本次教程…