MySQL主从复制(五):读写分离

news2024/10/5 18:32:54

一主多从架构主要应用场景:读写分离。读写分离的主要目标是分摊主库的压力。

读写分离架构


读写分离架构一

架构一结构图:

这种结构模式下,一般会把数据库的连接信息放在客户端的连接层,由客户端主动做负载均衡。也就是说由客户端来选择后端数据库进行查询。

读写分离架构二

架构二结构图:

该架构模式下,在MySQL和客户端之间有一个中间代理层proxy, 客户端只连接proxy, 由proxy根据请求类型和上下文决定请求的分发路由。

两种架构的区别

1)客户端直连方案

因为少了一层proxy转发, 所以查询性能稍微好一点儿, 并且整体架构简单, 排查问题更方便。 但是这种方案, 由于要了解后端部署细节, 所以在出现主备切换、 库迁移等操作的时候, 客户端都会感知到, 并且需要调整数据库连接信息。

你可能会觉得这样客户端也太麻烦了, 信息大量冗余, 架构很丑。 其实也未必, 一般采用这样的架构, 一定会伴随一个负责管理后端的组件, 比如Zookeeper, 尽量让业务端只专注于业务逻辑开发。

2)带proxy架构

带proxy的架构, 对客户端比较友好。 客户端不需要关注后端细节, 连接维护、 后端信息维护等工作, 都是由proxy完成的。 但这样的话, 对后端维护团队的要求会更高。 而且, proxy也需要有高可用架构。 因此, 带proxy架构的整体就相对比较复杂。

注:无论使用哪种架构都会遇到主从延迟问题(即在从库上会读到系统的一个过期状态),且主从延迟是不能100%避免的。

问:处理主从延迟有哪些方案?

答:主从延迟处理方案有以下几种:

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

下面对这几种方案详细介绍。

强制走主库方案


强制走主库方案思路:对查询请求进行分类,对于必须要拿到最新结果的请求,强制将其发到主库上。对于可以读到旧数据的请求,才将其发到从库上。

这个方案最大的问题在于, 有时候你会碰到“所有查询都不能是过期读”的需求, 比如一些金融类的业务。 这样的话, 你就要放弃读写分离, 所有读写压力都在主库, 等同于放弃了扩展性。

尽管如此,该方案仍是用的最多的一种方案。

Sleep方案


Sleep方案思路:主库更新后, 读从库之前先sleep一下。 具体的方案就是, 类似于执行一条select sleep(1)命令。

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

示例:

以卖家发布商品为例, 商品发布后, 用Ajax(Asynchronous JavaScript + XML, 异步JavaScript和XML) 直接把客户端输入的内容作为“新的商品”显示在页面上, 而不是真正地去数据库做查询。

这样, 卖家就可以通过这个显示, 来确认产品已经发布成功了。 等到卖家再刷新页面, 去查看商品的时候, 其实已经过了一段时间, 也就达到了sleep的目的, 进而也就解决了过期读的问题。

但从严格意义上来说,这个方案存在不精确问题。这个不精确主要包含两层意思:

1)假设一个查询请求原本可以在0.5s就可以在从库上拿到正确结果,此时也会等1s。

2)如果延迟超过1s,还是会出现主从延迟。

判断主备无延迟方案


确保备库无延迟,通常有以下三种做法:

查看seconds_behind_master确保主备无延迟

每次从库执行查询请求前,先执行show slave status\G判断seconds_behind_master是否已经等于0。 如果还不等于0 , 那就必须等到这个参数变为0才能执行查询请求。注:seconds_behind_master的单位是秒。show slave status\G结果的部分截图:

对比位点确保主备无延迟

1)Master_Log_File和Read_Master_Log_Pos, 表示的是读到的主库的最新位点。

2)Relay_Master_Log_File和Exec_Master_Log_Pos, 表示的是备库执行的最新位点。

如果Master_Log_File和Relay_Master_Log_File、 Read_Master_Log_Pos和Exec_Master_Log_Pos这两组值完全相同, 就表示接收到的日志已经同步完成。

show slave status\G结果部分截图:

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

1)Auto_Position=1 , 表示这对主备关系使用了GTID协议。

2)Retrieved_Gtid_Set, 是备库收到的所有日志的GTID集合。

3)Executed_Gtid_Set, 是备库所有已经执行完成的GTID集合。

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

可见, 对比位点和对比GTID这两种方法, 都要比判断seconds_behind_master是否为0更准确。

