redis 查询缓存_Redis缓存总结:淘汰机制、缓存雪崩、数据不一致....

在实际的工作项目中, 缓存成为高并发、高性能架构的关键组件 ,那么Redis为什么可以作为缓存使用呢?首先可以作为缓存的两个主要特征:

  • 在分层系统中处于内存/CPU具有访问性能良好,
  • 缓存数据饱和,有良好的数据淘汰机制

由于Redis 天然就具有这两个特征,Redis基于内存操作的,且其具有完善的数据淘汰机制,十分适合作为缓存组件。

其中,基于内存操作,容量可以为32-96GB,且操作时间平均为100ns,操作效率高。而且数据淘汰机制众多,在Redis 4.0 后就有8种了促使Redis作为缓存可以适用很多场景。

那Redis缓存为什么需要数据淘汰机制呢?有哪8种数据淘汰机制呢?

数据淘汰机制

Redis缓存基于内存实现的,则其缓存其容量是有限的,当出现缓存被写满的情况,那么这时Redis该如何处理呢?

Redis对于缓存被写满的情况,Redis就需要缓存数据淘汰机制,通过一定淘汰规则将一些数据刷选出来删除,让缓存服务可再使用。那么Redis使用哪些淘汰策略进行刷选删除数据?

在Redis 4.0 之后,Redis 缓存淘汰策略6+2种,包括分成三大类:

  • 不淘汰数据
    • noeviction ,不进行数据淘汰,当缓存被写满后,Redis不提供服务直接返回错误。
  • 在设置过期时间的键值对中,
    • volatile-random ,在设置过期时间的键值对中随机删除
    • volatile-ttl ,在设置过期时间的键值对,基于过期时间的先后进行删除,越早过期的越先被删除。
    • volatile-lru , 基于LRU(Least Recently Used) 算法筛选设置了过期时间的键值对, 最近最少使用的原则来筛选数据
    • volatile-lfu ,使用 LFU( Least Frequently Used ) 算法选择设置了过期时间的键值对, 使用频率最少的键值对,来筛选数据。
  • 在所有的键值对中,
    • allkeys-random, 从所有键值对中随机选择并删除数据
    • allkeys-lru, 使用 LRU 算法在所有数据中进行筛选
    • allkeys-lfu, 使用 LFU 算法在所有数据中进行筛选

17505f784e0cb0d8e689ad57a43687f1.png


img

Note: LRU( 最近最少使用,Least Recently Used)算法, LRU维护一个双向链表 ,链表的头和尾分别表示 MRU 端和 LRU 端,分别代表最近最常使用的数据和最近最不常用的数据。
LRU 算法在实际实现时,需要用链表管理所有的缓存数据,这会带来额外的空间开销。而且,当有数据被访问时,需要在链表上把该数据移动到 MRU 端,如果有大量数据被访问,就会带来很多链表移动操作,会很耗时,进而会降低 Redis 缓存性能。

其中,LRU和LFU 基于Redis的对象结构redisObject的lru和refcount属性实现的:

