Redis缓存如何保证一致性
为什么使用Redis做缓存
MySQL缺点
- 单机连接数目有限
- 对数据进行写速度慢
Redis优点
- 内存操作数据速度快
- IO复用,速度快
- 单线程模型,避免线程切换带来的开销,速度快
一致性问题
读数据的时候首先去Redis里读,没有读到再去MySQL里读,读回来之后更新到Redis里作为下一次的缓存。写数据的时候回产生数据不一致的问题,无论是先写到Redis里再写MySQL还是先写MySQL再写Redis,这两步写操作不能保证原子性,所以会出现Redis和MySQL里的数据不一致。无论采取何种方式都不能保证强一致性,如果对Redis里的数据设置了过期时间能够保证最终一致性,对架构做的优化只能降低不一致性发生的概率,不能从根本上避免不一致性。
根据写入的顺序不同分为四种。
先删缓存,再更新数据库
这种操作的问题?
一般考虑某种策略的问题都是考虑该种策略会不会导致被删除的脏数据由于时序混乱再次被读线程从MySQL中读出来。A线程写数据,B线程读数据,A线程删除了缓存,B线程读数据发现缓存没有命中从数据库中读数据,B线程把读出的旧数据写到Redis里,A线程把新数据写回去。和下面的先写数据库再删缓存相比,这种方式显著的缺点
- 先删缓存,所以当两个线程并发的时候很大几率会出现缓存不命中,一旦缓存不命中,在写线程修改MySQL完成之前读进来的永远是脏数据
- 在缓存到期之前Redis里一直是脏数据
解决策略
延迟双删,双删就是在更新完数据库后再删一次。不过延迟双删中更新数据库之前的删除还有什么意义?延迟的目的是为了删除在写MySQL期间读线程可能把脏数据再次读到Redis里,延迟的时间参照一次从MySQL读数据并写入Redis的时间
Cache Aside Pattern--先写数据库,再删缓存
为什么更新数据库后不更新而是删除缓存?
- 更新缓存的操作不是必须的。可能缓存里的数据并没有被读到,就会被下一次更新MySQL操作带来Redis更新操作覆盖,那么本次更新操作就是无意义的。
- 更新缓存代价大。如果缓存里的数据不是把MySQL里的数据直接存下来,而是需要经过某种复杂的运算,那么这种不必要的更新会带来更大的浪费。
这种操作的问题?
- 并发问题。A线程读数据但没有命中,B线程写数据。A线程读到了MySQL的旧数据,B线程写了新的数据进MySQL,B线程删除了Redis中旧数据的缓存,A用旧数据写到了Redis缓存里。此时Redis里就是旧的脏数据。但这种case出现的概率较低,需要Redis缓存失效同时出现线程写入操作,而且理论上A线程从MySQL中读数据应该更快的返回。
解决方案?
每个写MySQL线程写完后延时一定时间在去删Redis中的缓存。
Write Behind Caching Pattern--只更缓存,不更MySQL,MySQL由缓存异步的更新
Redis缓存如何保证一致性的更多相关文章
- Redis缓存和数据库一致性问题
工作中,经常会遇到缓存和数据库数据一致性问题.从理论上设置过期时间,是保证最终一致性的解决方案.这种方案下,我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可 ...
- redis缓存与数据库一致性问题
一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去. ...
- Redis缓存与数据库一致性解决方案
背景 缓存是数据库的副本,应用在查询数据时,先从缓存中查询,如果命中直接返回,如果未命中,去数据库查询最新数据并返回,同时写入缓存. 缓存能够有效地加速应用的读写速度,同时也可以降低后端负载.是应用架 ...
- redis,缓存雪崩,粗粒度锁,缓存一致性
1, redis单线程为什么快 io多路复用技术 单线程避免多线程的频繁切换问题 memcache缺点 kv形式数据 没有持久化mongodb 海量数据的访问效率 mr的计算模型文档就是类似json的 ...
- Redis缓存穿透、击穿、雪崩,数据库与缓存一致性
Redis作为高性能非关系型(NoSQL)的键值对数据库,受到了广大用户的喜爱和使用,大家在项目中都用到了Redis来做数据缓存,但有些问题我们在使用中不得不考虑,其中典型的问题就是:缓存穿透.缓存雪 ...
- Redis 缓存 + Spring 的集成示例(转)
<整合 spring 4(包括mvc.context.orm) + mybatis 3 示例>一文简要介绍了最新版本的 Spring MVC.IOC.MyBatis ORM 三者的整合以及 ...
- Redis缓存你必须了解的!
不管你是从事Python.Java.Go.PHP.Ruby等等… Redis都应该是一个比较熟悉的中间件.而大部分经常写业务代码的程序员,实际工作中或许只用到了set value.get value两 ...
- Redis缓存穿透和缓存雪崩以及解决方案
Redis缓存穿透和缓存雪崩以及解决方案 Redis缓存穿透和缓存雪崩以及解决方案缓存穿透解决方案布隆过滤缓存空对象比较缓存雪崩解决方案保证缓存层服务高可用性依赖隔离组件为后端限流并降级数据预热缓存并 ...
- redis 缓存击穿 看一篇成高手系列3
什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查询,这样缓存就失去了意义.如果 ...
随机推荐
- sqlserver2016 kb补丁
1. win2012r2 安装时 总是提示: 然后费了半天劲 下载下来又提示 找了一下 需要先安装这么一个补丁才可以 KB2919442 然后才能安装上 KB2919355 然后就可以正常安装了:
- Web Application Framework
ASP.NET Boilerplate https://github.com/aspnetboilerplate ASP.NET Boilerplate - Web Application Frame ...
- Android studio -SVN 使用笔记
1.Android studio 安装 中文组官网:http://www.android-studio.org/ 常见问题参考: 分支冲突合并 http://blog.csdn.net/tearsmo ...
- 【Redis】Redis 主从模式搭建
主从模式介绍 Redis虽然读取写入的速度都特别快,但是也会产生读压力特别大的情况.为了分担读压力,Redis支持主从复制,Redis的主从结构可以采用一主多从或者级联结构,Redis主从复制可以根据 ...
- Linux系统调优——网络(四)
(1).查看网络(Network)运行状态相关工具 1)nload监控总体带宽使用情况 nload需要自己安装,而且在安装前需要安装epel-release [root@youxi1 ~]# yum ...
- SAP 增强篇 Method1 BADI增强的查找方法
查找BADI的方法:(1)通过SE24,输入CL_EXITHANDLER,然后在方法GET_INSTANCE中设置断点,然后运行事务代码判断 exit_name的值,操作过程如下:输入se24,然后输 ...
- numpy包中,与线性代数相关的模块——linalg(利那隔)
https://github.com/scalanlp/breeze/wiki/Linear-Algebra-Cheat-Sheethttps://docs.scipy.org/doc/numpy-1 ...
- while死循环
while死循环放入主线程要注意,如果处理不当可能引起界面假死,如果界面假死,可以放入子线程中(如果每个循环处理时间现对于CPU很短,则建议在本次循环结束的尾部加入Sleep以释放对CPU的占用) C ...
- Connection reset by peer引发的思考
http://www.mamicode.com/info-detail-506381.html
- SpringMVC:学习笔记(12)——ThreadLocal实现会话共享
SpringMVC:学习笔记(12)——ThreadLocal实现会话共享 ThreadLocal ThreadLocal,被称为线程局部变量.在并发编程的情况下,使用ThreadLocal创建的变量 ...