当前位置: 首页 > news >正文

Redis学习路线(4)—— Redis实现项目缓存

一、什么是缓存

(一)概念:缓存就是数据交换的缓冲区(称为Cache),是存储数据的临时区域,一般读写性能较高。

(二)常见缓存: 浏览器缓存,服务器缓存,数据库缓存,CPU缓存,磁盘缓存。

(三)缓存的作用:

  • 降低后端负载
  • 提高读写效率,降低响应时间

(四)缓存的成本:

  • 数据一致性成本
  • 代码维护成本
  • 运维成本

二、缓存更新策略

(一)三种更新策略的对比

内存淘汰超时剔除主动更新
说明Redis提供的内存淘汰机制,当内存不足时自动淘汰部分数据,下次查询时更新缓存给缓存数据添加TTL,到期后自动删除缓存,下次查询时更新缓存编写业务逻辑,在修改数据库的同时更新缓存
一致性一般
维护成本

(二)业务场景

  • 低一致性需求: 使用内存淘汰机制,主要是针对几乎不改变的数据。
  • 高一致性需求: 主动更新,并以超时剔除作为协助方案,主要是针对频繁查询的缓存。

(三)主动更新策略

  • (1)Cache Aside Pattern: 由缓存调用者,同时更新数据库和缓存。(可控性更高)
    • 删除缓存还是更新缓存?
      • 更新缓存: 每次更新数据库都更新缓存,无效写操作较多。
      • 删除缓存: 更新数据库时让缓存失效,查询时再更新缓存。
    • (2)如何保证缓存与数据库的操作同时成功或失败?
      • 单体系统: 将缓存与数据库操作放在一个事务。
      • 分布式系统: 利用TCC等分布式事务方案。
    • (3)先操作缓存还是先操作数据库?
      • 先删除缓存,在操作数据库。
      • 先操作数据库,在删除缓存。(保证一致性的概率更高)
  • Read/Write Through Pattern: 缓存与数据库整合为一个服务,由服务来维护一致性。调用者调用该服务,无需关心缓存一致性问题。
  • Write Behind Caching Pattern: 调用者只操作缓存,由其它线程异步的将缓存数据持久化到数据库,保证最终一致。

三、缓存穿透、缓存雪崩、缓存击穿

(一)缓存穿透

1、缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。

2、缓存穿透过程: 客户端发送不存在的id 》 Redis按照 id 查询(未查询到) 》 数据库根据 id 查询(未查询到) 》 返回客户端 》 客户端发送不存在的id。(这个过程若采用多线程循环攻击数据库,那么就会造成数据库带宽爆满,请求阻塞,系统资源耗尽等等问题)

3、缓存穿透常用解决方案:

  • (1)缓存空对象: 在用户第一次查询缓存和数据库时,都没有对应的值,则在缓存中存储一个对应的空值,并设置一个短期的TTL,当恶意用户短期内发起请求时,都会在缓存中查找到对应的值,避免了缓存穿透。
    • 优点: 实现简单,维护方便
    • 缺点: 额外的内存消耗、可能造成短期的不一致
  • (2)布隆过滤: 通过布隆过滤器,在客户端和Redis之间做一道防火墙,当用户访问到布隆过滤器时,布隆过滤器会查询自身是否存在请求值,若不存在则拒绝,若存在则放行查询。
    • 优点: 内存占用较少,没有多余key
    • 缺点: 实现复杂,存在误判可能
  • (3)增强id复杂度,避免被猜测id规律
  • (4)做好数据的基础格式校验
  • (5)加强用户权限校验
  • (6)做好热点参数的限流

4、布隆过滤器: 一种算法,通过将数据库的数据进行某一种hash值计算,并将这些hash值转化为二进制位存储到布隆过滤器中,客户端发送的请求中的数据,通过hash计算转化为二进制位在布隆过滤器中查找,若能找到则说明存在该数据。

(二)缓存雪崩

1、缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库。

2、缓存雪崩的过程: 客户端请求数据 》 Redis查询(Redis部分缓存缺失或Redis宕机) 》 查询数据库(大量请求到达,把数据库也给宕机了)

