Redis缓存问题与缓存更新机制

目录

​编辑

 一、缓存问题

 1.1 缓存穿透

 1.1.1 问题来源

 1.1.2 解决方案

 1.1.2.1 缓存空对象

 1.1.2.2 使用布隆过滤器

 1.2 缓存击穿

 1.2.1 问题来源

 1.2.2 解决方案

 1.2.2.1 设置热点数据永远不过期

 1.2.2.2 新增后台定时更新缓存线程(逻辑不过期)

 1.2.2.3 使用分布式互斥锁

 1.2.2.4 接口限流与熔断,降级

 1.3 缓存雪崩

 1.3.1 问题来源

 1.3.2 解决方案

 1.3.2.1 缓存过期时间随机

 1.3.2.2 分布式部署

 1.3.2.3 设置热点数据永远不过期

 1.3.2.4 接口限流与熔断,降级

 二、缓存更新机制

2.1 缓存更新策略分类

 2.2 内存淘汰机制

 2.2.1 noeviction

 2.2.2 volatile-lru

 2.2.3 volatile-lfu

 2.2.4 volatile-ttl

 2.2.5 volatile-random

 2.2.6 allkey-lru

 2.2.7 allkey-lfu

 2.2.8 allkey-random

 2.3 超时剔除

 2.3.1 定时删除

 2.3.2 惰性删除

 2.4 主动更新

 2.4.1 主动更新策略

 2.4.1.1 Cache Aside Pattern

 2.4.1.2 Read/Write Through Pattern

 2.4.1.3 Write Behind Caching Pattern

 2.4.2 主动更新策略需要考虑的三个问题

 2.4.1 删除缓存还是更新缓存?

 2.4.1.1 删除缓存

 2.4.1.2 更新缓存

 2.4.2 如何保证缓存与数据库的操作同时成功或失败?

 2.4.3 先操作缓存还是数据库?

 2.4.3.1 先删除缓存,再操作数据库

2.4.3.2 先操作数据库,再删除缓存

2.4.3.3 延时双删策略

 2.5 缓存更新机制总结


 一、缓存问题

 1.1 缓存穿透

 1.1.1 问题来源

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求。由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

 1.1.2 解决方案

 1.1.2.1 缓存空对象

从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。

 1.1.2.2 使用布隆过滤器

类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小。

 1.2 缓存击穿

 1.2.1 问题来源

