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
什么是缓存击穿 在谈论缓存击穿之前,我们先来回忆下从缓存中加载数据的逻辑,如下图所示 因此,如果黑客每次故意查询一个在缓存内必然不存在的数据,导致每次请求都要去存储层去查询,这样缓存就失去了意义.如果 ...
随机推荐
- Faster, more memory efficient and more ordered dictionaries on PyPy
Faster, more memory efficient and more ordered dictionaries on PyPy https://morepypy.blogspot.com/20 ...
- Ubuntu 1604 安装配置 kafka,并配置开机自启(systemctl)
安装 kafka 需要先安装 jdk.一.下载官网:http://kafka.apache.org/downloads.html 二.安装 安装参考:https://segmentfault.com/ ...
- C# MVC Ajax上传多个图片,可预览,可重复上传等
//上传文件 function UploadFile(el) { var dataValue = $(el).attr("data-id"); var ele = dataValu ...
- Tosca 添加插件或者是扩展功能,把页面上某块内容识别成table
#遇到了问题 "ICS table was not found" 是因为编辑case的时候用到了插件的功能, 但是setting里面却没有配置这个插件 #在哪里添加插件 #目的 这 ...
- openresty开发系列22--lua的元表
openresty开发系列22--lua的元表 举个例子,在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作. 那如何计算两个table的相加 ...
- ISO/IEC 9899:2011 条款5——5.2 环境上的考虑
5.2 环境上的考虑 5.2.1 字符集 5.2.2 字符显示语义 5.2.3 信号与中断 5.2.4 环境限制
- 【PHP】 解决array_filter会过滤0 false的问题
定义和用法 array_filter() 函数用回调函数过滤数组中的元素. 该函数把输入数组中的每个键值传给回调函数.如果回调函数返回 true,则把输入数组中的当前键值返回给结果数组.数组键名保持不 ...
- Linux记录-mysql参数优化
1.参数优化show variables like ''/etc/my.cnf[mysqld]Max_connections =1024 #请求的最大连接数back_log =1024 #mysql能 ...
- C# 实现生产者消费者队列 (转)
按语:按照下面文档,测试成功: https://www.cnblogs.com/samgk/p/4772806.html 开发过程中经常会碰到这样的场景:需要从一个地方获取一些数据,然后处理数据并将其 ...
- yii webservice 提示:Procedure 'getSent' not present 错误的解决方法(转)
其实根据常用的webservice清除缓存方法,在client端加入这样一句话: ini_set("soap.wsdl_cache_enabled", "0") ...