show slave status\G结果部分截图:

问:在执行查询请求之前, 先判断从库是否同步完成的方法, 相比于sleep方案, 准确度确实提升了不少, 但还是没有达到“精确”的程度。 为什么这么说呢?

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

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

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

3)在备库执行binlog完成。

上面判断主备无延迟的逻辑, 是“备库收到的日志都执行完成了”。 但是, 从binlog在主备之间状态的分析中, 不难看出还有一部分日志, 处于客户端已经收到提交确认, 而备库还没收到日志的状态。

示例场景如下:

这时, 主库上执行完成了三个事务trx1、 trx2和trx3, 其中:

1)trx1和trx2已经传到从库, 并且已经执行完成了。

2)trx3在主库执行完成, 并且已经回复给客户端, 但是还没有传到从库中。

如果这时候你在从库B上执行查询请求, 按照我们上面的逻辑, 从库认为已经没有同步延迟, 但还是查不到trx3的。 严格地说, 就是出现了主从延迟。

配合semi-sync方案


该方案可以解决“对比GTID集合确保主备无延迟”中提到的不“精确”问题。

semi-sync replication(半同步复制)主备间的状态:

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

2)从库收到binlog后,给主库返回一个ack,表示收到了。

3)主库收到这个ack后,才能给客户端返回“事务完成”的确认。

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

问1:如果主库掉电的时候,有些binlog还来不及发给从库,会不会导致系统数据丢失?

1)如果使用的是普通的异步复制模式,则有可能会丢失数据。

2)如果使用的是semi-sync+位点判断的方案,则可以解决数据丢失问题。

需要注意的是,semi-sync+位点判断的方案,只对一主一备的场景成立。在一主多从场景中,主库只要等到一个从库的ack,就会开始给客户端返回确认。此时,在从库上执行查询请求,有以下两种情况:

1)如果查询落在这个响应了ack的从库上,能够确保读到最新数据。

2)如果查询落到其它从库上,他们可能还没有收到最新的日志,就可能会产生主从延迟。

注:如果在业务高峰期, 主库的位点或者GTID集合更新很快, 那么上面的两个位点等值判断就会一直不成立, 很可能出现从库上迟迟无法响应查询请求的情况。

问2:当发起一个查询请求后,如果要求得到准确结果,是否需要等到“主备完全同步”,才能执行查询请求?

答:不需要。

示例如下:

图中备库B下的虚线框, 分别表示relaylog(备库执行的最新位点)和binlog中的事务。 可以看到, 图中从状态1 到状态4, 一直处于延迟一个事务的状态。

备库B一直到状态4都和主库A存在延迟, 如果用上面必须等到无延迟才能查询的方案, select语句直到状态4都不能被执行。

但是, 其实客户端是在发完trx1更新后发起的select语句, 我们只需要确保trx1已经执行完成就可以执行select语句了。 也就是说, 如果在状态3执行查询请求, 得到的就是预期结果了。

semi-sync+主备无延迟方案,存在两个问题:

1)一主多从的时候, 在某些从库执行查询请求会存在主从延迟问题。

2)在持续延迟的情况下, 可能出现过度等待的问题。

等主库位点方案


该方案能解决“semi-sync+主备无延迟方案”存在的两个问题。

下面先来看一条命令:

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

这条命令的逻辑如下:

1)它是在从库执行的。

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

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

这条命令返回结果如下:

1)如果执行期间, 备库同步线程发生异常, 则返回NULL。

2)如果等待超过N秒, 就返回-1。

3)如果刚开始执行的时候, 就发现已经执行过这个位置了, 则返回0。

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

对于上图中先执行trx1, 再执行一个查询请求的逻辑, 要保证能够查到正确的数据, 我们可以使用这个逻辑:

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

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

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

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

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

上述逻辑流程图:

这里我们假设, 这条select查询最多在从库上等待1秒。 那么, 如果1秒内master_pos_wait返回一个大于等于0的整数, 就确保了从库上执行的这个查询结果一定包含了trx1的数据。

步骤5到主库执行查询语句, 是这类方案常用的退化机制(兜底方案)。 因为从库的延迟时间不可控, 不能无限等待, 所以如果等待超时, 就应该放弃, 然后到主库去查。

GTID方案


MySQL中同样提供了一个类似的命令:

select wait_for_executed_gtid_set(gtid_set, 1);

这条命令的逻辑是:

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

2)超时返回1。