缓存击穿是指缓存某些热点数据失效(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

 1.2.2 解决方案

 1.2.2.1 设置热点数据永远不过期

可以在刷缓存时,设置热点数据不过期。

 1.2.2.2 新增后台定时更新缓存线程(逻辑不过期)

后台新增一个缓存更新线程,缓存快要过期前刷新缓存时间,防止缓存失效。

 1.2.2.3 使用分布式互斥锁

可以使用Redis提供的分布式互斥锁,保证只有一个请求查询数据库和更新缓存,其他请求阻塞等待缓存更新完成后在访问缓存。

 1.2.2.4 接口限流与熔断,降级

重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些服务不可用时候,进行熔断,失败快速返回机制。

 1.3 缓存雪崩

 1.3.1 问题来源

缓存雪崩是指Redis缓存不能正常提供服务了(阻塞、服务宕机、大面积缓存失效等造成),导致所有请求都落到了数据库上,增加了数据库压力或者导致数据库宕机。

 1.3.2 解决方案

 1.3.2.1 缓存过期时间随机

缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。

 1.3.2.2 分布式部署

采用分布式部署方式部署缓存,避免缓存服务单节点,同时将热点数据均匀分布在不同的缓存数据库中。

 1.3.2.3 设置热点数据永远不过期

可以在刷缓存时,设置热点数据不过期。

 1.3.2.4 接口限流与熔断,降级

重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些服务不可用时候,进行熔断,失败快速返回机制。

 二、缓存更新机制

2.1 缓存更新策略分类

内存淘汰超时剔除主动更新
说明重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些服务不可用时候,进行熔断,失败快速返回机制。给缓存数据添加TTL时间,到期后自动删除缓存,下次查询时更新缓存编写业务逻辑,在修改数据的同时,更新缓存
一致性一般
维护成本

 2.2 内存淘汰机制

 2.2.1 noeviction

不淘汰,这是默认的淘汰策略;当内存达到限制后,写请求(set)会返回错误,读请求(get)和删除请求(del)可以继续进行

 2.2.2 volatile-lru

内存不足时,在设置了过期时间的key中,优先删除最近最少使用的key

 2.2.3 volatile-lfu

内存不足时,在设置了过期时间的key中,优先删除使用频率最少的key

 2.2.4 volatile-ttl

内存不足时,在设置了过期时间的key中,优先删除存活剩余时间最少的key

 2.2.5 volatile-random

内存不足时,在设置了过期时间的key中,随机删除某个key

 2.2.6 allkey-lru

内存不足时,在全体key范围内,优先删除最近最少使用的key

 2.2.7 allkey-lfu

内存不足时,在全体key范围内,优先删除使用频率最少的key

 2.2.8 allkey-random

内存不足时,在全体key范围内,随机删除某个key

 2.3 超时剔除

 2.3.1 定时删除

设置一个定时任务,随机抽取部分过期时间的key,检查是否过期,过期了就清除掉

 2.3.2 惰性删除

查询获取数据时,检查缓存是否过期,过期则删除,没过期不删除

Redis 默认采用惰性删除+定时删除结合的过期策略

 2.4 主动更新

 2.4.1 主动更新策略

 2.4.1.1 Cache Aside Pattern

由缓存的调用者,在更新数据库的同时更新缓存。

 2.4.1.2 Read/Write Through Pattern

缓存和数据库整合为一个服务,由服务来维护一致性。调用者调用服务,不用关心一致性问题。

 2.4.1.3 Write Behind Caching Pattern

调用者只操作缓存,由其他线程异步的将缓存数据持久化到数据库,最终保持一致。

在企业中使用最多的主动更新策略是 Cache Aside Pattern。也就是我们自己编码来保证数据的一致性。

 2.4.2 主动更新策略需要考虑的三个问题

 2.4.1 删除缓存还是更新缓存?

 2.4.1.1 删除缓存

更新数据库时让缓存失效,查询时再更新缓存。(延迟加载)一般选择这个方案。

这个方案比较合理一点,可以避免过多的无效写操作,缓存删除后,只要没人来查询这条数据,数据就不会被写入缓存,这样就可以避免大量无效的写操作

 2.4.1.2 更新缓存

每次更新数据库都更新缓存,无效写操作比较多。

这种方式的缺点很明显,举个例子:假如我更新了100次数据库,然后又同时更新了100次缓存,但是在更新的时候并没有人来查这个数据,那么我更新这100次缓存好像也没啥用吧,相当于前99次都是无用功,只有最后一次才是有用的。这就是无效写操作过多的原因。

 2.4.2 如何保证缓存与数据库的操作同时成功或失败?

1)单体系统,将缓存与数据库操作放在一个事务中。

2)分布式系统,利用TCC等分布式事务方案。

 2.4.3 先操作缓存还是数据库?

 2.4.3.1 先删除缓存,再操作数据库

这种方式存在很明显的问题,假设有两个并发操作,线程A更新,线程B查询。线程A先删除缓存,然后还没来得及更新数据库,CPU资源被线程B抢走,线程B查询缓存发现没有命中(因为已经被线程A删除了),查询数据库,然后把结果写入到缓存中。这个时候线程A终于抢到CPU资源了,然后更新数据库,此时就会造成数据不一致问题。

2.4.3.2 先操作数据库,再删除缓存

这种处理方式使用的频率是最高的,因为出错的概率非常小,只有一种比较极端的情况才会出现数据一致性问题。

同样有两个并发请求,线程A查询、线程B更新,当线程A查询的时候,缓存刚好失效,然后就去查询数据库拿到数据,在准备写入缓存的时候,CPU资源被线程B抢走,线程B开始更新数据库,然后删除缓存(这一步其实等于无用,因为缓存已经过期)。此时线程A再次获取到CPU资源,然后写入缓存,此时写入的是更新前的旧数据,会产生数据一致性问题。

看起来这确实也是一个问题,但是我们仔细分析一下这种情况都需要满足哪些条件:

1)并发读写操作
2)读缓存时,缓存刚好失效
3)写数据库操作要比写缓存快

写数据库是操作磁盘,写缓存是操作内存的,所以不太可能会出现写磁盘的速度快于写内存的。因此使用这种方式出现数据一致性的概率是很小的。

2.4.3.3 延时双删策略

 

延迟双删策略是分布式系统中数据库存储和缓存数据保持一致性的常用策略,但它不是强一致。其实不管哪种方案,都避免不了Redis存在脏数据的问题,只能减轻这个问题,要想彻底解决,得要用到同步锁和对应的业务逻辑层面解决。

前面两种方案的不足点我们进行了分析,第二种方式的使用频率比较高,但是也有一些小缺陷,虽然说发生的概率很低,但是这个概率到了线上会不会发生也不好说,所以就有了延时双删策略对第二种方式做补充。