3、解决方案:

  • (1)给不同的key的TTL添加随机值(避免同时失效)
  • (2)利用Redis集群提高服务的可用性(Redis哨兵机制监听选举主Redis,主从Redis保证数据安全性)
  • (3)给缓存业务添加降级限流策略
  • (4)给业务添加多级缓存

(三)缓存击穿

1、缓存击穿是指高并发缓存重建业务复杂的key突然失效,无数的请求访问在瞬间给数据库带来巨大的冲击。

2、常见的解决方案:

  • (1)互斥锁: 在一个线程进入缓存重建阶段时,获取互斥锁,其它线程无法进行获取互斥锁,并自旋尝试获取锁,直到互斥锁释放。
    • 缺点: 线程锁住了缓存,时间过长会造成业务阻塞。
  • (2)逻辑过期: 在存储一个数据时,添加一个逻辑上的过期时间,到期后直接移除即可。

3、两种解决方案的区别

解决方案优点缺点
互斥锁
  • 没有额外的内存消耗
  • 保证一致性
  • 实现简单
  • 线程需要等待,性能受影响
  • 可能发生死锁
逻辑过期
  • 现成无需等待,性能较好
  • 不保证一致性
  • 有额外内存消耗
  • 实现复杂

四、缓存工具封装

基于StringRedisTemplate封装一个缓存工具类。

  • 方法1: 将任意Java对象序列化为json并存储在string类型的key中,并设置TTL过期时间。
  • 方法2: 将任意Java对象序列化为json并存储在string类型的key中,并可以设置逻辑过期时间,用于处理缓存击穿问题。
  • 方法3: 根据指定key查询缓存,并反序列化为指定类型,利用缓存空值的方式解决缓存穿透问题。
  • 方法4: 根据指定key查询缓存,并反序列化为指定类型,需要利用逻辑过期解决缓存击穿问题。

(一)工具类

@Slf4j
@Component
public class CacheClient {private final StringRedisTemplate redisTemplate;public CacheClient(StringRedisTemplate redisTempalte) {this.redisTemplate = redisTempalte;}public String toJsonStr(Object value) {return JSONObject.toJSONString(value)}public <T> String toJsonObj(String json, Class<T> type) {return JSONObject.parseObject(json, type)}}

(二)实现缓存工具方法

方法1:序列化并设置TTL

	public void set(String key, Object data, Long time, TimeUnit unit) {redisTemplate.opsForValue().set(key, this.toJsonStr(data), time, unit);}

方法2:序列化并设置逻辑过期

	public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {//1、设置逻辑过期,RedisData -> (R Data, LocalDateTime dateTime)RedisData redisData = new RedisData(value, LocalDateTime.now().plusSeconds(unit.toSeconds(time)));//2、RedisData 写入RedisredisTemplate.opsForValue().set(key, this.toJsonStr(redisData));}

方法3:缓存空值解决缓存穿透

	public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit) {//1、查看Cache是否命中String key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);if(!json.isEmpty()){//命中,判断为有值,直接返回return this.toJsonObj(json, type);}if(Objects.isNull(json)){//命中,判断为空白,返回错误信息return null;}//未命中,查看数据库R r = dbFallback.apply(id);//若不存在对应数据,则打入Redis一个空值,并返回错误信息if (r == null) {redisTemplate.opsForValue().set(key, "", 2, TimeUnit.MINUTES);return null;}//若存在,则返回并设置TTLthis.set(key, r, time, unit);//返回该值return r;}

方法4: 逻辑过期解决缓存击穿

public <R, ID> R queryWithLogicalExpire(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit){//1、查看Cache是否命中String key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);if(Objects.isEmpty(json)){//命中,判断为空白,返回错误信息return null;}RedisData redisData = this.toJsonObject(json, Redis.Class);R r = type.cast(redisData.getData());LocalDateTime time = redisData.getDateTime();//若逻辑时间小于现实时间则返回当前对象if(time.isBefore(LocalDateTime.now())){redisData = JSON.parseObject(json, RedisData.class);if(redisData.getDateTime < LocalDateTime.now()){return type.cast(redisData.getData());}}//过期了,获取互斥锁String lockKey = "lock:shop:"+id;boolean isLock = tryLock(lockKey);//尝试获取互斥锁,如果事变,则睡眠重试if(!isLock){//失败则休眠后重试Thread.sleep(50);return queryWithLogicalExpire(keyPrefix, id, type, dbFallback, time, unit);}// 重建数据Executors.newFixedThreadPool(10).submit(() -> {try{//	查询数据库R r1 = dbFallback.apply(id);this.setWithLogicalExpire(id, r1, time, unit);}catch(Exception e){throw new RuntimeException(e);}finally{unlock(lockKey);}});return r;
}private boolean tryLock(String key) {Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "", 10, TimeUnit.SECONDS);return Boolean.getBoolean(flag);
}private void unlock(String key) {redisTemplate.delete(key);
}

