redis 如何保证数据一致性

news/2024/10/22 11:41:14/

前言

日常开发中常会使用redis作为项目中的缓存,只要我们使用 Redis 缓存,就必然会面对缓存和数据库间的一致性保证问题。而且如果数据不一致,那么应用从缓存中读取的数据就不是最新数据,可能会导致严重的业务问题。

为什么会数据不一致

数据一致性:指的是redis缓存跟数据库的数据的一致。假如缓存中没有数据,那么数据库的值必须是最新的。如果缓存中有数据,那么缓存中的值需要跟数据库的值相同。

理解完上述数据一致性的前提,我们看下什么情况下会导致缓存跟数据库的数据不一致。

  • 并发更新问题:当多个客户端同时对同一个数据进行更新时,假设有两个客户端同时读取了数据库中的数据,然后对其进行了修改,并分别将修改后的数据存入缓存。因为两个客户端并不知道对方的修改,所以会导致缓存中存储的数据和数据库中的数据不一致。
  • 异常情况:在更新缓存的过程中,如果发生了错误或者异常,可能导致缓存更新失败,从而导致缓存和数据库数据不一致,大致分为如下两种场景。
场景问题
先删除缓存,再更新数据库先删除缓存值, 数据库更新失败,导致请求再次访问缓存时,发现缓存缺失,再读数据库时,从数据库中读到旧值
先更新数据库,再删除缓存缓存删除失败,导致请求再次访问缓存时,发现缓存命中,并从缓存中读取到旧值

如何解决数据不一致的问题

无论是先操作缓存,还是先操作数据库,假如后者执行失败,我们可以发起重试,尽可能地去做「补偿」。我们可以把要更新/删除的值暂存到消息队列中,当应用没有能够成功地更新/删除数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或者更新。

这种做法引入消息队列,可能会增加更多的维护成本。如果重试超过的一定次数还是失败,需要向业务层发送报错信息。

注意:即使这两个操作执行时都没有失败,但是当有大量并发请求时,应用还是可能会读到不一致的数据。还是分以下两种情况讨论!

先更新数据库,再删除缓存

假设线程 A 删除了数据库中的值,但还没来得及删除缓存,线程 B 就开始读取数据了,那么此时,线程 B 查询缓存时,就会直接从缓存中读取到旧值。不过这种情况下,如果其他线程并发读缓存的请求不多,那么就不会有很多请求读取到旧值。并且线程 A 一般也会很快删除缓存值,这样其他线程再次读取时,就会发生缓存缺失,然后去数据库中获取最新的值,因此这种情况对业务的影响较小。

先删除缓存,再更新数据库(延迟双删)

我们先删除缓存,然后更新数据库的值,更新完数据库值以后,我们可以让线程先 sleep 一小段时间,再进行一次缓存删除操作。

这就是延迟双删,伪代码如下

redis.delKey(K)
db.update(K)
Thread.sleep(T)
redis.delKey(K)

有了sleep 的这段时间,即使有其他缓存从数据库读取到旧的值并重新放到缓存中,我们也能再次删除,保证缓存中会是新的值。至于sleep的这个时间如何确定?以实际业务执行时间为准。

总结

  1. 删除缓存或更新数据库失败导致的数据不一致,我们可以使用重试机制确保操作成功。
  2. 在删除缓存、更新数据库的这两步操作中,有其他线程的并发读导致其他线程读取到旧值,我们可以使用延迟双删方案解决。

http://www.ppmy.cn/news/1002064.html

相关文章

2023年华数杯赛题浅析

2023年华数杯作为与国赛同频的比赛(周四6点发题,周日晚8点交卷),也是暑期唯一一个正式比赛。今年的报名队伍已经高达​6000多对。基于这么多的人数进行国赛前队伍的练习,以及​其他用途。为了方便大家跟更好的选题&…

MySQL数据库——多表操作

文章目录 前言多表关系一对一关系一对多/多对一关系多对多关系 外键约束创建外键约束插入数据删除带有外键约束的表的数据删除外键约束 多表联合查询数据准备交叉连接查询内连接查询外连接查询左外连接查询右外连接查询满外连接查询 子查询子查询关键字ALL 关键字ANY 和 SOME 关…

网络:VRP介绍

1. VRP 华为使用的通用路由平台&#xff0c;华为的交换机、防火墙、安全设备、无线和路由器的命令行几乎一样。 2. VRP分为用户视图、系统视图。 3. 用户视图 user view <Huawei>&#xff1a;其中<>代表的是用户视图&#xff0c;Huawei是设备的名称。命令比较少。…

Mac系统如何修改默认的Java版本

1. 确定Java版本 # 查看当前系统都有哪些Java版本 /usr/libexec/java_home -V | grep jdk# 运行以下命令来查看当前默认的 Java 版本 java -version# 运行以下命令来查找当前默认的 Java 安装路径 /usr/libexec/java_home/usr/libexec/java_home -V | grep jdk java -versio…

IDEA超强XSD文件编辑插件-XSD / WSDL Visualizer

前言 XSD / WSDL Visualizer可以简化XML架构定义(XSD)和WSDL文件编辑过程; 通过使用与IntelliJ无缝集成的可视化编辑器&#xff0c;转换处理XSD和WSDL文件的方式。告别导航复杂和难以阅读的代码的挫败感&#xff0c;迎接流线型和直观的体验。 插件安装 在线安装 IntelliJ IDE…

kafka中幂等性producer和事务性producer

幂等性producer 在Kafka中,“幂等性生产者”的概念是指一种特性,它确保消息在生产者的发送操作被重试时仅发送一次。幂等性是一种重要的特性,因为在分布式系统中,网络问题或其他故障可能导致生产者发送的消息在传输过程中失败,从而需要重新发送。如果生产者没有幂等性保证…

Day12-1-Webpack前端工程化开发

Webpack前端工程化 1 案例-webpack打包js文件 1 在index.html中编写代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><me…

Java面向对象之==运算符与 equals()方法

运算符与 equals()方法 运算符 基本类型比较值:只要两个变量的值相等&#xff0c;即为true。引用类型比较引用(是否指向同一个对象)&#xff1a;只有指向同一个对象时&#xff0c;才返回true。用“”进行比较时&#xff0c;符号两边的数据类型必须兼容(可自动转换的基本数据类…