之前也看了很多相关的文章,但是感觉讲的都不好,很多文章都会去讲各种策略,比如(旁路缓存)策略、(读穿 / 写穿)策略和(写回)策略等,感觉意义真的不大,然后有的文章也只讲了部分情况,也没有告诉最优解。

我直接先抛一下结论:在满足实时性的条件下,不存在两者完全保存一致的方案,只有最终一致性方案。 根据网上的众多解决方案,总结出 6 种,直接看目录:

不好的方案

1. 先写 MySQL,再写 Redis

图解说明:

  • 这是一副时序图,描述请求的先后调用顺序;

  • 橘黄色的线是请求 A,黑色的线是请求 B;

  • 橘黄色的文字,是 MySQL 和 Redis 最终不一致的数据;

  • 数据是从 10 更新为 11;

  • 后面所有的图,都是这个含义,不再赘述。

请求 A、B 都是先写 MySQL,然后再写 Redis,在高并发情况下,如果请求 A 在写 Redis 时卡了一会,请求 B 已经依次完成数据的更新,就会出现图中的问题。

这个图已经画的很清晰了,我就不用再去啰嗦了吧,不过这里有个前提,就是对于读请求,先去读 Redis,如果没有,再去读 DB,但是读请求不会再回写 Redis。 大白话说一下,就是读请求不会更新 Redis。

2. 先写 Redis,再写 MySQL

同“先写 MySQL,再写 Redis”,看图可秒懂。

3. 先删除 Redis,再写 MySQL

这幅图和上面有些不一样,前面的请求 A 和 B 都是更新请求,这里的请求 A 是更新请求,但是请求 B 是读请求,且请求 B 的读请求会回写 Redis。

请求 A 先删除缓存,可能因为卡顿,数据一直没有更新到 MySQL,导致两者数据不一致。

这种情况出现的概率比较大,因为请求 A 更新 MySQL 可能耗时会比较长,而请求 B 的前两步都是查询,会非常快。

好的方案

4. 先删除 Redis,再写 MySQL,再删除 Redis

对于“先删除 Redis,再写 MySQL”,如果要解决最后的不一致问题,其实再对 Redis 重新删除即可,这个也是大家常说的“缓存双删”。

为了便于大家看图,对于蓝色的文字,“删除缓存 10”必须在“回写缓存10”后面,那如何才能保证一定是在后面呢?网上给出的第一个方案是,让请求 A 的最后一次删除,等待 500ms。

对于这种方案,看看就行,反正我是不会用,太 Low 了,风险也不可控。

那有没有更好的方案呢,我建议异步串行化删除,即删除请求入队列

异步删除对线上业务无影响,串行化处理保障并发情况下正确删除。

如果双删失败怎么办,网上有给 Redis 加一个缓存过期时间的方案,这个不敢苟同。个人建议整个重试机制,可以借助消息队列的重试机制,也可以自己整个表,记录重试次数,方法很多。

简单小结一下:

  • “缓存双删”不要用无脑的 sleep 500 ms;

  • 通过消息队列的异步&串行,实现最后一次缓存删除;

  • 缓存删除失败,增加重试机制。

5. 先写 MySQL,再删除 Redis

对于上面这种情况,对于第一次查询,请求 B 查询的数据是 10,但是 MySQL 的数据是 11,只存在这一次不一致的情况,对于不是强一致性要求的业务,可以容忍。(那什么情况下不能容忍呢,比如秒杀业务、库存服务等。)

当请求 B 进行第二次查询时,因为没有命中 Redis,会重新查一次 DB,然后再回写到 Reids。

那什么情况下会出现不一致的情况呢?

这里需要满足 2 个条件:

  • 缓存刚好自动失效;

  • 请求 B 从数据库查出 10,回写缓存的耗时,比请求 A 写数据库,并且删除缓存的还长。

对于第二个条件,我们都知道更新 DB 肯定比查询耗时要长,所以出现这个情况的概率很小,同时满足上述条件的情况更小。

6. 先写 MySQL,通过 Binlog,异步更新 Redis

这种方案,主要是监听 MySQL 的 Binlog,然后通过异步的方式,将数据更新到 Redis,这种方案有个前提,查询的请求,不会回写 Redis。

这个方案,会保证 MySQL 和 Redis 的最终一致性,但是如果中途请求 B 需要查询数据,如果缓存无数据,就直接查 DB;如果缓存有数据,查询的数据也会存在不一致的情况。

所以这个方案,是实现最终一致性的终极解决方案,但是不能保证实时性。

几种方案比较

我们对比上面讨论的 6 种方案:

  1. 先写 Redis,再写 MySQL

  • 这种方案,我肯定不会用,万一 DB 挂了,你把数据写到缓存,DB 无数据,这个是灾难性的;

  • 我之前也见同学这么用过,如果写 DB 失败,对 Redis 进行逆操作,那如果逆操作失败呢,是不是还要搞个重试?

  1. 先写 MySQL,再写 Redis

  • 对于并发量、一致性要求不高的项目,很多就是这么用的,我之前也经常这么搞,但是不建议这么做;

  • 当 Redis 瞬间不可用的情况,需要报警出来,然后线下处理。

  1. 先删除 Redis,再写 MySQL

  • 这种方式,我还真没用过,直接忽略吧。

  1. 先删除 Redis,再写 MySQL,再删除 Redis

  • 这种方式虽然可行,但是感觉好复杂,还要搞个消息队列去异步删除 Redis。

  1. 先写 MySQL,再删除 Redis

  • 比较推荐这种方式,删除 Redis 如果失败,可以再多重试几次,否则报警出来;

  • 这个方案,是实时性中最好的方案,在一些高并发场景中,推荐这种。

  1. 先写 MySQL,通过 Binlog,异步更新 Redis

  • 对于异地容灾、数据汇总等,建议会用这种方式,比如 binlog + kafka,数据的一致性也可以达到秒级;

  • 纯粹的高并发场景,不建议用这种方案,比如抢购、秒杀等。

