当前位置: 首页 > 科技观察

MySQL主从延迟,读写分离七大解决方案

时间:2023-03-14 00:26:27 科技观察

大家好,我是Tom。我们都知道互联网数据有一个特点。大多数场景都是读多写少,比如微博、微信、淘宝电商。根据第28原则,阅读流量的比例甚至可以达到90%。结合这个特性,我们也会对底层的数据库架构做相应的调整。使用读写分离。处理过程:客户端会集成SDK,每次执行SQL都会判断是写操作还是读操作。如果是写SQL,请求会发到主库。主库执行SQL,事务提交后生成binlog同步到从库。从库通过SQL线程回放binlog,并在从库表中生成相应的数据。如果是读SQL,请求会经过负载均衡策略,选择一个从库处理用户请求。看起来很有道理,但仔细想想却不是这样。主库和从库采用异步数据复制。如果两者之间的数据不同步怎么办?主库刚写完数据,从库还没来得及拉取最新的数据。读取请求来了。感觉数据丢失了?为了解决这个问题,今天,我们来讨论一下解决方案是什么?1.强制主库区别对待未使用的业务需求。场景一:如果对实时数据的要求不是很高,比如一个大V有几千万的粉丝,他发了一条微博,几秒后粉丝会收到这条消息,这会不会有特别大的影响。这时候,你就可以出库了。场景二:如果对实时数据要求非常高,比如金融业务。我们可以让查询强制主库在客户端代码标签下。2、延迟从库查询由于主从数据库之间的数据同步需要一定的时间间隔,所以有一种延迟从库查询数据的策略。例如:selectsleep(1)select*fromorderwhereorder_id=11111;在正式的业务查询中,先执行一条sleep语句,为从库预留一定的数据同步缓冲期。因为它采用的是一刀切的方案,在面对高并发的业务场景时,性能会下降的很厉害,一般不推荐这种方案。3、判断主从??是否延时?在决定选择主库还是从库之前,我写了一篇文章《京东一面:MySQL 主备延迟有哪些坑?主备切换策略 》。有没有讲过什么是主从延时?主从延迟的常见原因?方案一:在从库中执行命令showslavestatus。查看seconds_behind_master的值,单位是秒,如果是0,说明主备之间没有延迟。方案二:对比主从库的文件点。还是执行showslavestatus,响应结果中有关键参数。Master_Log_File读取的主库最新文件。Read_Master_Log_Pos读取的主库中最新文件的坐标位置。Relay_Master_Log_File从库中执行的最新文件。Exec_Master_Log_Pos从库中执行的最新文件的坐标位置。两两比较,以上参数是否相等。解决方案3:比较GTID集。Auto_Position=1在主从之间使用GTID协议。Retrieved_Gtid_Set从库接收到的所有binlog日志的GTID集合。Executed_Gtid_Set已从库中执行的GTID的集合。比较Retrieved_Gtid_Set和Executed_Gtid_Set的值是否相等。在进行业务SQL操作时,首先判断是否从数据库同步了最新的数据。从而决定是操作主库还是从库。缺点:无论采用以上哪种方案,如果主库的写操作频繁,从库的值永远跟不上主库的值,所以读流量总是打到主库上图书馆。这个问题的解决方案是什么?这个问题和MQ消息队列一样,既要高吞吐又要保证顺序。从全局来看,确实没有解决办法,但缩小范围就容易多了。我们可以保证一个分区内的消息是有序的。回到主从数据库的数据同步问题,从数据库中查询哪条记录,我们只需要保证对应写入的binglog已经同步数据即可,不需要关心所有的事务是否主从数据库的binlog是同步的。问题并不那么简单。4、从库节点判断主库站点在从库执行了如下命令,返回一个正整数M,表示从库从参数节点执行了多少笔交易。选择master_pos_wait(文件,pos[,超时]);file和pos代表主库上的文件名和位置。timeout是可选的,表示这个函数最多等待N秒。缺点:master_pos_wait返回的结果无法关联到具体操作的数据行,所以每次收到读请求,从库仍然无法确认数据是否已经同步,解决方案不是很实用。5.比较GTID执行下面的查询命令。等待直到从库中执行的事务包括gtid_set,返回0。超时,返回1。选择wait_for_executed_gtid_set(gtid_set,1);从MySQL5.7.6版本开始,允许在执行更新事务后,将本次事务的GTID返回给客户端。具体操作,设置参数session_track_gtids为OWN_GTID,调用API接口mysql_session_track_get_first从返回结果中解析出GTID。处理流程:发起一个写SQL操作,主库执行成功后返回本次事务的GTID。发起读SQL操作时,先执行selectwait_for_executed_gtid_set(gtid_set,1)fromlibrary。如果返回0,表示已经从数据库同步数据,可以对从库进行查询操作。否则,在主数据库上执行查询操作。缺点:和上面的master_pos_wait类似,如果写操作没有和读操作关联的context,那么GTID就传不过去。该程序不是很实用。6.引入缓存中间件高并发系统。缓存作为一种性能优化工具,被广泛使用。我们可以考虑引入缓存作为缓冲介质。处理过程:客户端编写SQL操作主数据库。同步删除缓存中的数据。当客户端读取数据时,它首先从缓存中加载。如果缓存中没有,它会强制查询主数据库来预热数据。缺点:K-V存储,适合一些简单的查询条件场景。对于复杂的查询,还是需要查询从库。7、数据分片是指RedisCluster模式。集群网络拓扑通常是3主3从。主节点负责写入和读取。通过水平分片支持数据的水平扩展。由于每个节点都是一个独立的服务器,因此可以提高整个集群的吞吐量。转换为数据库的常见解决方案是分库分表。每次读写都是对主库的一个分表进行操作,分库只是用于数据备份。当主库出现故障时,通过主从切换保证集群的高可用。