MySQL数据同步到 Redis 缓存的几种方法
创始人
2024-06-03 17:22:53
0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4 延迟双删

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

  1. 执行更新sql

  1. 延迟一段时间

  1. 再次删除redis的数据

// 延迟双删伪代码
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 延迟双写

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

上述代码缺陷;

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

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

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

上述代码改正:

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

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

6 总结

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

相关内容

热门资讯

变形记六年级作文(实用6篇) 变形记六年级作文 篇一我的变形记之旅我是一个普通的小学六年级学生,最近我读了一本引人入胜的小说《变形...
我是小农夫小学六年级记叙文(... 我是小农夫小学六年级记叙文 篇一我是小农夫我是一个小农夫,今年上小学六年级。在我家乡的小村庄里,大家...
采茶姑娘六年级作文【实用5篇... 采茶姑娘六年级作文 篇一茶园里的孩子们我家住在一个美丽的小山村,村子周围都是茶园。每年的春天,当茶叶...
我的假期生活六年级作文【优秀... 我的假期生活六年级作文 篇一我喜欢的假期活动假期对于学生来说,是一段宝贵的时间。在假期里,我可以尽情...
地球的自述六年级作文500字... 篇一:地球的自述你好,我是地球,这是我第一次向你们自述。作为宇宙中唯一一个有生命存在的行星,我感到非...
泪作文600字六年级(优秀6... 泪作文600字六年级 篇一:泪水中的勇敢泪水是我们内心的一种表达,它可以是喜悦的泪水,也可以是悲伤的...
六年级上册第一单元作文500... 六年级上册第一单元作文500字 篇一我的暑假生活暑假到了,我迫不及待地开始了我的暑假生活。这个暑假,...
小动物三年级作文300字【经... 小动物三年级作文300字 篇一我喜欢小动物我是一个小动物爱好者,我喜欢各种各样的小动物。我觉得它们都...
秋韵六年级作文【经典6篇】 秋韵六年级作文 篇一我与秋天的邂逅秋天是一个美丽的季节,它给大地披上了五彩斑斓的外衣。我喜欢秋天,因...
功夫不负有心人作文(优秀3篇... 功夫不负有心人作文 篇一在人生的道路上,我们常常会遇到各种各样的困难和挑战。然而,只要我们拥有一颗有...
三年级作文做家务200字左右... 三年级作文做家务200字左右 篇一帮助家人,乐在其中家务是我们生活中不可避免的一部分,也是我们孝敬父...
三年级作文254字(精彩6篇... 三年级作文254字 篇一最喜欢的动物我最喜欢的动物是猫。猫是一种非常可爱的动物,它们有着柔软的皮毛和...
小学三年级描写玫瑰花的作文【... 小学三年级描写玫瑰花的作文 篇一玫瑰花是我最喜欢的花之一。它是世界上最美丽的花朵之一,被誉为“花中皇...
三年级暑假作文:夏夜(经典6... 三年级暑假作文:夏夜 篇一夏夜的星空夏夜的星空美得像一幅画。当太阳落下地平线,天空渐渐暗下来的时候,...
三年级作文《可爱的小狗》(最... 三年级作文《可爱的小狗》 篇一可爱的小狗小狗是一种非常可爱的动物。它们有着软软的毛发和圆圆的大眼睛,...
我们的学校三年级作文六十个字... 我们的学校三年级作文六十个字 篇一我们的学校很美丽。校园里有很多树木和鲜花,四季都有不同的景色。教室...
美丽的海底世界三年级作文40... 篇一:美丽的海底世界海底世界真是美丽极了!在这里,我看到了各种各样奇特的鱼儿和珊瑚。我最喜欢的就是小...
三年级作文《有趣的游戏》范文... 三年级作文《有趣的游戏》范文 篇一有趣的游戏大家好!我是小明,今天我要给大家介绍一个非常有趣的游戏—...
小学三年级作文假期的生活50... 小学三年级作文假期的生活500字 篇一假期的生活假期来临了,我可是兴奋得不得了。因为这段时间,我可以...
三年级作文姥姥家的葡萄树【优... 三年级作文姥姥家的葡萄树 篇一姥姥家的葡萄树我家住在一个小镇上,每年暑假,我都会去姥姥家玩。姥姥家有...