所谓延时双删就是先进行缓存清除,再执行数据库操作,最后(延迟N秒)再执行缓存清除。延迟N秒的时间要大于一次写操作的时间,这个延时N秒就是了完善保证第二种策略中不足,可以保证线程A的写缓存和线程B的修改数据库、删除缓存都执行完毕,然后再删除缓存一次,就可以保证后面再来的查询请求可以查询到最新数据。

ps: 一般的延时时间设置为3S左右,具体情况要根据业务场景取最佳值。

 2.5 缓存更新机制总结

1)内存淘汰:不用自己维护,利用Redis内存淘汰机制,自动删除部分缓存数据,这些被删除的数据在下一次被查询时更新。这种方式一致性最差。

2)超时剔除:给缓存数据加上过期时间 ,到期后自动删除,下次查询时更新,数据一致性问题大概率会出现。维护成本比较低。

3)主动更新:编写业务逻辑,在修改数据库的同时更新缓存,一致性比较好,维护成本比较高。一般采用先操作数据库再更新缓存的方式。

一般在数据一致性要求比较低的场景下可以使用内存淘汰机制,比如商城首页的分类信息,这些东西基本上是不会变化的。如果一致性要求比较高,我们可以采用主动更新+超时剔除兜底的方式来处理。

如果觉得对您有帮助,欢迎点赞+收藏+关注!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MFC项目添加外部头文件和源文件后编译出现C1010错误

出现这个问题的主要原因是如果使用VC向生成工程的话&#xff0c;默认使用预编译头文件“stdafx.h”&#xff0c;这样做的目的是为了加快编译速度。 如果加入第三方c/cpp文件没有#include “stdafx.h” &#xff0c;就会报此错误。 在<解决方案管理器中>(就是可以看到工程…

Git 常用操作总结

版本控制系统&#xff08;VCS&#xff09;是管理文件和目录所做的更改的工具&#xff0c;每一次提交便记录下目录及其文件的内容&#xff0c;以及较上一版本的更改。通过这样去跟踪项目的更改过程&#xff0c;方便与他人进行协作&#xff0c;或者撤销不想要的更改以回退到此前的…

10 Web全栈 组件化设计

前端架构层次设计 前端技术体系庞大&#xff0c;层级也非常分明&#xff0c;在架构设计领域中不能一概而论&#xff0c;任何应用种类都有自己独立的架构体系。比如在前端开发领域&#xff0c;在框架基础上进行应用构建的开发者锁思考的问题&#xff0c;与在组件库设计方面的开…

【文件 part 6 - 格式化读写文件函数 随机读写】

