如何保证数据库和redis的数据一致性

news/2024/8/22 5:57:37 标签: redis, 缓存

1、简介

在客户端请求数据时,如果能在缓存中命中数据,那就查询缓存,不用在去查询数据库,从而减轻数据库的压力,提高服务器的性能。

2、问题如何保证两者的一致性

先更新数据库在删除缓存

难点:如何保证这两个操作都执行成功?

如果删除缓存失败了怎么办?

这次用户的投诉是因为在删除缓存(第二个操作)的时候失败了,导致缓存还是旧值,而数据库是最新值,造成数据库和缓存数据不一致的问题,会对敏感业务造成影响。

例子:

应用要把数据 X 的值从 1 更新为 2,先成功更新了数据库,然后在 Redis 缓存中删除 X 的缓存,但是这个操作却失败了,这个时候数据库中 X 的新值为 2,Redis 中的 X 的缓存值为 1,出现了数据库和缓存数据不一致的问题。

那么,后续有访问数据 X 的请求,会先在 Redis 中查询,因为缓存并没有 诶删除,所以会缓存命中,但是读到的却是旧值 1。

其实不管是先操作数据库,还是先操作缓存,只要第二个操作失败都会出现数据一致的问题。

问题原因知道了,该怎么解决呢?有两种方法:

  • 重试机制。
  • 订阅 MySQL binlog,再操作缓存

先来说第一种。

重试机制

我们可以引入消息队列,将第二个操作(删除缓存)要操作的数据加入到消息队列,由消费者来操作数据。

  • 如果应用删除缓存失败,可以从消息队列中重新读取数据,然后再次删除缓存,这个就是重试机制。当然,如果重试超过的一定次数,还是没有成功,我们就需要向业务层发送报错信息了。
  • 如果删除缓存成功,就要把数据从消息队列中移除,避免重复操作,否则就继续重试。

举个例子,来说明重试机制的过程。

订阅 MySQL binlog,再操作缓存

先更新数据库,再删缓存」的策略的第一步是更新数据库,那么更新数据库成功,就会产生一条变更日志,记录在 binlog 里。

于是我们就可以通过订阅 binlog 日志,拿到具体要操作的数据,然后再执行缓存删除,阿里巴巴开源的 Canal 中间件就是基于这个实现的。

Canal 模拟 MySQL 主从复制的交互协议,把自己伪装成一个 MySQL 的从节点,向 MySQL 主节点发送 dump 请求,MySQL 收到请求后,就会开始推送 Binlog 给 Canal,Canal 解析 Binlog 字节流之后,转换为便于读取的结构化数据,供下游程序订阅使用。

下图是 Canal 的工作原理:

所以,如果要想保证「先更新数据库,再删缓存」策略第二个操作能执行成功,我们可以使用「消息队列来重试缓存的删除」,或者「订阅 MySQL binlog 再操作缓存」,这两种方法有一个共同的特点,都是采用异步操作缓存

删除一个数据,相比更新一个数据更加轻量级,出问题的概率更小。在实际业务中,缓存的数据可能不是直接来自数据库表,也许来自多张底层数据表的聚合。


http://www.niftyadmin.cn/n/5556260.html

相关文章

jenkins系列-04-jenkins参数化构建

使用maven build之前,先checkout 指定分支或标签: 拖拽调整顺序:shell执行在前,构建在后: gitee新建标签tag:

ZGC的流程图

GC标记过程 1、初始标记 扫描所有线程栈的根节点,然后再扫描根节点直接引用的对象并进行标记。这个阶段需要停顿所有的应用线程(STW),但由于只扫描根对象直接引用的对象,所以停顿时间很短。停顿时间高度依赖根节点的数…

大模型-Bert+PET实战

PET(Pattern-Exploiting Training) 背景:预训练语言模型(比如BERT)知识全面,但是没有针对下游任务做针对训练,所以效果一般,所以需要根据任务做微调。 核心思想:根据先…

设计模式学习(二)工厂模式——抽象工厂模式+注册表

设计模式学习(二)工厂模式——抽象工厂模式注册表 前言使用简单工厂改进使用注册表改进参考文章 前言 在上一篇文章中我们提到了抽象工厂模式初版代码的一些缺点:①客户端违反开闭原则②提供方违反开闭原则。本文将针对这两点进行讨论 使用…

WordPress:无法创建新文章?创建新帖子时候页面空白

wordPress中我们新建文章的时候,会遇到页面空白,这个问题是怎么导致呢?我们可以打开F12开发者模式看下报错信息,这是一个警告信息 Warning: Creating default object from empty value in /pub 到数据库 wp_posts中查看生成了很…

数据结构—链式二叉树-C语言

代码位置:test-c-2024: 对C语言习题代码的练习 (gitee.com) 一、前言: 在现实中搜索二叉树为常用的二叉树之一,今天我们就要通过链表来实现搜索二叉树。实现的操作有:建二叉树、前序遍历、中序遍历、后序遍历、求树的节点个数、求…

Linux软件包管理器——yum

什么是软件包 在linux下安装软件,一个通常的办法就是下载程序的源代码,编译,得到可执行程序,但是这样比较麻烦,就有人把一些常用的软件提前编译好,做成软件包,这样下载的时候,直接下…

linux - shell - 单引号与双引号

在 Shell 脚本中,双引号 (") 和单引号 () 都用于引用字符串,但它们的解析机制有所不同。 双引号 (") 使用双引号包围的字符串会保留大多数字符的字面意义,但允许以下字符在引号内进行解析: 变量替换:如 $…