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

我们都知道互联网数据有个特性,大部分场景都是 读多写少,比如:微博、微信、淘宝电商,按照 二八原则,读流量占比甚至能达到 90%

结合这个特性,我们对底层的数据库架构也会做相应调整。采用 读写分离

7cf4f33d7a91bb9d1ad2789321632f2e.png

处理过程:

  • 客户端会集成 SDK,每次执行 SQL 时,会判断是 操作

  • 如果是 SQL,请求会发到 主库

  • 主数据库执行SQL,事务提交后,会生成 binlog ,并同步给 从库

  • 从库 通过 SQL 线程回放 binlog ,并在从库表中生成相应数据

  • 如果是 SQL,请求会通过 负载均衡 策略,挑选一个 从库 处理用户请求

看似非常合理,细想却不是那么回事

主库从库 是采用异步复制数据,如果这两者之间数据还没有同步怎么办?

主库刚写完数据,从库还没来得及拉取最新数据, 请求就来了,给用户的感觉,数据丢了???

eded9fff9d17593a08ba08ae95ed9ceb.png

针对这个问题,今天,我们就来探讨下有什么解决方案?

一、强制走主库

针对不用的业务诉求,区别性对待

场景一:

如果是对数据的 实时性 要求不是很高,比如:大V有千万粉丝,发布一条微博,粉丝晚几秒钟收到这条信息,并不会有特别大的影响。这时,可以走 从库

场景二:

如果对数据的 实时性 要求非常高,比如金融类业务。我们可以在客户端代码标记下,让查询强制走主库。

二、从库延迟查询

由于主从库之间数据同步需要一定的时间间隔,那么有一种策略是延迟从从库查询数据。

比如:

select sleep(1)
select * from order where order_id=11111;

在正式的业务查询时,先执行一个sleep 语句,给从库预留一定的数据同步缓冲期。

因为是采用一刀切,当面对高并发业务场景时,性能会下降的非常厉害,一般不推荐这个方案。

三、判断主从是否延迟?决定选主库还是从库

方案一:

在从库 执行 命令 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_SetExecuted_Gtid_Set 的值是否相等

在执行业务SQL操作时,先判断从库是否已经同步最新数据。从而决定是操作主库,还是操作从库。

缺点:

无论采用上面哪一种方案,如果主库的写操作频繁不断,那么从库的值永远跟不上主库的值,那么读流量永远是打在了主库上。

针对这个问题,有什么解决方案?

这个问题跟 MQ消息队列 既要求高吞吐量又要保证顺序是一样的,从全局来看确实无解,但是缩小范围就容易多了,我们可以保证一个分区内的消息有序。

回到 主从库 之间的数据同步问题,从库查询哪条记录,我们只要保证之前对应的写binglog已经同步完数据即可,可以不用管主从库的所有的事务binlog 是否同步。

问题是不是一下简单多了

46caecd0a46f3c1ffb73d4eb6ab14c0c.png

四、从库节点判断主库位点

在从库执行下面命令,返回是一个正整数 M,表示从库从参数节点开始执行了多少个事务

select master_pos_wait(file, pos[, timeout]);
  • file 和 pos 表示主库上的文件名和位置

  • timeout 可选, 表示这个函数最多等待 N 秒

缺点:

master_pos_wait 返回结果无法与具体操作的数据行做关联,所以每次接收读请求时,从库还是无法确认是否已经同步数据,方案实用性不高。

五、比较 GTID

执行下面查询命令

  • 阻塞等待,直到从库执行的事务中包含 gtid_set,返回 0

  • 超时,返回 1

select wait_for_executed_gtid_set(gtid_set, 1);

MySQL 5.7.6 版本开始,允许在执行完更新类事务后,把这个事务的 GTID 返回给客户端。具体操作,将参数session_track_gtids 设置为OWN_GTID,调用 API 接口mysql_session_track_get_first 返回结果解析出 GTID

处理流程:

  • 发起 SQL 操作,在主库成功执行后,返回这个事务的 GTID

  • 发起 SQL 操作时,先在从库执行 select wait_for_executed_gtid_set (gtid_set, 1)

  • 如果返回 0,表示已经从库已经同步了数据,可以在从库执行 查询 操作

  • 否则,在主库执行 查询 操作

缺点:

跟上面的 master_pos_wait 类似,如果 写操作读操作 没有上下文关联,那么 GTID 无法传递 。方案实用性不高。

六、引入缓存中间件

a88270c94c72697103162abee571dc50.png

高并发系统,缓存作为性能优化利器,应用广泛。我们可以考虑引入缓存作为缓冲介质

处理过程:

  • 客户端 SQL ,操作主库

  • 同步将缓存中的数据删除

  • 当客户端读数据时,优先从缓存加载

  • 如果 缓存中没有,会强制查询主库预热数据

缺点:

K-V 存储,适用一些简单的查询条件场景。如果复杂的查询,还是要查询从库。

七、数据分片

ea6b76a4117c99c4bbd82b1dc6146bec.png

参考 Redis Cluster 模式, 集群网络拓扑通常是 3主 3从,主节点既负责写,也负责读。

通过水平分片,支持数据的横向扩展。由于每个节点都是独立的服务器,可以提高整体集群的吞吐量。

转换到数据库方面

常见的解决方式,是分库分表,每次读写都是操作主库的一个分表,从库只用来做数据备份。当主库发生故障时,主从切换,保证集群的高可用性。

ce86c37ffc042c5a9eb12e0a48ef684c.gif

往期推荐

e2bb75f85cd0a45f6f6f380fb7ffd1bd.png

Spring官方推荐的@Transactional还能导致生产事故?


f4380a64afc6dd5572848b75352fc093.png

Objects.equals有坑


4854e75a4c0cd3e66ae8e04193e9fb1f.png