相关文章:

Redis学习路线(4)—— Redis实现项目缓存

一、什么是缓存 &#xff08;一&#xff09;概念&#xff1a;缓存就是数据交换的缓冲区&#xff08;称为Cache&#xff09;&#xff0c;是存储数据的临时区域&#xff0c;一般读写性能较高。 &#xff08;二&#xff09;常见缓存&#xff1a; 浏览器缓存&#xff0c;服务器缓…...

【Unity造轮子】实现一个类csgo的武器轮盘功能

文章目录 前言素材导入开始1.放背景和中间的圆圈&#xff0c;调整合适的宽高和位置2.添加选择图像框3.添加一些武器道具选择4.书写脚本RadialMenuManager5.绑定脚本和对象6.运行效果&#xff0c;按tab键开启关闭轮盘7.优化添加显示选中的武器文本8.添加鼠标选中放大的效果9.添加…...

代码随想录算法训练营第三十天 | 单调栈系列复习

单调栈系列复习 每日温度未看解答自己编写的青春版重点题解的代码日后再次复习重新写 下一个更大元素 I未看解答自己编写的青春版重点题解的代码日后再次复习重新写 下一个更大元素II未看解答自己编写的青春版重点题解的代码日后再次复习重新写 接雨水未看解答自己编写的青春版…...

redis数据未到过期时间被删除

1. 问题描述 使用了jeecgboot开发后端代码&#xff0c;代码设置的redis过期时间为24小时&#xff0c;部署使用的宝塔面板&#xff0c;在redis中看到的过期时间也是为24小时&#xff0c;但是并未到过期时间&#xff0c;数据就被删除。 2. 解决办法 观察了一下redis中的数据&a…...

32.选择器

选择器 html部分 <div class"toggle-container"><input type"checkbox" id"good" class"toggle"><label for"good" class"label"><div class"ball"></div></label&…...

Linux--验证命令行上运行的程序的父进程是bash

1.输入以下代码&#xff1a; #include <stdio.h> #include <unistd.h> int main() {printf("hello world: pid: %d, ppid: %d\n",getpid(),getppid());return 0; }2.编译得到可执行程序​​​ 3.运行得到ppid 4.输入指令 ps axj | head -1 &&am…...

MySQL数据库关于表的一系列操作

MySQL中的数据类型 varchar 动态字符串类型&#xff08;最长255位&#xff09;&#xff0c;可以根据实际长度来动态分配空间&#xff0c;例如&#xff1a;varchar(100) char 定长字符串&#xff08;最长255位&#xff09;&#xff0c;存储空间是固定的&#xff0c;例如&#…...

Spring基于注解管理bean及全注解开发

文章目录 spring概述Spring定义Spring核心Spring Framework的特点 基于注解管理bean依赖开启组件扫描使用注解定义Bean案例:Autowired注入属性注入set注入形参上注入只有一个构造函数&#xff0c;无注解Autowire注解和Qualifier注解联合 Resource注入Spring全注解开发 spring概…...

QtC++ 技术分析3 - IOStream

目录 iostreamscanf/printfiostream 整体架构流相关类流缓冲区 模板特化后整体结构文件流文件流对象创建常见文件流操作输出格式设定文件流状态 字符串流字符串流内部缓冲区字符串流使用 流缓冲区用户自定义 IO iostream scanf/printf 几种常见的输入输出流函数 scanf 从键盘…...

2023年Q2京东环境电器市场数据分析(京东数据产品)

