MySQL|京东二面:MySQL 主从延迟,读写分离 7 种解决方案

MySQL|京东二面:MySQL 主从延迟,读写分离 7 种解决方案

文章图片

MySQL|京东二面:MySQL 主从延迟,读写分离 7 种解决方案

文章图片

MySQL|京东二面:MySQL 主从延迟,读写分离 7 种解决方案

我们都知道互联网数据有个特性 , 大部分场景都是读多写少 , 比如:微博、微信、淘宝电商 , 按照二八原则 , 读流量占比甚至能达到 90%
结合这个特性 , 我们对底层的数据库架构也会做相应调整 。 采用读写分离

处理过程:

  • 客户端会集成 SDK , 每次执行 SQL 时 , 会判断是写或读操作
  • 如果是写SQL , 请求会发到主库
  • 主数据库执行SQL , 事务提交后 , 会生成binlog , 并同步给从库
  • 从库通过 SQL 线程回放binlog , 并在从库表中生成相应数据
  • 读 负载均衡 从库
看似非常合理 , 细想却不是那么回事
主库与从库是采用异步复制数据 , 如果这两者之间数据还没有同步怎么办?
主库刚写完数据 , 从库还没来得及拉取最新数据 , 读请求就来了 , 给用户的感觉 , 数据丢了???

针对这个问题 , 今天 , 我们就来探讨下有什么解决方案?
一、强制走主库针对不用的业务诉求 , 区别性对待
场景一:如果是对数据的实时性要求不是很高 , 比如:大V有千万粉丝 , 发布一条微博 , 粉丝晚几秒钟收到这条信息 , 并不会有特别大的影响 。 这时 , 可以走从库 。
场景二:如果对数据的实时性要求非常高 , 比如金融类业务 。 我们可以在客户端代码标记下 , 让查询强制走主库 。
二、从库延迟查询由于主从库之间数据同步需要一定的时间间隔 , 那么有一种策略是延迟从从库查询数据 。
比如:
select sleep(1)select * from order where order_id=11111;

在正式的业务查询时 , 先执行一个sleep 语句 , 给从库预留一定的数据同步缓冲期 。
因为是采用一刀切 , 当面对高并发业务场景时 , 性能会下降的非常厉害 , 一般不推荐这个方案 。
三、判断主从是否延迟?决定选主库还是从库之前写过一篇文章 《京东一面:MySQL 主备延迟有哪些坑?主备切换策略 》
有讲过 什么是主备延迟? 、 主备延迟的常见原因?
方案一:在从库 执行 命令 show slave status
查看 seconds_behind_master 的值 , 单位为秒 , 如果为 0 , 表示主备库之间无延迟
方案二:比较主从库的文件点位
还是执行 show slave status  , 响应结果里有截个关键参数
  • Master_Log_File 读到的主库最新文件
  • Read_Master_Log_Pos 读到的主库最新文件的坐标位置
  • Relay_Master_Log_File 从库执行到的最新文件
  • Exec_Master_Log_Pos 从库执行到的最新文件的坐标位置
两两比较 , 上面的参数是否相等
方案三:比较 GTID 集合
  • Auto_Position=1 主从之间使用 GTID 协议
  • Retrieved_Gtid_Set 从库收到的所有binlog日志的 GTID 集合
  • Executed_Gtid_Set 从库已经执行完成的 GTID 集合
比较 Retrieved_Gtid_Set 和 Executed_Gtid_Set 的值是否相等
在执行业务SQL操作时 , 先判断从库是否已经同步最新数据 。 从而决定是操作主库 , 还是操作从库 。
缺点:无论采用上面哪一种方案 , 如果主库的写操作频繁不断 , 那么从库的值永远跟不上主库的值 , 那么读流量永远是打在了主库上 。
针对这个问题 , 有什么解决方案?这个问题跟 MQ消息队列 既要求高吞吐量又要保证顺序是一样的 , 从全局来看确实无解 , 但是缩小范围就容易多了 , 我们可以保证一个分区内的消息有序 。
回到 主从库 之间的数据同步问题 , 从库查询哪条记录 , 我们只要保证之前对应的写binglog已经同步完数据即可 , 可以不用管主从库的所有的事务binlog 是否同步 。
问题是不是一下简单多了

四、从库节点判断主库位点在从库执行下面命令 , 返回是一个正整数 M , 表示从库从参数节点开始执行了多少个事务
select master_pos_wait(file pos[ timeout
);