[Mysql]主从复制和读写分离

image

如何避免主从延迟?#

读写分离对于提升数据库的并发非常有效,但是,同时也会引来一个问题:主库和从库的数据存在延迟,比如你写完主库之后,主库的数据同步到从库是需要时间的,这个时间差就导致了主库和从库的数据不一致性问题。这也就是我们经常说的主从同步延迟

如果我们的业务场景无法容忍主从同步延迟的话,应该如何避免呢(注意:我这里说的是避免而不是减少延迟)?

这里提供两种我知道的方案(能力有限,欢迎补充),你可以根据自己的业务场景参考一下。

强制将读请求路由到主库处理#

既然你从库的数据过期了,那我就直接从主库读取嘛!这种方案虽然会增加主库的压力,但是,实现起来比较简单,也是我了解到的使用最多的一种方式。

比如 Sharding-JDBC 就是采用的这种方案。通过使用 Sharding-JDBC 的 HintManager 分片键值管理器,我们可以强制使用主库。

HintManager hintManager = HintManager.getInstance();
hintManager.setMasterRouteOnly();
// 继续JDBC操作

对于这种方案,你可以将那些必须获取最新数据的读请求都交给主库处理。

延迟读取#

还有一些朋友肯定会想既然主从同步存在延迟,那我就在延迟之后读取啊,比如主从同步延迟 0.5s,那我就 1s 之后再读取数据。这样多方便啊!方便是方便,但是也很扯淡。

不过,如果你是这样设计业务流程就会好很多:对于一些对数据比较敏感的场景,你可以在完成写请求之后,避免立即进行请求操作。比如你支付成功之后,跳转到一个支付成功的页面,当你点击返回之后才返回自己的账户。

数据同步写入从库#

主从复制模式,一般都是异步写数据到从库,当然这个异步也可以设置为同步,只有当从库写完成,主库上的写请求才能返回。
这种方案是最佳单也是最有效的一种,但也是性能最差的一种,尤其是有大量从库的情况下,严重影响请求效率。

缓存(中间件)路由法#

写请求时缓存记录一个key,这个key的失效时间设置为主从同步的延时,读请求的时候先去缓存中确认是否存在key,如果key存在说明发生了写请求,数据未同步到从库,这时走主库即可,若不存在这个key,直接走从库的查询即可。
中间件应该也是可以判断是否同步完成,与使用缓存记录类似。
这种方案最大的弊端是引入了缓存,系统复杂度上升。

选择性强制读主库#

对于一些特殊的业务场景,采用强制读主库。
弊端,需要把每一个这种情况都找出来,设置成强制走主库。

等GTID 方案#

MySQL 在执行完事务后,会将该事务的 GTID 会给客户端,然后客户端可以使用该命令去要执行读操作的从库中执行,等待该 GTID,等待成功后,再执行读操作;如果等待超时,则去主库执行读操作,或者再换一个从库执行上述流程。
MariaDB 的 MaxScale 就是使用该方案,MaxScale 是 MariaDB 开发的一个数据库智能代理服务(也支持 MySQL),允许根据数据库 SQL 语句将请求转向目标一个到多个服务器,可设定各种复杂程度的转向规则。

总结#

关于如何避免主从延迟,我们这里介绍了两种方案。实际上,延迟读取这种方案没办法完全避免主从延迟,只能说可以减少出现延迟的概率而已,实际项目中一般不会使用。

总的来说,要想不出现延迟问题,一般还是要强制将那些必须获取最新数据的读请求都交给主库处理。如果你的项目的大部分业务场景对数据准确性要求不是那么高的话,这种方案还是可以选择的。

什么情况下会出现主从延迟?如何尽量减少延迟?

我们在上面的内容中也提到了主从延迟以及避免主从延迟的方法,这里我们再来详细分析一下主从延迟出现的原因以及应该如何尽量减少主从延迟。

要搞懂什么情况下会出现主从延迟,我们需要先搞懂什么是主从延迟。

MySQL 主从同步延时是指从库的数据落后于主库的数据,这种情况可能由以下两个原因造成:

  • 从库 I/O 线程接收 binlog 的速度跟不上主库写入 binlog 的速度,导致从库 relay log 的数据滞后于主库 binlog 的数据;
  • 从库 SQL 线程执行 relay log 的速度跟不上从库 I/O 线程接收 binlog 的速度,导致从库的数据滞后于从库 relay log 的数据。

与主从同步有关的时间点主要有 3 个:

  • 主库执行完一个事务,写入 binlog,将这个时刻记为 T1;
  • 从库 I/O 线程接收到 binlog 并写入 relay log 的时刻记为 T2;
  • 从库 SQL 线程读取 relay log 同步数据本地的时刻记为 T3。

结合我们上面讲到的主从复制原理,可以得出:

  • T2 和 T1 的差值反映了从库 I/O 线程的性能和网络传输的效率,这个差值越小说明从库 I/O 线程的性能和网络传输效率越高。
  • T3 和 T2 的差值反映了从库 SQL 线程执行的速度,这个差值越小,说明从库 SQL 线程执行速度越快。

那什么情况下会出现出从延迟呢?这里列举几种常见的情况:

从库机器性能比主库差:从库接收 binlog 并写入 relay log 以及执行 SQL 语句的速度会比较慢(也就是 T2-T1 和 T3-T2 的值会较大),进而导致延迟。解决方法是选择与主库一样规格或更高规格的机器作为从库,或者对从库进行性能优化,比如调整参数、增加缓存、使用 SSD 等。

从库处理的读请求过多:从库需要执行主库的所有写操作,同时还要响应读请求,如果读请求过多,会占用从库的 CPU、内存、网络等资源,影响从库的复制效率(也就是 T2-T1 和 T3-T2 的值会较大,和前一种情况类似)。解决方法是引入缓存(推荐)、使用一主多从的架构,将读请求分散到不同的从库,或者使用其他系统来提供查询的能力,比如将 binlog 接入到 Hadoop、Elasticsearch 等系统中。

大事务:运行时间比较长,长时间未提交的事务就可以称为大事务。由于大事务执行时间长,并且从库上的大事务会比主库上的大事务花费更多的时间和资源,因此非常容易造成主从延迟。解决办法是避免大批量修改数据,尽量分批进行。类似的情况还有执行时间较长的慢 SQL ,实际项目遇到慢 SQL 应该进行优化。

从库太多:主库需要将 binlog 同步到所有的从库,如果从库数量太多,会增加同步的时间和开销(也就是 T2-T1 的值会比较大,但这里是因为主库同步压力大导致的)。解决方案是减少从库的数量,或者将从库分为不同的层级,让上层的从库再同步给下层的从库,减少主库的压力。

网络延迟:如果主从之间的网络传输速度慢,或者出现丢包、抖动等问题,那么就会影响 binlog 的传输效率,导致从库延迟。解决方法是优化网络环境,比如提升带宽、降低延迟、增加稳定性等。

单线程复制:MySQL5.5 及之前,只支持单线程复制。为了优化复制性能,MySQL 5.6 引入了 多线程复制,MySQL 5.7 还进一步完善了多线程复制。

复制模式:MySQL 默认的复制是异步的,必然会存在延迟问题。全同步复制不存在延迟问题,但性能太差了。半同步复制是一种折中方案,相对于异步复制,半同步复制提高了数据的安全性,减少了主从延迟(还是有一定程度的延迟)。MySQL 5.5 开始,MySQL 以插件的形式支持 semi-sync 半同步复制。并且,MySQL 5.7 引入了 增强半同步复制 。

作者:Esofar

出处:https://www.cnblogs.com/DCFV/p/18318659

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Duancf  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示