(五)Redis 缓存异常、应对策略

redis · 浏览次数 : 59

小编点评

缓存和数据库一致性保证 一、缓存与数据库一致性 缓存和数据库之间的数据一致性问题主要涉及到两个方面:缓存中有数据且与数据库中的值相同,以及缓存中没有数据,最新值在数据库中。 对于读写缓存,为了保证缓存和数据库中的数据保持一致,可以采用同步直写策略。在业务应用中,使用事务机制来保证缓存和数据库的更新具有原子性。对于数据一致性要求不高的场景,可以使用异步写回策略。 只读缓存在新增数据时符合数据一致性第二种情况,但在删改数据时,如果操作缓存或数据库失败,可能导致数据不一致。为了解决这个问题,可以采用重试机制,将数据暂存到消息队列中,然后重新进行删除或更新。如果操作成功,则从消息队列中移除数据,避免重复操作。 二、缓存雪崩 大量应用请求无法在 Redis 缓存中进行处理,导致数据库压力激增。雪崩的原因主要有两个方面:一是缓存中有大量数据同时过期;二是 Redis 缓存实例挂了。 解决方法包括:微调过期时间,对于同一批数据设置不同的过期时间;降级处理,非核心数据请求直接返回空或错误等预置信息;熔断,拒绝缓存客户端的请求,保护数据库;限流,允许部分请求到达 Redis 缓存,无法命中再访问数据库。 三、缓存击穿 针对某个热点数据的请求无法在缓存中处理,大量访问该数据的请求发送到了后端数据库,压力激增影响到其他请求。为了避免缓存击穿给数据库带来的激增压力,对于访问特别频繁的热点数据,可以不设置过期时间,全部在缓存中进行处理。 四、缓存穿透 要访问的数据既不在 Redis 缓存中,也不在数据库中,导致请求压力落到数据库,缓存也就成了“摆设”。穿透的原因主要有两种:一是业务数据被误删除;二是恶意攻击访问。 解决方法包括:缓存空值或缺省值;布隆过滤器;前端请求过滤。 五、总结 雪崩、击穿、穿透这三类异常问题从成因来看,前两个主要是因为数据不在缓存中了,而穿透则是因为数据既不在缓存中,也不在数据库中。当雪崩或击穿发生时,一旦数据库中的数据被再次写入到缓存后,应用又可以在缓存中快速访问数据了,数据库的压力也会相应地降低,而穿透发生时,Redis 缓存和数据库会同时持续承受请求压力。对应的熔断、降级、限流这些方法都是属于“有损”方案,在保证数据库和整体系统稳定的同时,会对业务应用带来负面影响。

正文

1、缓存和数据库不一致

只要我们使用 Redis 缓存,就必然会面对缓存和数据库间的一致性保证问题,这里的“一致性”包含了两种情况:缓存中有数据且与数据库中的值相同、缓存中没有数据,最新值在数据库中。

对于读写缓存来说,要想保证缓存和数据库中的数据一致,就要采用同步直写策略,在业务应用中使用事务机制,来保证缓存和数据库的更新具有原子性。对数据一致性的要求不高的场景,可以使用异步写回策略。

只读缓存在新增数据时是符合数据一致性第二种情况的,但是在删改数据时,无论是操作缓存还是操作数据库,有一项失败,就会产生数据不一致的问题。具体情况如图:
针对这种情况可以引用重试机制来解决,具体来说,可以把要数据暂存到消息队列中。无论哪项操作失败,都可以从消息队列中重新读取这些值,然后再次进行删除或更新。如果删改成功,就把数据从消息队列中去除,以免重复操作,以此来保证数据一致性。多次重试仍然失败的话就需要业务层面预警来排查解决了。

除了操作失败的原因,实际当有大量并发请求时,应用还是有可能读到不一致的数据。根据删改缓存、数据库的先后顺序分为两种情况:先操作缓存和先操作数据库。通过引用“延迟双删”的操作,来保证先操作缓存后操作数据库的数据一致性问题,代码示意如下:

redis.delKey(X)
db.update(X)
Thread.sleep(N)
redis.delKey(X)