typedef struct redisObject { unsigned type:4; unsigned encoding:4; // 对象最后一次被访问的时间 unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or * LFU data (least significant 8 bits frequency // 引用计数 * and most significant 16 bits access time). */ int refcount; void *ptr; } robj; 复制代码

Redis的LRU会使用redisObject的lru记录最近一次被访问的时间,随机选取参数maxmemory-samples 配置的数量作为候选集合,在其中选择 lru 属性值最小的数据淘汰出去。

在实际项目中,那么该如何选择数据淘汰机制呢?

  • 优先选择 allkeys-lru算法,将最近最常访问的数据留在缓存中,提升应用的访问性能。
  • 有顶置数据使用 volatile-lru算法 ,顶置数据不设置缓存过期时间,其他数据设置过期时间,基于LRU 规则进行筛选 。

在理解了Redis缓存淘汰机制后,来看看Redis作为缓存其有多少种模式呢?

Redis缓存模式

Redis缓存模式基于是否接收写请求,可以分成只读缓存和读写缓存:

只读缓存:只处理读操作,所有的更新操作都在数据库中,这样数据不会有丢失的风险。

  • Cache Aside模式

9b6ac4700aa0a8e57ab35308fe18b722.png


image.png

读写缓存,读写操作都在缓存中执行,出现宕机故障,会导致数据丢失。缓存回写数据到数据库有分成两种同步和异步:

  • 同步:访问性能偏低,其更加侧重于保证数据可靠性
    • Read-Throug模式
    • Write-Through模式
  • 异步:有数据丢失风险,其侧重于提供低延迟访问
    • Write-Behind模式

0c5da8df94879ac2b8debe590dc4310b.png


image.png

Cache Aside模式

查询数据先从缓存读取数据,如果缓存中不存在,则再到数据库中读取数据,获取到数据之后更新到缓存Cache中,但更新数据操作,会先去更新数据库种的数据,然后将缓存种的数据失效。

而且Cache Aside模式会存在并发风险:执行读操作未命中缓存,然后查询数据库中取数据,数据已经查询到还没放入缓存,同时一个更新写操作让缓存失效,然后读操作再把查询到数据加载缓存,导致缓存的脏数据。

Read/Write-Throug模式

查询数据和更新数据都直接访问缓存服务,缓存服务同步方式地将数据更新到数据库。出现脏数据的概率较低,但是就强依赖缓存,对缓存服务的稳定性有较大要求,但同步更新会导致其性能不好。

Write Behind模式

查询数据和更新数据都直接访问缓存服务,但缓存服务使用异步方式地将数据更新到数据库(通过异步任务) 速度快,效率会非常高,但是数据的一致性比较差,还可能会有数据的丢失情况,实现逻辑也较为复杂。

在实际项目开发中根据实际的业务场景需求来进行选择缓存模式。那了解上述后,我们的应用中为什么需要使用到redis缓存呢?

在应用使用Redis缓存可以提高系统性能和并发,主要体现在

  • 高性能:基于内存查询,KV结构,简单逻辑运算
  • 高并发: Mysql 每秒只能支持2000左右的请求,Redis轻松每秒1W以上。让80%以上查询走缓存,20%以下查询走数据库,能让系统吞吐量有很大的提高

虽然使用Redis缓存可以大大提升系统的性能,但是使用了缓存,会出现一些问题,比如,缓存与数据库双向不一致、缓存雪崩等,对于出现的这些问题该怎么解决呢?

使用缓存常见的问题

使用了缓存,会出现一些问题,主要体现在:

  • 缓存与数据库双写不一致
  • 缓存雪崩: Redis 缓存无法处理大量的应用请求,转移到数据库层导致数据库层的压力激增;
  • 缓存穿透:访问数据不存在在Redis缓存中和数据库中,导致大量访问穿透缓存直接转移到数据库导致数据库层的压力激增;
  • 缓存击穿:缓存无法处理高频热点数据,导致直接高频访问数据库导致数据库层的压力激增;

缓存与数据库数据不一致

只读缓存(Cache Aside模式)

对于只读缓存(Cache Aside模式), 读操作都发生在缓存中,数据不一致只会发生在删改操作上(新增操作不会,因为新增只会在数据库处理),当发生删改操作时,缓存将数据中标志为无效和更新数据库 。因此在更新数据库和删除缓存值的过程中,无论这两个操作的执行顺序谁先谁后,只要有一个操作失败了就会出现数据不一致的情况。

总结出,当不存在并发的情况使用重试机制(消息队列使用),当存在高并发的情况,使用延迟双删除(在第一次删除后,睡眠一定时间后,再进行删除),具体如下:

操作顺序是否高并发潜在问题现象应对方案
NOTE:
延迟双删除伪代码:
redis.delKey(X) db.update(X) Thread.sleep(N) redis.delKey(X)

读写缓存(Read/Write-Throug、Write Behind模式 )

对于读写缓存,写操作都发生在缓存中,后再更新数据库,只要有一个操作失败了就会出现数据不一致的情况。

总结出,当不存在并发的情况使用重试机制(消息队列使用),当存在高并发的情况,使用分布锁。具体如下:

操作顺序是否高 并发潜在问题现象应对方案

缓存雪崩

缓存雪崩,由于缓存中有大量数据同时过期失效或者缓存出现宕机,大量的应用请求无法在 Redis 缓存中进行处理,进而发送到数据库层导致数据库层的压力激增,严重的会造成数据库宕机。

对于缓存中有大量数据同时过期,导致大量请求无法得到处理, 解决方式:

  • 数据预热将发生大并发访问前手动触发加载缓存不同的key, 可以避免在用户请求的时候,先查询数据库
  • 设置不同的过期时间,让缓存失效的时间点尽量均匀
  • 双层缓存策略, 在原始缓存上加上拷贝缓存,原始缓存失效时可以访问拷贝缓存,且原始缓存失效时间设置为短期,拷贝缓存设置为长期
  • 服务降级 , 发生缓存雪崩时,针对不同的数据采取不同的降级方案 ,比如,非核心数据直接返回预定义信息、空值或是错误信息

对于缓存出现宕机,解决方式:

  • 业务系统中实现服务熔断或请求限流机制,防止大量访问导致数据库出现宕机

缓存穿透

缓存穿透,数据在数据库和缓存中都不存在,这样就导致查询数据,在缓存中找不到对应key的value,都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。

当有大量访问请求,且其绕过缓存直接查数据库,导致数据库层的压力激增,严重的会造成数据库宕机。

对于缓存穿透,解决方式:

  • 缓存空值或缺省值,当一个查询返回的数据为空时, 空结果也将进行缓存,并将它的过期时间设置比较短,下次访问直接从缓存中取值,避免了把大量请求发送给数据库处理,造成数据库出问题。
  • 布隆过滤器( BloomFilter ),将所有可能查询数据key哈希到一个足够大的bitmap中 , 在查询的时候先去BloomFilter去查询key是否存在,如果不存在就直接返回,存在再去查询缓存,缓存中没有再去查询数据库 ,从而避免了数据库层的压力激增出现宕机。

缓存击穿

缓存击穿,针对某个访问非常频繁的热点数据过期失效,导致访问无法在缓存中进行处理,进而会有导致大量的直接请求数据库,从而使得数据库层的压力激增,严重的会造成数据库宕机。

对于缓存击穿,解决方式:

  • 不设置过期时间,对于访问特别频繁的热点数据,不设置过期时间。

总结

在大多数业务场景下,Redis缓存作为只读缓存使用。针对只读缓存来说, 优先使用先更新数据库再删除缓存的方法保证数据一致性 。

其中,缓存雪崩,缓存穿透,缓存击穿三大问题的原因和解决方式

c4d76bd8e8becaad40575c2be954aaec.png

作者:Ccww
链接:https://juejin.cn/post/6919271744754679815

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

5部适合学英语的动画电影,快和孩子一起看!

全世界只有3.14 % 的人关注了爆炸吧知识今天我们与大家分享5部非常适合小学生学习英语的动画电影,家长们可依据不同类别和主题为孩子挑选喜欢的影片,在家陪孩子一起观看。文末可免费领取哦~01 《丁丁历险记》讲述的是一天丁丁买了一只古老的船模送给船长…

OC面向对象—封装

OC面向对象—封装 一、面向对象和封装 面向对象的三大特性:封装(成员变量)、继承和多态 在OC语言中,使用interface和implementation来处理类。 interface就好像暴露在外面的时钟表面,像外界提供展示以及接口。implemen…

如何把 .NET 进程中的所有托管异常找出来?

大家应该知道 .NET异常 本质上就是一个 Object 对象,也就是说只要你执行了 new XXException() 语句,那么它就会分配到 GC Heap 上。这也就意味着,如果你有一个进程的dump文件,那你就可以从dump中导出程序最近都抛了什么异常&#…

编程题: 将一个矩阵(二维数组)顺时针旋转90度

在一个m*n的矩阵任取一个元素(i, j),发现旋转后对应的元素下标变成:(j, m-i)。 进一步研究一下矩阵的各种翻转可知:沿左上到右下的对角线翻转:(i, j)与(j, i)对换; 沿右上到左下的对角线翻转:(i, j)与(n-j, m-i)对换;上下翻转:(i,…

activiti5.9 mysql_Activiti5.9换成MySQL数据库

Activiti5.9默认的数据库是db,可是我们项目中运用的是mysql,那只好把db换成mysql步骤:1.下载activiti-5.9.zip 2.解压activiti-5.10.zip并移动(ACTIVITI_HOMED:\myspace\activiti-5.9) 3.修改ACTIVITI_HOME\setup\build.db.properties文件&a…

10张让你大脑崩溃的图,敢接受挑战吗?

全世界只有3.14 % 的人关注了爆炸吧知识快睡了吧?来做一组视觉游戏~一些人热爱挑战各种错觉,如果你也是这类型图片的粉丝,这10张图片会让你非常过瘾!入门篇【挑战一】在这张图片中,你能看到几个红球?5个&am…

Hdu 3478 Catch

如果出现遍历图中的某个点都是在奇数时刻或者偶数时刻,那么小偷的藏点就是根据时间判定在某些的奇数点和偶数点了。 如果图出现奇数的环,即:有一个环由奇数个点组成,那么环中的某个点在奇数和偶数时刻都能到达(可以画图试试)。其实…

节点

常用节点类型 节点类型常量 节点类型值 元素节点 element 1 属性节点 attribute 2 文本节点 text 3 注释节点 comment 8 文档…

Source Generator 单元测试

Source Generator 单元测试IntroSource Generator 是 .NET 5.0 以后引入的一个在编译期间动态生成代码的一个机制,介绍可以参考 C# 强大的新特性 Source GeneratorGetStarted使用起来还算比较简单的,我平时一般用 xunit,所以下面的示例也是使…

GetItemValue、Itemname使用方法

使用GetItemValue方法(1) NotesDocument类別的GetItemValue方法会传回文件中指定栏位的数值。不论栏位值是文字、数字、时间日期…等等, GetItemValue都是以阵列型态来回传,即使其中也沒有任何数值了。 使用GetItemValue方法(2) 语法 valueArray NotesD…

mysql二阶段提交有什么问题_MySQL的事务两阶段提交的技术有什么意义?

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":9,"count":9}]},"card":[{"des":"用于处理分布式环境下高性能事务一致性问题。…

又一个中国男人荣获巨奖!拿奖拿的手软,却坦言“我对诺奖没有兴趣”...

全世界只有3.14 % 的人关注了爆炸吧知识获得诺奖似乎只是时间问题2020年9月10日,2021年科学突破奖( BREAKTHROUGH PRIZES)正式公布。来自中国香港的科学家卢煜明获得了生命科学科学突破奖,华人数学家孙崧获得了数学新视野奖。前几…

ffbe攻略站_最终幻想勇气启示录ffbe兵员强化攻略

最终幻想勇气启示录兵员如何强化?兵员强化后有哪些加强?来看看9k9k小编带来的最终幻想勇气启示录ffbe兵员强化攻略。在兵员选栏中,我们可以看到有强化兵员这一选项,在这里面,我们可以选择兵员进行强化,强化…

无法打开物理文件“E:\Database\VRVIES6841-FZ01-Global\VRVEIS.mdf”。操作系统错误 5:“5(拒绝访问。)”...

在用SQLServer2012附加SQLServer2000备份的数据库事,报如下错误: 无法打开物理文件“E:\Database\VRVIES6841-FZ01-Global\VRVEIS.mdf”。操作系统错误 5:“5(拒绝访问。)”。 (Microsoft SQL Server,错误: 5120) 解决方法: 1.先在…

IIS6注册.net4.0

开始----运行---cmd回车-----cd c:/windows/microsoft.net/framework/v4.0.30319回车,然后输入aspnet_regiis.exe -ir 就OK了

不止命令行!自定义VS生成事件

前言在VS中打开项目属性,选择“生成事件”选项卡。在“生成前事件命令行”或“生成后事件命令行”文本框中可以输入任何命令提示符或.bat文件中有效的命令:但是,有没有可能执行更丰富的命令呢?生成事件的本质上面设置的“生成事件…

如果你女朋友不让你看她卸妆......

1 如果你女朋友不让你看她卸妆▼2 扫地机器人的正确用法(图源网络,侵删)▼3 来比个心(素材来源网络,侵删)▼4 精彩攻防战▼5 那些吃辣条的小学生长大了...▼6 人生的道路上有时候也要回头看看▼7 先礼…

[9月29日的脚本] 枚举SharePoint列表(PowerShell)

脚本下载: SPListEnumerator.zip http://gallery.technet.microsoft.com/scriptcenter/SPListEnumerator-PowerShell-b0ce0b9f 本脚本通过一个“大型”列表或者是文档库来枚举并为相关项提供信息。 在SharePoint(2007版和2010版)中,我们有一个…

深入理解javascript函数

函数实际上是对象,每个函数都是Function类型的实例,且与其他类型一样具有属性和方法.由于函数是对象,故函数名即为指向函数的指针,正是由于这一点,函数没有重载,重复定义函数只会后者替换前者. 函数的定义 函数的定义有三种: 函数声明function sum(num1,num2){ return num1num2…

mac mysql php_Mac搭建php开发环境:Apache+php+MySql

前言Windows搭建PHP开发环境很熟练了,要在自己的Mac搭建PHP开发环境还是第一次,因此分享给大家。Mac自带Apache、php,需要自己安装MySql。1.启动Apache// 启动Apache服务sudo apachectl start// 重启Apache服务sudo apachectl restart// 停止Apache服务s…