今年Q2&#xff0c;环境电器市场中不少类目表现亮眼&#xff0c;尤其是以净水器、空气净化器、除湿机等为代表的环境健康电器。此外&#xff0c;像冷风扇这类具有强季节性特征的电器也呈现出比较好的增长态势。 接下来&#xff0c;结合具体数据我们一起来分析Q2环境电器市场中…...

TCP/UDP的首部

TCP/UDP首部信息 TCP首部第一个4字节第二个4字节与第三个4字节第四个4字节第五个4字节选项最大报文段长度&#xff08;MSS&#xff09;选项窗口扩大选项时间戳选项 什么时候发送RST包UDP首部 TCP首部 TCP 首部长度为20字节&#xff0c;加上选项部分最大可达60字节。 第一个4…...

Kubernetes(K8s)从入门到精通系列之四:K8s的基本概念和术语之集群类

Kubernetes K8s从入门到精通系列之四:K8s的基本概念和术语之集群类 一、Master二、Node三、命名空间集群表示一个由Master和Node组成的K8s集群。 一、Master Master指的是集群的控制节点。在每个K8s集群都需要有一个或一组被称为Master的节点,来负责整个集群的管理和控制。M…...

黑马头条---day1

手机端查看 docker 容器&#xff0c;镜像操作命令 1、docker删除所有镜像命令 删除所有镜像的命令是Docker中一个非常常见的操作。下面是具体的实现步骤和命令示例&#xff1a; $ docker stop $(docker ps -aq) 停止所有正在运行的容器。 $ docker rm $(docker ps -aq) 删…...

【序列化工具JdkSerialize和Protostuff】

序列化工具对比 JdkSerialize&#xff1a;java内置的序列化能将实现了Serilazable接口的对象进行序列化和反序列化&#xff0c; ObjectOutputStream的writeObject()方法可序列化对象生成字节数组 Protostuff&#xff1a;google开源的protostuff采用更为紧凑的二进制数组&#…...

C++ 多线程编程导论(下)

文章目录 参考资料线程安全&#xff08;续&#xff09;门闩与屏障——latch 对象与 barrier 对象门闩&#xff08;latch&#xff09;屏障&#xff08;barrier&#xff09; 一次性调用——once_flag 对象与 call_once 函数 异步任务未来与承诺——future 对象与 promise 对象fut…...

Java并发系列之一:JVM线程模型

什么是线程模型&#xff1a; Java字节码运行在JVM中&#xff0c;JVM运行在各个操作系统上。所以当JVM想要进行线程创建回收这种操作时&#xff0c;势必需要调用操作系统的相关接口。也就是说&#xff0c;JVM线程与操作系统线程之间存在着某种映射关系&#xff0c;这两种不同维…...

容灾独家技术揭秘:HyperBDR无主机数据同步技术

01、一对一单机热备-传统灾备方式 单机热备是一种备份解决方案&#xff0c;它使用两台服务器来确保高可用性&#xff0c;是市场上最为常见的灾备模式。 在单机热备中&#xff0c;一台主服务器和一台备用服务器保持同步&#xff0c;以确保在主服务器出现故障或宕机时可以立即切换…...

FANUC机器人SRVO-050碰撞检测报警和SRVO-053干扰值过大故障报警总结

FANUC机器人SRVO-050碰撞检测报警和SRVO-053干扰值过大故障报警总结 前面和大家分享了关于SRVO-050碰撞检测报警和SRVO-053干扰值过大的原因分析以及处理方法,感兴趣的朋友可以参考以下链接中的内容: FANUC机器人SRVO-050碰撞检测报警原因分析及处理对策...

微信如何提高回复信息速度?

规范流程话术有什么用&#xff1f;为了提高回复客户的效率和质量&#xff0c;可以事先设计好的一套标准化的对话模板。它通常包括多个环节和问题&#xff0c;帮助客服人员或销售人员在与客户沟通时&#xff0c;按照标准化的流程进行&#xff0c;以提高工作效率和客户满意度。 如…...

模拟Stevens Lewis描述的小型飞机纵向动力学的非线性动态反演控制器研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 针对Stevens和Lewis描述的小型飞机纵向动力学的非线性动态&#xff0c;研究非线性动态反演控制器可以是一个有趣的课题。动态反演控制器的目标…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...