具体情况与应对措施总结如图:

2、雪崩

指大量的应用请求无法在 Redis 缓存中进行处理,到达数据库层面,导致数据库的压力激增。原因有二:
其一,缓存中有大量数据同时过期。
其二,Redis 缓存实例挂了。

原因一可以通过以下两个方法解决:
(1)微调过期时间:对于同一批数据设置不同的过期时间,如通过随机数延迟过期等。
(2)降级处理:非核心数据请求直接返回 空 或 错误 等预置信息,核心数据运行未命中缓存访问数据库。

原因二可以通过以下两个方法解决:
(1)熔断:拒绝缓存客户端的请求,保护数据库,防止整个系统崩溃,直到 Redis 缓存实例恢复正常,但是对业务应用的影响范围大。
(2)限流:允许部分请求到达 Redis 缓存,无法命中再访问数据库,减轻数据库压力,相对于熔断来说影响范围稍微缩小。
无论采取何种措施,雪崩都已经发生了,必定会影响到业务系统,所以要做好预防工作,构建 Redis 缓存高可靠集群,尽量避免事故。

3、击穿

指针对某个热点数据的请求,无法在缓存中处理,大量访问该数据的请求发送到了后端数据库,压力激增影响到其他请求,如下图:
为了避免缓存击穿给数据库带来的激增压力,对于访问特别频繁的热点数据,可以不设置过期时间了,全部在缓存中进行处理。

4、穿透

指要访问的数据既不在 Redis 缓存中,也不在数据库中,导致请求压力还是落到数据库,缓存也就成了“摆设”。如下图:
通常情况是由于业务数据被误删除,或者恶意攻击访问,有三种方案解决缓存穿透的影响:
(1)缓存空值或缺省值:针对穿透的数据,在 Redis 中缓存一个空值或是和业务层协商确定的缺省值,避免把大量请求发送给数据库。
(2)布隆过滤器
布隆过滤器由一个初值都为 0 的 bit 数组和 N 个哈希函数组成,数据入库则进行标记,过程如下:

  • 使用 N 个哈希函数,分别计算这个数据的哈希值,得到 N 个哈希值。
  • 我们把这 N 个哈希值对 bit 数组的长度取模,得到每个哈希值在数组中的对应位置。
  • 我们把对应位置的 bit 位设置为 1,这就完成了在布隆过滤器中标记数据的操作。

当查询某个数据时,按照哈希函数的计算结果,查看 bit 数组中这 N 个位置上的 bit 值,只要有一个不为 1,这就表明布隆过滤器没有对该数据做过标记。当缓存穿透发生,布隆过滤器的快速检测特性可以帮数据库阻挡大部分的压力。例子如下图:
(3)前端请求过滤:在请求入口前端进行合法性检测,把恶意的请求(如请求参数不合理、非法值或请求字段不存在)直接过滤掉。

小结

雪崩、击穿、穿透,这三类异常问题从成因来看,前两个主要是因为数据不在缓存中了,而穿透则是因为数据既不在缓存中,也不在数据库中。当雪崩或击穿发生时,一旦数据库中的数据被再次写入到缓存后,应用又可以在缓存中快速访问数据了,数据库的压力也会相应地降低,而穿透发生时,Redis 缓存和数据库会同时持续承受请求压力。

对应的熔断、降级、限流这些方法都是属于“有损”方案,在保证数据库和整体系统稳定的同时,会对业务应用带来负面影响。降级时,有部分数据的请求就只能得到错误返回信息,无法正常处理。熔断时,整个缓存系统暂停,影响的业务范围更大。流机时,整个业务系统的吞吐率会降低,并发处理能力减弱,影响到用户体验。

所以,应当尽量使用预防式方案,总结如下:

  • 雪崩,合理地设置数据过期时间,以及搭建高可靠缓存集群。
  • 击穿,在缓存访问非常频繁的热点数据时,不要设置过期时间。
  • 穿透,提前在入口前端实现恶意请求检测,或者规范数据库的数据删除操作,避免误删除。

与(五)Redis 缓存异常、应对策略相似的内容:

(五)Redis 缓存异常、应对策略

1、缓存和数据库不一致 只要我们使用 Redis 缓存,就必然会面对缓存和数据库间的一致性保证问题,这里的“一致性”包含了两种情况:缓存中有数据且与数据库中的值相同、缓存中没有数据,最新值在数据库中。 对于读写缓存来说,要想保证缓存和数据库中的数据一致,就要采用同步直写策略,在业务应用中使用事务机制

[转帖]Redis学习五(Spring Cache For Redis).

https://www.cnblogs.com/jmcui/p/8410560.html 一、概述 缓存(Caching)可以存储经常会用到的信息,这样每次需要的时候,这些信息都是立即可用的。 常用的缓存数据库: Redis 使用内存存储(in-memory)的非关系数据库,字符串、列表、集合、散列

[转帖]Redis进阶实践之五Redis的高级特性

https://www.cnblogs.com/PatrickLiu/p/8341951.html 一、引言 上一篇文章写了Redis的特征,使用场景,同时也介绍了Redis的基本数据类型,redis的数据类型是操作redis的基础,这个必须好好的掌握。今天我们开始介绍一些Redis的高级特性,虽然

[转帖]redis惰性删除 lazy free 源码剖析,干货满满

目录 前言 数据删除场景 lazy free 概念 配置 源码剖析(版本 6.2.6) 场景一:客户端执行的显示删除/清除命令 场景二:某些指令带有的隐式删除命令 场景三:删除过期数据 场景四:内存淘汰数据删除 场景五:主从同步清空从库 小结 前言 都说 redis 是单线程的,其实并不是说 red

文心一言 VS 讯飞星火 VS chatgpt (107)-- 算法导论10.1 5题

五、用go语言,栈插入和删除元素只能在同一端进行,队列的插入操作和删除操作分别在两端进行,与它们不同的,有一种双端队列(deque),其插入和删除操作都可以在两端进行。写出4个时间均为 O(1)的过程,分别实现在双端队列的两端插入和删除元素的操作,该队列是用一个数组实现的。 文心一言: 在 Go 语

文件系统(五):exFAT 文件系统原理详解

前言 exFAT是微软2006年推出的一种文件系统,距今已快二十年,相比于FAT16和FAT32,exFAT还是算年轻。exFAT一直是微软的一个专用文件系统,直到2019年微软发布它的规范,目前微软拥有exFAT多个元素的专利,如果产品上使用exFAT,需要微软授权,否则有可能侵权。 exFAT被

架构设计(五):有状态服务和无状态服务

架构设计(五):有状态服务和无状态服务 作者:Grey 原文地址: 博客园:架构设计(五):有状态服务和无状态服务 CSDN:架构设计(五):有状态服务和无状态服务 无状态的服务 在横向扩展服务的过程中,将状态(例如用户会话数据)从服务中移出并将会话数据存储在持久性存储介质中,如关系型数据库或 No

ComfyUI进阶:Comfyroll插件 (五)

ComfyUI进阶:Comfyroll插件 (五)前言:学习ComfyUI是一场持久战,而Comfyroll 是一款功能强大的自定义节点集合,专为 ComfyUI 用户打造,旨在提供更加丰富和专业的图像生成与编辑工具。借助这些节点,用户可以在静态图像的精细调整和动态动画的复杂构建方面进行深入探索。C

【Playwright+Python】系列教程(五)元素定位

一、常见元素定位 定位器是 Playwright 自动等待和重试能力的核心部分。简而言之,定位器代表了一种随时在页面上查找元素的方法,以下是常用的内置定位器。 1、按角色定位 按显式和隐式可访问性属性进行定位 语法:page.get_by_role() Dom结构示例1: 示例代码1: page.g

数据库实验五:数据库编程

2、设计一个小型的数据库应用程序  可利用现有的数据库,也可重新设计数据库。  要求实现数据的增加、删除、修改、查询的功能。  在报告中描述清楚使用的数据库、数据表及实现的功能(要求截图,并附 代码) 设计一个小型的数据库应用程序 数据库名:student 表名:infor 字段: Sno:学