如何避免MySQL主从延迟带来的读写问题?
在 MySQL 部署架构选型上,何避许多公司都会用到主从读写分离的延迟架构,如下是读写一个一主一从的架构,主库master负责写入,问题从库slave进行读取。何避
图片
但是延迟既然是读写分离,必然会面临这样一个问题,读写当在主库上进行更新后,问题有可能数据还没来得及同步到从库,何避但是延迟这个时候又有读数据的需求,为了能正确读取出数据,读写这个时候就只有读主库了。问题但是何避这样做增加了主库的压力,违反了我们做读写分离的延迟初衷。所以这一节我们就来针对这种情况探讨下,读写如何尽量的避免对主库的压力,尽量的从从库读取数据。
主从复制的原理
在探讨解决方案前,我们先要对主从复制的原理有所了解,IT技术网数据库的操作都会记录到binlog,如下图所示,
图片
1,从数据库(slave)会启动两个线程io_thread 和sql_thread ,通过io_thread将自身与主数据库(master)建立连接。
2,slave向master发出要同步的位置信息(包含同步的文件名和偏移量),表示需要从该位置发起同步。
3,主数据库master 将位置点后的binlog发送给slave, slave获取到本地形成relay log(中转日志)。
4, 接着通过sql_thread解析relay log,执行sql。
从主从复制的过程可以看出,主从延迟时间是 在主库master执行sql的时间点到从库通过解析relay log 执行sql后的时间点之间的差值。如果应用程序能够在master写入数据后等待这么一段时间,再去slave读取,就能正确的读取出来数据了。
但是这个时间差值是不确定的,云南idc服务商究竟应用程序需要等待多久才去读取slave,就成了我们需要思考🤔的问题。
如何避免延迟期间的主从数据不一致
比起在写入数据后读取主库或者写入数据后sleep一段时间读取从库,我给出两个我觉得比较靠谱点的方法。
判断位点是否同步
第一种方法是通过等待slave 将master写入数据后的 binlog的位点同步完成再对slave进行读取。
每次修改型sql的执行会将master的binlog 的位点(日志偏移量)前移,如果在修改型sql执行完成后,能够获取到master的binlog 位点,并且在客户端阻塞等待slave同步该位点完毕,再从slave读取就可以了。
MYSQL中提供了一个函数select master_pos_wait(file, pos[, timeout]) 用于在slave上执行等待master节点上的位点同步完成,其中file,和pos是在master上的文件和位点,timeout 为了让master_pos_wait 函数在timeout秒内没有返回,则会直接触发超时返回。
返回结果解析,
返回结果正常情况下是一个大于0的整数,b2b供应网表示从pos位点开始完成了多少个事务。如果直接返回结果0,则说明在执行select master_pos_wait(file, pos[, timeout]) 时,位点已经同步完成。如果触发超时则返回-1。如果执行期间slave发生错误,则返回NULL。所以,在判断是否应该在写入数据后读从库的逻辑,我们可以这样来写,
1, 在master写入数据后立马执行 show master status,可以获取如下结果
图片
Pasted image 20240308162704.png
可以看到master的binlog文件名称以及位点。
2, 在slave上执行 select master_pos_wait(mysql-bin.232011,3129472,1);,如果1s内没有返回,则直接返回-1。
图片
3, 在上一步如果触发超时返回返回-1,则直接读取主库,如果是>=0 的值,则直接读取从库。
这样便能最大程度从从库读取数据。
判断GTID 是否同步
接着,我们来看下第二种方式,其实第二种方式和通过位点的方式类似,不同的是slave判断是否将数据同步完成的依据是看GTID的值。
什么是GTID值?GTID 的全称是 Global Transaction Identifier,全局事务 ID,是一个事务在提交的时候生成的,是这个事务的唯一标识。
MYSQL开启 GTID 模式的方式是 在启动一个 MySQL 实例的时候,加上参数 gtid_mode=on 和 enforce_gtid_cnotallow=on 。
每个事务是和GTID 值一一对应的,每个MYSQL实例会维护一个GTID 集合,来表示实例执行过的事务。
在slave节点上,通过show slave status 可以看到 GTID集合,如下图所示,
图片
Pasted image 20240308165622.png
Auto_Positinotallow=1 ,表示这对主备关系使用了 GTID 协议。Retrieved_Gtid_Set,是备库收到的所有日志的 GTID 集合。Executed_Gtid_Set,是备库所有已经执行完成的 GTID 集合。如果Executed_Gtid_Set 等于Retrieved_Gtid_Set 说明slave将从master那里获取到的binlog全部执行完毕。
在master节点执行 show master status,也能看到GTID集合,Executed_Gtid_Set 为master节点执行过的GTID集合。如下图所示,
图片
在GTID 模式下,从库slave从主库master取binlog的逻辑将不再是直接告诉master 要取的文件和位点了,而是由slave将自身的GTID集合告诉master。
master再结合自身的GTID集合,找出在master中有但是在slave中没有的GTID集合,然后从binlog中找到第一个不在GTID集合中的事务,从该事务的binlog位点开始,往后读取binlog发送给slave。
MYSQL针对于GTID同样提供 了一个函数select wait_for_executed_gtid_set(gtid_set, 1); 来让slave去判断对master执行过的gtid_set 是否已经同步完成。
wait_for_executed_gtid_set 函数的返回结果解析如下,
如果slave 执行的事务中包含传入的 gtid_set,返回 0。如果等待1s后还没同步完成,则返回1。所以在GTID 模式下的,在判断是否应该在写入数据后读从库的逻辑,我们可以这样来写,
1, 在master写入数据后立马执行 show master status,可以获取如下结果
图片
可以看到master的Executed_Gtid_Set的值。
2, 在slave上执行
复制select wait_for_executed_gtid_set(76cd5ea1-c541-11ee-87ef-fa163eefe144:1-56382789, 808d2fb8-687b-11ec-b8b9-fa163e410530:1-144078103, 9081c19b-63de-11ed-9755-fa163eb8b97f:1-1093294115, 1);1.2.3.,如果1s内没有返回,则直接返回1。
图片
3, 在上一步如果触发超时即返回1,则直接读取主库,如果是=0 ,则直接读取从库。这样便能最大程度从从库读取数据。
相关文章
轻松掌握Windows10操作——以电脑ws10使用教程为主题(逐步学习ws10操作,提高电脑使用效率)
摘要:随着科技的不断进步,电脑已经成为我们日常生活和工作中必不可少的工具。而Windows10作为最新版本的操作系统,带来了更多实用的功能和更流畅的用户体验。然而,对于一些刚接触或不熟悉...2025-11-05- 摘要:红米4X作为小米旗下的一款入门级手机,以其卓越的性能和出色的价格性价比备受用户追捧。在本文中,我们将详细评测红米4X的性能、电池表现以及拍照表现,为大家带来全面的了解。...2025-11-05
- 摘要:随着科技的不断进步,个人电脑已成为现代生活中不可或缺的工具。而要让电脑发挥最佳性能,一个高效的处理器就显得至关重要。i57600处理器作为Intel第七代酷睿系列的成员之一,以其卓...2025-11-05
RX470海外版(探索RX470海外版的出色表现和超值特点)
摘要:近年来,随着电子竞技的兴起和游戏画质的迅速提升,显卡已成为许多玩家升级硬件的首选。RX470海外版作为一款中高端显卡,以其卓越的性能和超值的价格备受关注。本文将深入探讨RX470海...2025-11-05联想电脑新机使用教程(带你一步步了解联想电脑新机,让你成为电脑操作达人!)
摘要:随着科技的不断进步,联想推出了一款全新的电脑,为用户带来更快、更强大的性能和更好的使用体验。然而,对于一些新手用户来说,上手新机可能会遇到一些困惑和难题。本教程将带领大家逐步了解联...2025-11-05e52650CPU(解析e52650CPU的技术特点及应用领域)
摘要:e52650CPU是英特尔推出的一款高性能处理器,拥有强大的计算能力和稳定的性能表现。本文将从技术特点和应用领域两个方面对e52650CPU进行详细解析,帮助读者更好地了解该处理器...2025-11-05

最新评论