个人结论:

  • 实时一致性方案:采用“先写 MySQL,再删除 Redis”的策略,这种情况虽然也会存在两者不一致,但是需要满足的条件有点苛刻,所以是满足实时性条件下,能尽量满足一致性的最优解。

  • 最终一致性方案:采用“先写 MySQL,通过 Binlog,异步更新 Redis”,可以通过 Binlog,结合消息队列异步更新 Redis,是最终一致性的最优解。


如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,

咱们下期见!答案获取方式:已赞 已评 已关~

学习更多知识与技巧,关注与私信博主(03)

如何保障 MySQL 和 Redis 的数据一致性?相关推荐

  1. 招银一面:如何保障 MySQL 和 Redis 的数据一致性?

    如何保障 MySQL 和 Redis 的数据一致性?这个问题很早之前我就遇到过,但是一直没有仔细去研究,上个月看了极客的课程,有一篇文章专门有过讲解,刚好有粉丝也问我这个问题,所以感觉有必要单独出一篇 ...

  2. 如何保证MySQL和Redis的数据一致性?10张图带你搞定!

    导语 | 本文的主要思路是首先带大家认识了解MySQL和Redis的数据一致性情况,然后进行反推不一致的情况,从而进行探究单线程中的不一致的情况.同时探究多线程中的不一致的情况,拟定数据一致性策略. ...

  3. 如何保证MySQL和Redis的数据一致性?

    " 今天给大家剖析一下工作中常见的 MySQL 和 Redis 数据一致性问题. 图片来自 Pexels 什么是数据的一致性 一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据 ...

  4. 认识 MySQL 和 Redis 的数据一致性问题

    作者:sinxu,腾讯 CSIG 后台开发工程师 1. 什么是数据的一致性 "数据一致"一般指的是:缓存中有数据,缓存的数据值 = 数据库中的值. 但根据缓存中是有数据为依据,则& ...

  5. MySQL redis如何实现_如何保障mysql和redis之间的数据一致性?(转发)

    在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问Mysql等数据库.这样可以大大缓解数据库的压力. ...

  6. redis数据一致性串行化方案_若何保障mysql和redis之间的数据一致性?(转发)

    在高并发的营业场景下,数据库大多数情形都是用户并发接见最微弱的环节.以是,就需要使用redis做一个缓冲操作,让请求先接见到redis,而不是直接接见Mysql等数据库.这样可以大大缓解数据库的压力. ...

  7. Redis延时双删实现mysql和redis的数据一致性

    在高并发的业务场景下,为了保护数据库,我们一般都会做缓冲.所以,假设我们用redis做一个缓冲操作,让请求先访问redis,而不是直接访问mysql,来缓解数据库的压力. 平常的读取缓存没啥问题,但假 ...

  8. mysql与redis数据同步(c/c++)(写mysql同步到redis,并且以json格式保存)

    系统开发中时常会需要缓存来提升并发读的能力,这时可以通过mysql的UDF和hiredis来进行同步 原理: 通过mysql自动同步redis 在服务端开发过程中,一般会使用MySQL等关系型数据库作 ...

  9. 常用数据库 知识点大全 (Mysql,Redis,MongoDB)

    目录 Mysql 1.1 5大引擎 共10个 1.2 事务 1.3 锁1 锁2 1.4 Btree/B+tree 1.5 mysql进阶 Redis 2.1 Redis介绍 2.2 redis的五大数 ...

最新文章

  1. TensorRT 7.2.1 开发概要(上)
  2. 超赞的PyTorch资源大列表,GitHub标星9k+,中文版也上线了
  3. 十年技术,不要再迷茫
  4. python股票编程规范_Python 编程规范梳理
  5. python第四篇:linux命令行总结 + 自动备份Python程序
  6. 关于IAR的一些总结 -- ARM调试和Flash调试的区别
  7. 【分布计算环境学习笔记】9 Web Service
  8. 输入法——讨厌的全角
  9. SAP Spartacus里如何查看HTTP请求的状态
  10. C++:53---菱形继承、虚继承
  11. java中常量定义在interface中好还是定义在class中
  12. activiti 条件表达式json报错_json模块和pickle模块
  13. python post 表单类数据_python post content-type:multipart/form-data 类型的表单数据
  14. IEquatable「T」和Equal详解
  15. System.Web.Helpers.Json 与 Newtonsoft.Json 的性能对比
  16. 用Redis实现分布式锁 与 实现任务队列【转载】
  17. Codeforces Round #574 (Div. 2)
  18. .bat脚本基本命令合集
  19. 通过代理服务器下载网页
  20. 产品经理为什么比程序员工资要高?百度员工:因为他是产品灵魂

热门文章

  1. APISIX安装与灰度、蓝绿发布
  2. 懒癌患者的学习记录之JAVA简单选择排序
  3. 虽然2021年折磨了我一整年,但2022年我依旧笑对新年【CSDN 年度征文|回顾 2021,展望 2022】
  4. java for循环中map_Java用For循环Map
  5. 『NLP学习笔记』Triton推理服务器加速模型推理
  6. 【愚公系列】2022年02月 wireshark系列-数据抓包分析之UDP协议
  7. 支付宝被风控7天怎么办?付解决方案
  8. leetcode 51. N皇后问题
  9. 2012年刚流行的段子
  10. matlab文件路径操作 mfilename