为什么创建线程池一定要用ThreadPoolExecutor?


8b361da28a43d10cf5fb1997fa01d1d9.gif

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

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

相关文章

array_keys_PHP array_keys()函数与示例

array_keysPHP array_keys()函数 (PHP array_keys() function) array_keys() function is used to get the keys of an array, it accepts an array as an argument and returns a new array containing keys. array_keys()函数用于获取数组的键,它接受一个数组作为…

再见Postman,这款API神器更好用!

代码未动,文档先行其实大家都知道 API 文档先行的重要性,但是在实践过程中往往会遇到很多困难。程序员最讨厌的两件事:1. 写文档,2. 别人不写文档。大多数开发人员不愿意写 API 文档的原因是写文档短期收益远低于付出的成本&#…

strtolower_PHP strtolower()函数与示例

strtolowerPHP strtolower()函数 (PHP strtolower() function) strtolower() function is a string function, it accepts the string and returns an lowercase string. strtolower()函数是一个字符串函数,它接受该字符串并返回小写字符串。 Syntax: 句法&#xf…

如何保证数据库和缓存双写一致性?

前言数据库和缓存(比如:redis)双写数据一致性问题,是一个跟开发语言无关的公共问题。尤其在高并发的场景下,这个问题变得更加严重。我很负责的告诉大家,该问题无论在面试,还是工作中遇到的概率非…

面试官:AtomicInteger是如何保证线程安全?

blog.csdn.net/nanhuaibeian/article/details/120936139一、为什么引入 AtomicInteger ?谈到线程安全,会首先想到了synchronized 和 Lock,但是这种方式又有一个名字,叫做互斥锁,一次只能有一个持有锁的线程进入,再加上…

机器学习 训练验证测试_测试前验证| 机器学习

机器学习 训练验证测试In my previous article, we have discussed about the need to train and test our model and we wrote a code to split the given data into training and test sets. 在上一篇文章中,我们讨论了训练和测试模型的必要性,并编写了…

如何判断线程池已经执行完所有任务了?

作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)很多场景下,我们需要等待线程池的所有任务都执行完,然后再进行下一步操作。对于线程 Thread …

IRCTC的完整形式是什么?

IRCTC:印度铁路餐饮和旅游公司 (IRCTC: Indian Railways Catering and Tourism Corporation) IRCTC is an abbreviation of Indian Railways Catering and Tourism Corporation. It is a subsidiary of the Indian Railway established by the Ministry of Railways…

分布式锁的 3 种实现方案!

前言 大家好,我是磊哥。今天跟大家探讨一下分布式锁的设计与实现。希望对大家有帮助,如果有不正确的地方,欢迎指出,一起学习,一起进步哈~分布式锁概述数据库分布式锁Redis分布式锁Zookeeper分布式锁三种分布式锁对比1.…

java学习笔记16--异常

java学习笔记16--异常 异常 异常时导致程序中断运行的一种指令流,如果不对异常进行正确的处理,则可能导致程序的中断执行,造成不必要的损失, 所以在程序的设计中必须要考虑各种异常的发生,并正确的做好相应的处理&am…

ruby hash添加数据_如何在Ruby中向Hash添加元素?

ruby hash添加数据Before going through the ways to add elements to the hash instances, let us understand what could be called as a hash element. So, Hash is the collection of keys and their values. For example, 在介绍向哈希实例添加元素的方法之前,…

线程安全问题的 3 种解决方案!

作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)线程安全是指某个方法或某段代码,在多线程中能够正确的执行,不会出现数据不一致或数据污染的…

黑色30s高并发IIS设置

在这篇博文中,我们抛开对阿里云的怀疑,完全从ASP.NET的角度进行分析,看能不能找到针对问题现象的更合理的解释。 “黑色30秒”问题现象的主要特征是:排队的请求(Requests Queued)突增,到达HTTP.…

我们可以覆盖Java中的main()方法吗?

The question is that "Can we override main() method in Java?" 问题是“我们可以覆盖Java中的main()方法吗?” No, we cant override the main() method in java. 不,我们不能覆盖java中的main()方法 。 First, we will understand what …

一文读懂MySQL查询语句的执行过程

需要从数据库检索某些符合要求的数据,我们很容易写出 Select A B C FROM T WHERE ID XX 这样的SQL,那么当我们向数据库发送这样一个请求时,数据库到底做了什么?我们今天以MYSQL为例,揭示一下MySQL数据库的查询过程&a…

angularJS的$http.post请求,.net后台接收不到参数值的解决方案

JS通用部分var shoppingCartModule angular.module(starter, [ionic], function ($httpProvider) {// Use x-www-form-urlencoded Content-Type$httpProvider.defaults.headers.post[Content-Type] application/x-www-form-urlencoded;charsetutf-8;/*** The workhorse; conve…

带有示例的Python列表reverse()方法

列出reverse()方法 (List reverse() Method) reverse() method is used to reverse the elements of the list, the method is called with this list (list in which we have to reverse the elements) and it reverses all elements in the list. reverse()方法用于反转列表中…

复杂度O(n)倒转链表

1 public class ListNode {2 int val;3 ListNode next;4 ListNode(int x) { val x; }5 ListNode(){}6 7 public static ListNode revese(ListNode input)8 {9 ListNode head new ListNode();//头插法的头 10 ListNode cur in…

synchronized底层是如何实现的?

作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)想了解 synchronized 是如何运行的?就要先搞清楚 synchronized 是如何实现?synchronized 同步…

java sublist_Java Vector subList()方法与示例

java sublist向量类subList()方法 (Vector Class subList() method) subList() method is available in java.util package. subList()方法在java.util包中可用。 subList() method is used to return a set of sublist [it returns all those elements exists in a given rang…