格式化读写文件函数 /* 函数调用: */ fprintf ( 文件指针&#xff0c;格式字符串&#xff0c;输出表列&#xff09;&#xff1b; fscanf ( 文件指针&#xff0c;格式字符串&#xff0c;输入表列&#xff09;&#xff1b;/** 函数功能:* 从磁盘文件中读入或输出字符* fprint…

SAP从入门到放弃系列之生产订单结算

文章目录概览 一、概述二、结算的模式2.1、订单相关的成本归集2.2、产品相关的成本归集 最后 一、概述 当生产从计划到订单&#xff0c;生产领料、投料、报工、入库整个生产流程完成后&#xff0c;生产订单中会产生对应的财务数据&#xff0c;或者说借贷项数据&#xff08;材料…

npm启动,node.js版本过高

“dev_t”: “set NODE_OPTIONS”–openssl-legacy-provider" & npm run dev\n"

Ubuntu安装碰撞检测库FCL以及前置依赖libccd, OctoMap

Ubuntu安装碰撞检测库FCL以及前置依赖libccd, OctoMap 大致安装流程见FCL github地址&#xff0c;但是在安装libccd时存在一些问题。 建议完整浏览后再进行安装 1.编译libccd的报错 首先FCL页面已经说明libccd要直接克隆源码&#xff0c;不要下载压缩包。 其次&#xff0c;在…

MAYA传送带上放石头(新旧粒子系统)

播放试试 使用老的粒子系统 particleShape1.shuliangrand(0,5); particleShape1.daxiao<<rand(0.2,0.5),rand(0.2,0.5),rand(0.2,0.5)>>; particleShape1.xuanzhuan<<rand(360),rand(360),rand(360)>>; 使用新的粒子系统 粒子向后滑落 新粒子系统能进行…

SSMP整合案例(11) 在界面中实现添加操作

上文 SSMP整合案例(10) vue端调整项目环境 发送请求 基本界面编写我们搭建了基本的页面结构 然后 我们来做个新增的功能 首先 新增 我们肯定是用户点击了这个新建之后 我们再来处理这个逻辑 我们之前的代码 新增是有绑定 一个事件的 但是这个 AddBook中并没有内容 首先 我们…

4.44ue4:相机抖动

1.创建相机抖动类 右键内容面板&#xff0c;点击创建蓝图类&#xff0c;搜索shake&#xff08;camera shake&#xff09; 2.使用相机抖动&#xff1a; 节点&#xff1a;play world .. api解释&#xff1a; epicenter&#xff1a;震源 inner Radius&#xff1a;内圈范围&a…

【梦辛工作室】java实现简易消息队列处理器 可分区 分区顺序消费MxMQ

大家好哇&#xff0c;又是我&#xff0c;梦辛工作室的灵&#xff0c;最近在巩固JUC并发包&#xff0c;突然想到如果自己的应用体量不大&#xff0c;但有需要消息队列来实现应用解耦和削峰来缓解服务器突增压力&#xff0c;比如抢票时&#xff0c;突然有比较用户同时抢票&#x…

分布式运用——rsync远程同步

分布式运用——rsync远程同步 一、rsync的背景和原理1.rsync的功能2.rsync的应用场景3.使用rsync的基本命令4.scp与rsync的区别 二、配置rsync源服务器1.关闭防火墙2.建立/etc/rsyncd.conf 配置文件3.保证所有用户对源目录/var/www/html 都有读取权限4.启动 rsync 服务程序5.关…

flutter3.7版本下使用flutter boost解决使用platview崩溃或异常问题

背景 工程使用了混合开发&#xff0c;使用flutter boost插件&#xff0c;flutter 的activity1 frament1 跳转activity2 frament2&#xff0c;frament1 包含platformView&#xff0c;按照上面老哥解决崩溃问题的基础上&#xff0c;出现activity2 frament2返回activity1 framen…

“未来之光:揭秘创新科技下的挂灯魅力“

写在前面&#xff1a; 高度信息化当下时代&#xff0c;对电脑及数字设备的需求与日俱增无处不在&#xff0c;随之而来的视觉疲劳和眼睛问题也攀升到了前所未有的高度。传统台灯对于长时间使用电脑的人群来说是完全无法解决这些问题的。一款ScreenBar Halo 屏幕挂灯&#xff0c;…

数学建模——插值(下)

本文是面向数学建模准备的&#xff0c;是介绍性文章&#xff0c;没有过多关于原理的说明&#xff01;&#xff01;&#xff01; 目录 一、2维插值原理及公式 1、二维插值问题 2、最邻近插值 3、分片线性插值 4、双线性插值 5、二维样条插值 二、二维插值及其Matlab工具箱…

微信小程序

私人博客 许小墨のBlog —— 菜鸡博客直通车 系列文章完整版&#xff0c;配图更多&#xff0c;CSDN博文图片需要手动上传&#xff0c;因此文章配图较少&#xff0c;看不懂的可以去菜鸡博客参考一下配图&#xff01; 系列文章目录 前端系列文章——传送门 后端系列文章——传送…

opencv使用applyColorMap()函数,可以将灰度图或彩色图转换成自定义的彩色图,或opencv提供的20多种色彩值

文章目录 1、applyColorMap()函数的使用&#xff1a;&#xff08;1&#xff09;函数原型&#xff1a;void applyColorMap(InputArray src, OutputArray dst, int colormap)void applyColorMap(InputArray src, OutputArray dst, InputArray userColor) &#xff08;2&#xff0…

利用Python构建宁德时代、比亚迪、隆基绿能股票时间序列预测模型

存货 import tushare as ts # 导包 import numpy as np import matplotlib.pyplot as plt from scipy.signal import find_peaks from scipy.stats import norm import datetime import pandas as pd import seaborn as sns # pip install seaborn import matplotlib.patches …

WideNet:让网络更宽而不是更深

这是新加坡国立大学在2022 aaai发布的一篇论文。WideNet是一种参数有效的框架&#xff0c;它的方向是更宽而不是更深。通过混合专家(MoE)代替前馈网络(FFN)&#xff0c;使模型沿宽度缩放。使用单独LN用于转换各种语义表示&#xff0c;而不是共享权重。 混合专家(MoEs) 条件计…

数通王国历险记之TCP协议下的三大协议的验证实验

系列文章目录 数通王国历险记&#xff08;1&#xff09; 前言 一&#xff0c;我们要先知道PDU是什么&#xff1f; 二、TCP协议下的三大协议的验证实验 1.FTP的验证实验 1&#xff0c;拓扑图 2.将lsw4配置一下 3&#xff0c;FTP服务器端开启FTP服务&#xff1a; 4&#x…