浅谈MySQL数据同步到 Redis 缓存的几种方法

admin11个月前笔记104

image.png

1 Mysql查完数据,再同步写入到Redis中

缺点1:会对接口造成延迟,因为同步写入redis本身就有延迟,并且还要做重试,如果redis写入失败,还需要重试,那就更费时间了。

缺点2:不解耦,如果redis崩了,那直接卡线程了

缺点3:如果人为该数据库,那就没法同步了, 除非再人为删除对应的Redis,但删除Redis这个过程也有个时间差

2 Mysql查完数据,通过发送MQ,在消费者线程去同步Redis

缺点1:多了层MQ,也就是会有很大的概率导致同步延迟问题.

缺点2:要对MQ的可用性做预防

缺点3:如果人为该数据库,那就没法同步了

优点1:可以大幅减少接口的延迟返回的问题

优点2:MQ本身有重试机制,无需人工去写重试代码

优点3:解耦,把查询Mysql和同步Redis完全分离,互不干扰

3 订阅Mysql的Binlog文件(可借助Canal来进行)

CanalServer会伪装成MysqlServer从库,去订阅MysqlServer主库的Binlog文件

Canal启动的时候会配置对应的消息MQ(RabbitMQ, RocketMQ, Kafka), 监听到Binlog文件有变化是,会把变化的sql语句转换成json格式,并作为消息内容发送到MQ中

项目中只要监听对应MQ,就能拿到Binlog改动的内容,Json数据中有明确的操作类型(CURD), 以及对应的数据。把对应数据同步到redis即可

缺点1:canal订阅Binlog的整个操作过程是单线程的,所以面临超高并发的情况下,性能可能不太出色。当然可以部署多个Canal 与 多个消费者,但是要注意消息重复消费问题,做好幂等性校验

优点1:即使人为改数据库,也会监听到,并且也会同步

优点2:异步同步,不会对接口返回有格外延迟

4 延迟双删

在执行修改sql之前,先将redis的数据删除

执行更新sql

延迟一段时间

再次删除redis的数据

1
2
3
4
5
// 延迟双删伪代码
deleteRedisCache(key);   // 删除redis缓存
updateMysqlSql(obj);        // 更新mysql
Thread.sleep(100);           // 延迟一段时间
deleteRedisCache(key);   // 再次删除该key的缓存

缺点:这个延迟时间不好把控,到底延迟多久,这个很难去评估

扩展: 如果不使用延迟双删,仅仅是delete缓存,然后改mysql数据。只有这两步会出现什么问题呢?

5. 单个请求,单线程没问题,高并发多线程下会出问题

6. 如果Thread1线程要更新数据,此时Thread1线程把redis清理了

7. 此时Thread2线程来了,但Thread1还没有更新mysql完毕

8. Thread2查询redis肯定是null,此时Thread2就要查mysql了,然后再把查到的数据写到缓存

9. 由于Thread1还没来得及修改mysql数据,所以此时Thread2查出来的数据是【旧数据】,Thread2把旧数据又写入Redis 了

10. 此时Thread3线程来了,查询Redis发现有数据,则直接拿缓存数据了,此时【Thread3查出来的是旧数据】,直接带着旧数据返回了,这就是问题所在

11. 而延迟双删的第二次删除作用就是防止Thread2把旧数据又写入了,有了延迟双删,Thread3查询Redis的时候还是null,就会从mysql 去拿最新数据了

12. 所以正常的这个延迟时间,应该是Thread2查缓存到拿mysql数据,到再保存到redis这整个时间,作为Thread1的延迟时间,但是这个Thread2这个过程的时间会受到很多因素影响,因此很难断定究竟会是多久

5 延迟双写

1
2
3
// 延迟双写伪代码
updateMysqlSql(obj);        // 更新mysql
addRedis(key);   // 再次删除该key的缓存

上述代码缺陷;

  • 高并发下,两条线程同时执行上面代码,并对mysql 修改,且修改内容不通,可能会导致Redis与Mysql数据不一致

  • T1线程执行完updateMysqlSql,释放了行锁,此时T2线程再执行updateMysqlSql 与 addRedis, 最后T1执行addRedis,这种情况会导致数据库改成了T2线程的数据,但Redis却是T1线程的数据

优化

1
2
3
4
5
// 完美延迟双写伪代码
开启事务
updateMysqlSql(obj);        // 更新mysql
addRedis(key);   // 再次删除该key的缓存
提交事务

上述代码改正:

把两句代码放到一个事务里面,只有T1执行完Mysql 与 Redis的时候,T2才能开始执行,就可以保证数据一致性。推荐使用分布式锁

双写缺点:Mysql 与 Redis是单线程的。性能方面不行,因此不推荐使用

6 总结

推荐使用Canal的方式,进行异步同步。其次是MQ方式

到此这篇关于浅谈MySQL数据同步到 Redis 缓存的几种方法的文章就介绍到这了,更多相关MySQL数据同步到Redis缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!


相关文章

linux的网络服务功能—FTP、SSH和NFS

linux的网络服务功能—FTP、SSH和NFS

现在很多用linux进行开发的工程师,他们大多都是在windows系统上安装虚拟机,然后在虚拟机中安装linux系统,然后在里面完成项目的开发的。这种方式往往需要经常的和windows之间进行文件的传...

windows server VPN搭建(史上最简单易懂教程)

windows server VPN搭建(史上最简单易懂教程)

一、事前说明:1).VPN网络已开启NAT配置,客户端连接后本机公网地址会转换为VPN SERVER公网地址;2).目前server端支持多种VPN隧道协议(PPTP、L2TP、IPLec、SSLvp...

大神教你轻松驾驭Tomcat

大神教你轻松驾驭Tomcat

对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时...

ChatGPT保姆级教程,一分钟学会使用ChatGPT!

ChatGPT保姆级教程,一分钟学会使用ChatGPT!

一.准备工作和注册美区 Apple ID 一样的流程:挂个代理,伪装在日本、新加坡或者美国,建议新加坡;亲测香港是100%不可行的准备一个国外手机号,GoogleVoice 虚拟号会被识别,亲测不行,...

让你在终端输入密码时显示星号

让你在终端输入密码时显示星号

正如你在上面的图片中看到的,我已经输入了密码,但没有任何指示(星号或圆点符号)。现在,我不确定我是否输入了所有密码。这个安全机制也可以防止你附近的人猜测密码长度。当然,这种行为可以改变。这是本指南要说...

列出所有的 Bash Shell 内置命令

列出所有的 Bash Shell 内置命令

shell 内置命令就是一个命令或一个函数,从 shell 中调用,它直接在 shell 中执行。 bash shell 直接执行该命令而无需调用其他程序。你可以使用 help 命令查看 Bash 内...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。