在前面等位点的方案中, 我们执行完事务后, 还要主动去主库执行show master status。 而MySQL 5.7.6版本开始, 允许在执行完更新类事务后, 把这个事务的GTID返回给客户端, 这样等GTID的方案就可以减少一次查询。

等GTID的执行流程:

1)trx1事务更新完成后, 从返回包直接获取这个事务的GTID, 记为gtid1。

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

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

4)如果返回值是0, 则在这个从库执行查询语句。

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

上述逻辑流程图:

问:怎么能够让MySQL在执行事务后, 返回包中带上GTID呢?

答:把参数session_track_gtids设置为OWN_GTID, 然后通过API接口mysql_session_track_get_first从返回包解析出GTID的值即可。

小结:思考题


思考:假设你的系统采用了等GTID的方案, 现在你要对主库的一张大表做DDL,在做读写分离时可能会出现什么情况呢? 为了避免这种情况, 你会怎么做呢?

假设,这条语句在主库上要执行10分钟,提交后传到备库就要10分钟(典型的大事务)。那么,在主库DDL之后再提交的事务的GTID,去备库查的时候,就会等10分钟才出现。

这样,这个读写分离机制在这10分钟之内都会超时,然后走主库。

这种预期内的操作,应该在业务低峰期的时候,确保主库能够支持所有业务查询,然后把读请求都切到主库,再在主库上做DDL。等备库延迟追上以后,再把读请求切回备库。

通过这个思考题,我主要想让关注的是,大事务对等位点方案的影响。

当然了,使用gh-ost方案来解决这个问题也是不错的选择。

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

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

相关文章

ROS | Gmapping进行Slam建图

launch文件 GMapping参数设置: 修改参数:

笔记 | 《css权威指南》

网络安全色 URL text-indent line-height & vertical-align 字体 font-weight 400 normal 700 bold background-attachment

【C++】c++入门(下 )

