【征服redis16】收官-redis缓存一致性问题解决方案

2024-01-23 07:04

本文主要是介绍【征服redis16】收官-redis缓存一致性问题解决方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天我们来写redis最后一篇:redis作为缓存时如何与数据库实现数据一致的问题。

最近看redis看得有点麻了,这篇就简单描述吧

目录

1.什么是缓存与数据库一致性问题

1.1 缓存一致性的概念

1.2 缓存不一致的场景

2.缓存不一致的解决思路


1.什么是缓存与数据库一致性问题

1.1 缓存一致性的概念

只要使用redis做缓存,就必然存在缓存和DB数据一致性问题。若数据不一致,则业务应用从缓存读取的数据就不是最新数据,可能导致严重错误。比如将商品的库存缓存在Redis,若库存数量不对,则下单时就可能出错,这是不能接受的。

缓存和DB的数据一致性包含如下情况:

  • 缓存有数据 缓存的数据值需和DB相同
  • 缓存无数据 DB必须是最新值

不符合这两种情况的,都属于缓存和DB数据不一致

1.2 缓存不一致的场景

目前常见的方式是先删缓存,再更新数据库,等请求获取缓存时,发现没有,从db获取 ,再重新赋值到缓存,这是最典型的缓存操作;

在正常请求下是不会有问题的,一但并发量起来了,就会产生如下问题

可能发生的问题1:

先删除缓存,数据库还没有更新成功,此时如果读取缓存,缓存不存在,去数据库中读取到的是旧值,缓存不一致发生。

可能发生的问题2:

没有按照规范操作,对于缓存未删除,直接更新数据库,数据库更新成功了,但是缓存更新失败了,导致缓存取到的值是旧值。

2.缓存不一致的解决思路

对于这个问题,我们公司采取的措施简单粗暴:

  1. 查询的时候先查缓存,没有了再查数据库。
  2. 删除或者更新的时候,先更新数据库,成功之后再删缓存,等待缓存下一步被自动更新。

这个很明显是有漏洞的,如果在查询的过程中被修改了,就会出现不一致的情况。不过我司并发度没那么高。

我们看到比较多的一种方案是这样的:延时双删

  1. 线程1删除缓存,然后去更新数据库

  2. 线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存

  3. 线程1,根据估算的时间,sleep,由于sleep的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除

  4. 如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值(不用线程sleep,这个耗线程池)

再一个思路是利用mq

这里可以利用类似于 阿里的canal 中间件模仿slave订阅mqsql的binlog日志,一当日志新增(add,update),就调用mq。不过这种方式需要加中间件,需要耗费mq资源,改动量大,结构也比较复杂。

还有一种简易的方式,就是设置缓存的过期时间,

每次放入缓存的时候,设置一个过期时间,比如5分钟,以后的操作只修改数据库,不操作缓存,等待缓存超时后从数据库重新读取。

如果对于一致性要求不是很高的情况,可以采用这种方案。

这个方案还会有另外一个问题,就是如果数据更新的特别频繁,不一致性的问题就很大了。

在实际生产中,我们有一些活动的缓存数据是使用这种方式处理的。

因为活动并不频繁发生改变,而且对于活动来说,短暂的不一致性并不会有什么大的问题。

这个问题在腾讯云社区有一个比较复杂的讨论:

Redis缓存与数据库一致性解决方案-腾讯云开发者社区-腾讯云

这篇关于【征服redis16】收官-redis缓存一致性问题解决方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/635585

相关文章

Springboot整合Redis主从实践

《Springboot整合Redis主从实践》:本文主要介绍Springboot整合Redis主从的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言原配置现配置测试LettuceConnectionFactory.setShareNativeConnect

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

MySQL 设置AUTO_INCREMENT 无效的问题解决

《MySQL设置AUTO_INCREMENT无效的问题解决》本文主要介绍了MySQL设置AUTO_INCREMENT无效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录快速设置mysql的auto_increment参数一、修改 AUTO_INCREMENT 的值。

关于跨域无效的问题及解决(java后端方案)

《关于跨域无效的问题及解决(java后端方案)》:本文主要介绍关于跨域无效的问题及解决(java后端方案),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录通用后端跨域方法1、@CrossOrigin 注解2、springboot2.0 实现WebMvcConfig

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Java死锁问题解决方案及示例详解

《Java死锁问题解决方案及示例详解》死锁是指两个或多个线程因争夺资源而相互等待,导致所有线程都无法继续执行的一种状态,本文给大家详细介绍了Java死锁问题解决方案详解及实践样例,需要的朋友可以参考下... 目录1、简述死锁的四个必要条件:2、死锁示例代码3、如何检测死锁?3.1 使用 jstack3.2

解决JSONField、JsonProperty不生效的问题

《解决JSONField、JsonProperty不生效的问题》:本文主要介绍解决JSONField、JsonProperty不生效的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录jsONField、JsonProperty不生效javascript问题排查总结JSONField

html 滚动条滚动过快会留下边框线的解决方案

《html滚动条滚动过快会留下边框线的解决方案》:本文主要介绍了html滚动条滚动过快会留下边框线的解决方案,解决方法很简单,详细内容请阅读本文,希望能对你有所帮助... 滚动条滚动过快时,会留下边框线但其实大部分时候是这样的,没有多出边框线的滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三