Mysql读写分离过期常用解决方案

所属分类: 数据库 / Mysql 阅读数: 309
收藏 0 赞 0 分享

mysql读写分离的坑

读写分离的主要目标是分摊主库的压力,由客户端选择后端数据库进行查询。还有种架构就是在MYSQL和客户端之间有一个中间代理层proxy,客户端之连接proxy,由proxy根据请求类型和上下文决定请求的分发路由。

  • 客户端直连方案:因为少了一层proxy转发,所以查询性能稍微好一点儿,并且整体架构简单,排查问题更方便。但是这种方案,由于要了解后端部署细节,所以在出现主备切换、库迁移等操作的时候,客户端都会感知到,并且需要调整数据库连接信息。
  • 带proxy架构:对客户端比较友好。客户端不需要关注后端细节,连接维护、后端信息维护等工作,都是由proxy完成的。但这样的话,对后端维护团队的要求会更高。

无论使用哪种架构,由于主从可能存在延迟,客户端执行完一个更新事务后马上发起查询,如果查询选择的是从库的话,就有可能读到刚刚的事务更新之前的状态。这种“在从库上会读到系统的一个过期状态”的现象,我们暂且称之为“过期读”。

方案一:强制走主库方案

将查询请求分为两类:

  • 对于必须要拿到最新结果的请求,强制将其发到主库上。比如,在一个交易平台上,卖家发布商品以后,马上要返回主页面,看商品是否发布成功。那么,这个请求需要拿到最新的结果,就必须走主库。
  • 对于可以读到旧数据的请求,才将其发到从库上。在这个交易平台上,买家来逛商铺页面,就算晚几秒看到最新发布的商品,也是可以接受的。那么,这类请求就可以走从库。这个方案的最大问题在于会碰到所有查询都不是“过期读”的需求,比如金融类业务,这样就要放弃读写分离,所有的压力都在主库。采用以下方案。

方案二:Sleep方案

主库更新后,读从库之前先sleep一下,类似执行了select sleep(1)命令,这个方案的假设是,大多数情况下主备延迟在1秒之内,做一个sleep可以有很大概率拿到最新的数据。

以卖家发布商品为例,商品发布后,用Ajax直接把客户端输入的内容作为“新的商品”显示在页面上,而不是真正地去数据库做查询。这样,卖家就可以通过这个显示,来确认产品已经发布成功了。等到卖家再刷新页面,去查看商品的时候,其实已经过了一段时间,也就达到了sleep的目的,进而也就解决了过期读的问题。

方案三:判断主备无延迟方案:

第一种方法:先用show slave status结果里的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(全局事物ID)确保主备无延迟

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

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

方案四:等主库位点方案

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

这条命令是在从库执行的 ,参数file和pos指的是主库上的文件名和位置,timeout表示这个函数最多等待N秒。

  • 这个命令正常返回的结果是一个正整数M,表示从命令开始执行,到应用完file和pos表示的binlog位置,执行了多少事务。
  • 如果备库同步线程发生异常,则返回null
  • 如果等待超过N秒,就返回-1
  • 如果刚开始执行就发现已经执行过了,则返回0

如图:先执行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到主库执行查询语句,是这类方案常用的退化机制。因为从库的延迟时间不可控,不能无
限等待,所以如果等待超时,就应该放弃,然后到主库去查。按照我们设定不允许过期读的要求,就只有两种选择,一种是超时放弃,一种是转到主库查询。

并发连接和并发查询

innodb_thread_concurrency参数是控制innodb的并发线程上限。一旦超过这个数值,新请求就会进入等待。

  • show processlist看到的几千个连接,是值并发连接,而当前正在执行的语句,才是并发查询。并发连接影响不大,只是会多占内存,而并发查询才是CPU杀手。
  • 在线程进入锁等待以后,并发线程的计数会建议,也就是等行锁的线程是不算在并发查询里的。因为所等待已经不吃CPU了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

MySQL中按照多字段排序及问题解决

这篇文章主要介绍了MySQL中按照多字段排序及问题解决的方法,非常的实用,有需要的小伙伴可以参考下。
收藏 0 赞 0 分享

MySQL外键使用详解

两天有人问mysql中如何加外键,今天抽时间总结一下。mysql中MyISAM和InnoDB存储引擎都支持外键(foreign key),但是MyISAM只能支持语法,却不能实际使用。
收藏 0 赞 0 分享

Mysql中LAST_INSERT_ID()的函数使用详解

从名字可以看出,LAST_INSERT_ID即为最后插入的ID值,有了这个实用的函数,我们可以实现很多问题,下面我们就来深入探讨下。
收藏 0 赞 0 分享

MySql insert插入操作的3个小技巧分享

这篇文章主要介绍了MySql insert插入操作的3个小技巧分享,本文讲解了插入的数据来源自其他表、插入时排除(忽略)重复记录、插入时遇到重复记录做更新操作三个小技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

mysql修改自增长主键int类型为char类型示例

这篇文章主要介绍了mysql修改自增长主键int类型为char类型示例,需要的朋友可以参考下
收藏 0 赞 0 分享

Windows下使用Cygwin编译MySQL客户端

这篇文章主要介绍了Windows下使用Cygwin编译MySQL客户端,本文详细的讲解了编译过程,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL数据库优化推荐的编译安装参数小结

这篇文章主要介绍了MySQL数据库优化推荐的编译安装参数小结,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL之Field‘***’doesn’t have a default value错误解决办法

这篇文章主要介绍了MySQL之Field‘***’doesn’t have a default value错误解决办法,需要的朋友可以参考下
收藏 0 赞 0 分享

php连接MySQL的两种方式对比

这篇文章主要介绍了php连接MySQL的两种方式对比,一种是原生的链接方式另外一种是PDO方式,附上示例,推荐给大家,有需要的小伙伴可以参考下
收藏 0 赞 0 分享

Mysql InnoDB删除数据后释放磁盘空间的方法

这篇文章主要介绍了Mysql InnoDB删除数据后释放磁盘空间的方法,Innodb数据库对于已经删除的数据只是标记为删除,并不真正释放所占用的磁盘空间,这就导致InnoDB数据库文件不断增长,本文就讲解释放磁盘空间的方法,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多