c入门 1.内联函数1.1 概念1.2 特性 2.auto关键字(C11)2.1 简介2.2 auto的使用2.3 auto不能推导的场景2.4 typedef取别名也能产生和auto的效果,为什么不使用? 3.基于范围的for循环(C11)3.1 9.1 范围for的语法3.2 范围for的使用条件 4.指针空值nullptr(C11…

寻找峰值 ---- 二分查找

题目链接 题目: 分析: 因为题目中要找的是任意一个峰值即可, 所以和<山脉数组的峰值索引>这道题差不多因为峰值左右都小于峰值, 所以具有"二段性", 可以使用二分查找算法如果nums[mid] < nums[mid 1], mid一定不是峰值, 所以left mid 1如果nums[mid] &…

【大模型部署】在C# Winform中使用文心一言ERNIE-3.5 4K 聊天模型

【大模型部署】在C# Winform中使用文心一言ERNIE-3.5 4K 聊天模型 前言 今天来写一个简单的ernie-c#的例子&#xff0c;主要参考了百度智能云的例子&#xff0c;然后自己改了改&#xff0c;学习了ERNIE模型的鉴权方式&#xff0c;数据流的格式和简单的数据解析&#xff0c;实…

电商平台的消费增值模式革新

在当今的电商市场&#xff0c;用户留存和粘性是各大平台竞相追求的目标。而消费增值模式&#xff0c;以其独特的激励机制&#xff0c;正逐渐成为电商平台吸引和留住用户的新策略。 一、消费即投资&#xff1a;创新的返利机制 在传统的电商消费中&#xff0c;消费者完成交易后&…

基于QEMU-aarch64学习UEFI(EDK2)-7Print打印函数

1 基于QEMU-aarch64学习UEFI(EDK2)-7Print打印函数 文章目录 1 基于QEMU-aarch64学习UEFI(EDK2)-7Print打印函数1.1 Print打印函数输出字符串1.2 Print打印函数其他用法程序开发我们以 edk2-stable202302版本为准。 1.1 Print打印函数输出字符串 我们把edk2/MdeModulePkg/App…

Upstream最新发布2024年汽车网络安全报告-百度网盘下载

Upstream最新发布2024年汽车网络安全报告-百度网盘下载 2024年2月7日&#xff0c;Upstream Security发布了2024年Upstream《GLOBAL AUTOMOTIVE CYBERSECURITY REPORT》。这份报告的第六版着重介绍了汽车网络安全的拐点&#xff1a;从实验性的黑客攻击发展到规模庞大的攻击&…

springboot 两个相同类型的Bean使用@Resouce加载

问题描述 有两个相同类型的Bean 使用Service等注解注入或者Bean注入启动以后报错&#xff1a; qualifying bean of type com.fasterxml.jackson.databind.ObjectMapper available: expected single matching bean but found 2提示有相同的类型两个。 解决 * 每个Bean Resour…

AI预测福彩3D采取888=3策略+杀断组+杀和尾缩水测试5月24日预测第1弹

哈喽&#xff0c;各位亲爱的小伙伴&#xff0c;在发布本期预测结果之前&#xff0c;先对最近的这套算法测试做一下总结。 最近的一套算法采用了88723的容差策略&#xff0c;关于容差策略相信大家都比较清楚&#xff1a;容差可以最大限度的保证初始大底中包含中奖号码&#xff0…

「网络流浅谈」网络流的概念

更好的阅读体验 通常做题思路&#xff1a;问题转化为流网络&#xff0c;再通过最大流 / 最小割 / 费用流与问题之间的数量关系&#xff0c;求解出原问题。 网络流于其他算法不同&#xff0c;概念定理需要熟记于心&#xff0c;否则后面做题会有很大的障碍。 1. 流网络 一个流…

鸿蒙开发ArkUI-X基础知识:【ArkUI代码工程及构建介绍】

代码工程及构建介绍 背景 ArkUI作为OpenHarmony的默认开发框架&#xff0c;在本项目&#xff08;ArkUI-X&#xff09;中需要做到一套代码同时支持多平台构建&#xff0c;所以会采取共仓开发的方式&#xff0c;部分仓直接指向OpenHarmony相关开源仓。 代码结构及仓库结构 代…

css左右滚动互不影响

想实现左右都可以滚动&#xff0c;且互不影响。 只需要再左边的css里面 .threedlist {cursor: pointer;width: 280px;position: fixed;height: 100vh; /* 定义父容器高度 */overflow-y: auto; /* 只有在内容超过父容器高度时才出现滚动条 */} 如果想取消滚动条样式 .threedli…

windows docker desktop 更换镜像存储目录

windows docker desktop 更换镜像存储目录 方法&#xff1a;如图&#xff0c;Browse浏览一个新的目录并选中&#xff0c;确定后&#xff0c;程序会开始stop&#xff0c;在stop完成前&#xff0c;会持续迁移原有镜像到新的位置&#xff0c;你会发现目标位置的磁盘占用空间越来越…

2024最新 Jenkins + Docker 实战教程(五)- 配置Gitee Webhooks实现自动构建部署

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

Matlab:音频处理

用Matlab绘制一段音频信号在时域上的波形图&#xff0c;然后用低通滤波器滤掉噪音并再次绘制 1、导入音频文件 filename X:\1.mp3; % 替换为你的音频文件路径 [x, Fs] audioread(filename); 2、获取音频信号长度 len length(x); 3、计算时间轴 t (0:len-1) / Fs; 4、…

轻量音乐网站程序源码,在线音乐免费听歌

这是一个高品质的音乐共享和流媒体平台&#xff0c;用户可以在这个网站上免费在线听歌。这个轻量级的音乐网站程序源码&#xff0c;是您创建自己的音乐流媒体网站的最佳选择&#xff01;它还支持制作插件&#xff0c;并且在更新后&#xff0c;您可以保留您的自定义设置。 下 载…

ASP+ACCESS基于WEB车辆管理系统

3.1 系统需求分析 该过程是个不断认识不断细化的过程。这里所要完成的工作是深入描述软件的功能和性能&#xff0c;确定软件的设计限制和软件同其他系统元素的接口细节&#xff0c;从而奠定软件的开发基础。 性能需求&#xff1a;该系统中&#xff0c;管理员模块只有管理人员…

重学java 40.多线程 — 死锁和线程状态

—— 24.5. 一、死锁 1.死锁介绍&#xff08;锁嵌套就有可能产生死锁&#xff09; 指的是两个或者两个以上的线程在执行的过程中由于竞争同步锁而产生的一种阻塞现象;如果没有外力的作用,他们将无法继续执行下去,这种情况称之为死锁 例&#xff1a; 两线程处于互相等待的状态&a…

SQL刷题笔记day2

1 题目 我的通过代码&#xff1a; select salary from salaries group by salary order by salary desc 复盘&#xff1a;考点是只显示一次——group by&#xff0c;逆序&#xff08;从大到小&#xff09;——order by...desc 2题目 我的错误代码&#xff1a; select empl…