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

Redis进阶

Redis是一种key-value的数据库,key一般是String类型,value的类型多种多样,redis的数据结构通常指的都是value的类型

什么是缓存?

缓存就是数据交换的缓存区(Cache),是存储数据的临时地方,读写性能较高

缓存的作用

降低后端的负载(数据库压力)

提高读写效率,降低响应时间

缓存的成本

数据一致性成本(双写一致问题)

代码维护成本(缓存三兄弟)

运维成本(高可用,集群模式)

一.Spring框架集成Redis的Java客户端

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis

1.提供了对不同Redis客户端的整合(Lettuce和Jedis,SpringBoot2.x起默认选择Lettuce)

2.提供了RedisTemplate统一API来操作Redis

3.支持Redis哨兵和Redis集群

4.支持基于JDK,JSON,字符串,String对象的数据序列化及反序列化

SpringDataRedis的序列化方式

首先介绍什么是序列化?什么是反序列化?

序列化:在数据传输的时候,将内存中的对象转换为可以存储或传输的格式(字节流)的过程

反序列化:将存储或传输的格式转换回内存中的对象的过程

SpringDataRedis默认使用的是JDK中提供的序列化工具,通常我们在使用RedisTemple时都会写一个配置类,将序列化器和反序列化器改为String方式,来对对象进行序列化,反序列化

那么为什么需要我们重新指定序列化器和反序列化器,为什么不使用默认提供的jdk中的序列化器和反序列化器?

首先我们要知道,在网络传输过程中数据都是以字节流的形式传输的,也就是数组保存,传输的数据不可读,看着像乱码,我们要将对象转为JSON的格式存储

尽管JSON的序列化方式可以满足可读需求,但是还存在一些问题

它会将JSON格式存储的对象对象的类地址保存,用于反序列化,存入redis中会带来额外的内存开销

StringRedisTemple是Spring提供的一个类,它的key和value序列化方式默认就是String方式,所以我们在使用的时候,键值都得用String类型,要存储对象时,把对象转为JSON字符串存储,或者将对象中的数据都转为String类型

StringRedisTemplate和RedisTemplate的区别

StringRedisTemple存储对象时不需要存储类的地址,但需要我们手动将json格式字符串转化为对象

二.使用redis作为缓存中间件

在项目中我们经常会使用缓存来减轻数据库的压力,在高并发的业务场景下,数据库是扛不住大量请求,这时候我们就需要增加一个或多个中间层来减轻数据库压力,而redis就是将数据存储到缓存中,读写速度远远大于从磁盘中读写

