IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> redis应用 -> 正文阅读

[大数据]redis应用

redis和数据库双写一致性问题

分析:一致性问题是分布式常见问题,还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。答这个问题,先明白一个前提。就是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。另外,我们所做的方案其实从根本上来说,只能说降低不一致发生的概率,无法完全避免。因此,有强一致性要求的数据,不能放缓存。

回答:首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用设置缓存失效时间(一般再秒级)或者消息队列的重试机制。

分析:

将不一致分为三种情况:

  1. 数据库有数据,缓存没有数据;

  2. 数据库有数据,缓存也有数据,数据不相等;

  3. 数据库没有数据,缓存有数据。

1.读写策略

1 读请求

不要求强一致性的读请求,走redis,要求强一致性的直接从mysql读取。

读操作优先读取redis,不存在的话就去访问MySQL,并把读到的数据写回Redis中;

2 写请求

数据首先都写到数据库,然后把缓存里对应的数据失效掉(删掉)。
(先写redis再写mysql的弊端,如果写入失败事务回滚会造成redis中存在脏数据)

为何是删缓存而不是更新缓存?

?

这么做引发的问题是,如果A,B两个线程同时做数据更新,A先更新了数据库,B后更新数据库,则此时数据库里逻辑上存的是B的数据。

但要考虑两种情况:
1.A在更新缓存前卡住了,如果在更新缓存的时候,是B先更新了缓存,而A后更新了缓存,则缓存里是A的数据。这样缓存和数据库的数据也不一致。
2.A更新成功了,B更新失败了。则缓存里是A的数据。这样缓存和数据库的数据也不一致。

针对更新失败的解决方案:
方案一:采用补偿策略,更新失败后缓存delete。如果更新失败,那么再对缓存进行删除,让读请求重新回源来保证数据一致性。

方案二:“日志记录后手动操作”。更新失败会记入日志,手动操作【人工操作,不灵活】。

方案三:“key存入MQ重新消费set一次”。借用MQ中间件,将有问题的key放入MQ,重新消费进行更新缓存【借用第三方组件,耗费大】。
?

删缓存一定能保证双写一致性吗?

线程1和2为分别写数据,线程3为读数据。理论上缓存最后应该是线程2的数据,但实际有可能出现

出现的原因如下:

线程1执行完成后,此时缓存为空。这时线程2去更新数据库因为比较耗时还没有写完,另外一个线程3请求来查询数据,发现缓存里没有,就去数据库里查此时查到的为10,然后准备回写缓存前,此时线程2更新数据库完成了并删了缓存,线程3继续回写完缓存后,此时缓存的值为10。

解决方案1:

遇到这种情况,可以用队列的去解决这个问题,创建一个先进先出的阻塞队列如ArrayBlockingQueue,当有数据更新请求时,先把它丢到队列里去,当更新完后在从队列里去除,如果在更新的过程中,遇到以上场景,先去缓存里看下有没有数据,如果没有,可以先去队列里看是否有相同商品ID在做更新,如果有也把查询的请求发送到队列的末端里去,然后同步等待缓存更新完成。?

这里有一个优化点,如果发现队列里有一个查询请求了,那么就不要放新的查询操作进去了,用一个while(true)循环去查询缓存,循环个200MS左右,如果缓存里还没有则直接取数据库的旧数据(不要更新缓存),一般情况下是可以取到的。

当然这种排队的策略对性能是有一定的影响的。

解决方案2:

利用Redisson的读写锁机制,在操作缓存时,线程3上了读锁之后,线程2就需要等待线程3写缓存释放之后才能去抢锁并删缓存。

注意:此方案报保证抢锁的顺序性,不能让写锁线程2一直阻塞,则会一直读到老的数据。

删除缓存失败的补偿方案参考:

删除缓存失败的补偿方案参考:

  1. 对删除缓存进行重试,数据的一致性要求越高,我越是重试得快。(个人理解当删除缓存失败后,应该还要为当前key值设置标记,当下一次对当前key值有查询请求时,直接读数据库,直到删除失败的标记消失为止)

  2. 定期全量更新,简单地说,就是我定期把缓存全部清掉,然后再全量加载。

  3. 给所有的缓存一个失效期。

第三种方案可以说是一个大杀器,任何不一致,都可以靠失效期解决,失效期越短,数据一致性越高。但是失效期越短,查数据库就会越频繁。因此失效期应该根据业务来定。

2.并发情况选型

并发不高的情况:

读: 读redis->没有,读mysql->把mysql数据写回redis,有的话直接从redis中取;

写: 写mysql->成功,再写redis;

并发高的情况:

此种情况对一致性特别低。

读: 读redis->没有,读mysql->把mysql数据写回redis,有的话直接从redis中取;

写:异步化,先写入redis的缓存,就直接返回;定期或特定动作如放到先进先出的阻塞队列将数据保存到mysql,可以做到多次更新,一次保存;

?

参考:
1.Redis怎么保持缓存与数据库一致性? https://blog.csdn.net/belalds/article/details/82078009
2.Redis 如何保持和MySQL数据一致 https://blog.csdn.net/thousa_ho/article/details/78900563

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:41:07  更:2022-10-17 12:43:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 6:30:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码