如何解决 Redis 缓存与 MySQL 的数据一致性问题?

方法·3
回答·98
最热
最新
  • Canal 技术  模拟 MySQL 的是从服务器  根据主从复制机制来实现
  • 方式一:mysql 排他锁+分布式锁 方式二:分布式读写锁 方式三(不太可靠):canel 监听 mysql binglog 方式四(很不可靠):延迟双删
  • 要彻底解决一致性问题,旁路缓存模式就不可能,什么脱裤子放屁的延迟双删解决不了一致性问题,要严格一致,就要用读穿透写穿透模式,要最终一致,就用读穿透写延后模式。
  • 方案 1(普通) 读:读 redis,没有数据就读 mysql,将 MySQL 数据保存到缓存中。 写:写 mysql,同时让 redis 缓存失效(删除 key,过期) 缺点:数据量巨大,更新频繁的数据写入无能为力。比如数量巨大,每个变跟状态又很频繁,这样很容易把数据库写挂。 方案 2(binlog) 基于 binlog 使用 mysql_udf_redis,将数据库中的数据同步到 Redis。 缺点: mysql_udf_redis 是有人实现的同步数据到 Redis 的功能,需要学习成本,第三方的插件不稳定。 方案 3(MQ 或定时任务) MQ.队列同步,变跟数据 2 份,使用消息队列,一份给 Redis 消费,一份给 Mysql 消费。 定时任务 后台定时任务,定时刷新 Redis 中信息到数据库。 缺点:怎么保证到数据库和到 Redis 中的状态一致性。就是假设一条修改数据,从队列写入到 Mysql 成功,但是写入到 Redis 失败,这种如何搞。还有就是需要一个消息队列,使用第三方的比如 Kafka,RabbitMq 等来实现,管理起来不方便,系统整体稳定性不行,而且只是这么个比较小的箱格数据信息同步。有点杀鸡用牛刀
  • 第一种读:我们先从缓存中读取数据,若命中直接返回,否则查询数据库并将数据加入缓存中返回 第二种写:我们有 2 种情况: 1 先更新数据库再更新(删除)缓存 2 先更新(删除)缓存再更新数据库 分析第一种情况如果都是正常,一切都没问题 若更新数据库失败,直接抛出异常,若更新数据库成功,更新(删除)缓存失败,则会导致数据不一致 解决方案:1 增加锁,保证原子性                2 讲更新删除失败的 key 放入消息队列,再次消费,会有短暂的消失不一样 分析第二种情况 正常情况下,删除缓存成功,更新数据库成功 异常情况下,删除缓存失败,抛异常                   删除成功,数据库失败,再次读取还是老数据,数据一致 上述方案感觉完美解决了数据一致性问题,其实不然,高并发下也有问题 A 删除缓存成功 B 查询数据,缓存没命中,读取数据库老数据,缓存老数据,A 更新数据库成功,后面再查询都是老数据 解决方案,将删除缓存,更新数据库,查询数据做成串行化保证数据 3 使用 canal 订阅 binlog 日志
  • 我觉得既然用了缓存,那保证数据最终一致即可,允许一段时间内数据不一致。 如果强行保证缓存和 mysql 数据一致,延迟双删应该解决不了,用订阅 binlog 的方式可以实现。
  • 为什么没有人回答 先更新数据库再删缓存。。。比延时双删简单,出现问题的概率很小
  • 我觉得简单点, 挂上事物删了就结束了。
  • 看了好多延迟双删的回答…是不是要从一开始就思考,引入 redis 的目的是啥…大部分都是为了性能,抗流量吧…你把缓存删了,万一正好是个热点被删了,数据库不就打爆了么…
  • 当在业务逻辑中有新的增删改的时候设置一个标识符,并且设置过期时间为 mysql 到 redis 的缓存时间,放下次请求发生时去判断这个标识符是否存在,如果存在就去 mysql 中查询,如果不存在就在 redis 中查询。
  • 方案一:读写分离;方案二:队列存储请求;场景三:访问量大,处理器来不及处理,队列内的请求数量越来越高,则会影响查询效率;解决:分布式数据库集群,再加上消息队列(kafka等)。
    • 1

      读写分离

    • 2

      缓存队列

    • 3

      读写分离缓存队列

  • 订阅binlog
    • 1

      第一部

    • 2

      第二部

  • 只是写的我个人的解决方向,大家不喜欢也别喷😂,笑一下放过我,主要是要解决耦合度才这么个方向解决的
    • 1

      读的问题

    • 2

      写的问题

    • 3

      同步数据

    • 查看完整方法(共4步)