首先我们要明白什么样的数据需要添加到缓存中:需要频繁查询的数据

    @Overridepublic List<ShopType> queryTypeList() {//先查询缓存判断是否存在String key = "cache:shopType";String shopTypeJson = stringRedisTemplate.opsForValue().get(key);if(StrUtil.isNotBlank(shopTypeJson)){List<ShopType> shopTypes = JSONUtil.toList(shopTypeJson,ShopType.class);return shopTypes;}List<ShopType> shopTypes = query().orderByAsc("sort").list();if(shopTypes == null){return null;}stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shopTypes));return shopTypes;}

缓存更新策略

内存淘汰:在缓存内存不足时,redis会主动淘汰部分数据

超时剔除:给缓存添加数据的时候设置过期时间

主动更新:编写业务逻辑,在数据库更新的时候,主动去更新缓存

操作缓存和数据库时有三个问题需要考虑

1.删除缓存还是更新缓存?

更新缓存:每次更新数据库都更新缓存,无效写操作较多,浪费内存资源

删除缓存:更新数据库时让缓存失效,查询时再更新缓存,这样即使无效的写操作,我们也不会主动去同步的更新缓存

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

单体系统:将缓存与数据库操作放在一个事务中,也就是将操作缓存和操作数据库写在一个方法内,给Service层添加Transational注解,让spring帮我们统一管理事务

分布式系统:利用TCC等分布式事务方案

3.先操作缓存还是先操作数据库?

并发产生的双写一致性问题

数据库中数据被修改,我们需要同步的去删除缓存

无论是先操作数据库还是先删除缓存,都会出现有线程读取到脏数据的情况,推荐使用先操作数据库的方式,而且两种方式如果没有上锁的话都是弱一致,都是最终确保数据的一致性

三.缓存击穿,缓存穿透,缓存雪崩及解决方案

缓存击穿

概述:缓存击穿是指一个热点key过期或这个缓存业务重建复杂,恰好再这个时间点有大量请求到来,查询缓存没有,请求全部打到数据库中,给数据库带来巨大压力

解决方案:互斥锁,逻辑过期

互斥锁:互相等待,只有一个线程在重建缓存,其他线程都在等待,性能差

在使用互斥锁方案中,如果是多集群模式,需要使用分布式锁,因为在每一个Tomact服务器中都有一把锁,多个服务器就会有多把锁

逻辑过期:再添加缓存数据时,不设置过期时间,只增加一个过期字段,对数据一致性需求高的业务不可用,因为在重建缓存之前,如果数据库中的数据更改了,没有获得锁的线程直接返回了旧数据

为什么需要开辟一个线程单独重构缓存,在加入双写一致性问题中不是解决了双写一致问题吗?

首先,需要明确的是在逻辑过期方案中写缓存业务的时候,操作数据库时不会删除缓存,因为逻辑过期就是为了这个缓存key一直存在,所以在逻辑过期解决方案中是需要在缓存逻辑过期后去更新缓存的,确保缓存中的是新数据

缓存穿透

概述:缓存穿透是指客户端请求的数据在缓存和数据库中都不存在,这样缓存永远都不不会生效,请求全部打到数据库,这种情况一般是遭到了恶意攻击

解决方案:缓存空对象,布隆过滤

缓存空对象:当数据库中也查询不到这个数据,将这个数据的值存为null存到缓存中

优点实现简单,维护方便

缺点额外的内存消耗,可能造成短期的数据不一致(在构建缓存后,数据库有了数据)

布隆过滤:

概述:布隆过滤是一种算法,底层使用BitMap来实现,也就是一个bit数组,用于快速判断一个元素是否在一个集合中

优点:内存空间占用少,没有多余的key

缺点:实现复杂,存在误差(数组越长,误判率越低)

缓存雪崩

概述:在同一时间点内,大量的缓存同时过期或redis服务宕机,导致请求全部到达数据库,带来巨大压力

大量缓存失效:给缓存失效时间添加随机值

redis服务宕机

利用redis集群提高服务的可用性

给业务添加多级缓存

给缓存业务添加降级限流策略

示例代码:

 private Shop queryWithMutex(Long id){String key = RedisConstants.CACHE_SHOP_KEY +id;String shopJson = stringRedisTemplate.opsForValue().get(key);if(StrUtil.isNotBlank(shopJson)){Shop shop = JSONUtil.toBean(shopJson,Shop.class);return shop;}if(shopJson != null){return null;}// TODO 实现缓存重建,获取互斥锁String lockKey = "lock:shop"+id;Shop shop = null;// TODO 判断是否获取成功try {boolean isLock = tryLock(lockKey);if(!isLock){// TODO 失败,则休眠重试Thread.sleep(50);return queryWithMutex(id);//递归重试}// TODO 成功,查询数据库shop = getById(id);//Mybatis-Plus提供的单表查询//模拟重建延时Thread.sleep(200);if(shop == null){stringRedisTemplate.opsForValue().set(key,"",RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);return null;}stringRedisTemplate.opsForValue().set(key,JSONUtil.toJsonStr(shop),RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);}catch(InterruptedException e){throw new RuntimeException(e);}finally{unlock(lockKey);}//TODO 写入缓存,释放互斥锁return shop;}

http://www.dtcms.com/a/593193.html

相关文章:

  • 做采购 通常在什么网站看邢台市人事考试网
  • 构筑码头数字防线:视频汇聚平台EasyCVR全方位码头海岸线监管方案
  • 计算机理论基础学习Day19
  • 金仓数据库运维优化实践:从成本中心到效能引擎的转型之路
  • 招标网站哪个好用seo指什么
  • Java面试题1:Java 中 Exception 和 Error 有什么区别?
  • MacX DVD Ripper Pro for Mac v6.8.2 安装教程|MacDVD转换软件怎么安装?
  • 【rkyv】 Rust rkyv 库全面指南
  • 【Rust 探索之旅】Rust 性能优化实战指南:从编译器到并发的完整优化方案(附京东/华为云真实案例)
  • 做网站除了域名还要买什么网站搭建dns有用吗
  • 分布式虚拟 Actor 技术在码头生产调度中的应用研究
  • AI Agent设计模式 Day 6:Chain-of-Thought模式:思维链推理详解
  • Anthropic 经济指数(Economic Index)概览
  • 深圳设计网站开发网站运行模式
  • iOS崩溃日志深度分析与工具组合实战,从符号化到自动化诊断的完整体系
  • C++ Qt的QLineEdit控件详解
  • 杭州专业网站设计制作中山企业网站推广公司
  • 软考 系统架构设计师系列知识点之杂项集萃(196)
  • 基于华为昇腾CANN的自定义算子开发
  • Java iText7 PDF模板填充工具:支持多页生成、中文无坑、多占位符精确定位
  • 2025年12月英语四级大纲词汇表PDF电子版(含正序版、乱序版和默写版)
  • 蝶山网站建设樟木头仿做网站
  • 【Linux网络编程】套接字编程
  • 网站怎么做弹出表单网站竞价 英文
  • 电子电气架构 --- 当前技术水平
  • OS 特性之PendSV 异常
  • 跆拳道东莞网站建设触屏版网站开发
  • 在电脑端企业微信打开内置浏览器并调试
  • Seata原理与简单示例
  • LeetCode 420 - 强密码检验器