Redis缓存

我们之前在说redis的用途时,也提到了redis做缓存,那这里我们再来重新回顾一下

(一)Redis缓存的意义

  我们说Redis最主要的三大用途:1.做数据库    2.做缓存    3.做消息队列

我们之所以用redis做缓存,看中的就是他的访问速度时很快的

我们看这个图,我们mysql是在硬盘上存储数据,而redis是在内存上存储数据的,这时我们redis就可以作为mysql的缓存

   那对于计算机硬件来说,往往访问速度快的,那么他的存储空间就越小,同时成本也高,所以我们通常速度快的要给速度慢的做缓存,那我们会说,虽然引入缓存我们访问速度快了,但是存储空间小啊,我们不能放入所有数据,如果放入所有数据,那还不如直接用他来存储呢,当什么缓存呀?

   确实如此,但是我们发现,大部分数据都满足二八原则,也就是说20%的数据能够满足大概80%左右的请求量,这样不就能够很好的扬长避短了吗,我们使用空间小但是速度快的内存存储20%来解决大概80%的请求量,剩下的请求量我们就可以让用户访问硬盘上的数据

(二)使用Redis作为缓存

在一个网站中,我们经常使用mysql来存储数据,那虽然mysql功能强大,但是他的性能不高

  那因为mysql的效率比较低,就会导致一旦请求量增多,并发量还很有限,就导致我们数据库很大概率就会挂了(因为服务器每次处理一个请求都要消耗一定的硬件资源,当这些资源中的任意一个被消耗完了,机器就容易出故障了)

  那这个解决办法我们之前也说到过

1.开源:引入多个机器,构成数据库集群

2.节流:引入缓存,将热点数据保存到缓存上,后续查询时优先去缓存中找数据

  那为什么引入缓存叫做节流? 首先就是redis访问速度快,并且消耗资源比较少(redis只是key-value方式存储的,不涉及复杂查询那么多限制),所以redis能够支持更多并发量

  引入缓存就类似于使用一层筛网把数据包住一样,客户端访问服务器发起查询请求,业务服务器先查redis,如果又就直接返回不查询mysql,如果没有就查询mysql

  注意引入缓存只是来加快读操作速度的,如果时写操作还是要写数据库,不能写缓存(这里与主从复制的主从节点有一点点类似)

(三)缓存的更新策略(面试常见)

我们说redis做缓存来存储一些热点数据(二八原则),那怎么判断他是不是热点数据?

 1)定期生成

 每隔一定时间,我们就对各个数据的访问量进行统计,然后我们会选出访问量最高的钱n%个数据放到缓存中

 优点:实现起来比较简单,过程是可控的,一定时间内缓存有什么是固定的

 缺点:实时性不够,如果有一些突发时间,比如突然有一些次成为了热词,就会给数据库带来比较大的压力

 2)实时生成

给缓存设定容量上限(可在redis的配置文件更改)

接下来用户进行查询:

   如果redis中查询到了,就直接返回,如果redis中不存在,就在数据库查,然后把查到的结果写入redis,当缓存满了,就要把一些不是那么热点的数据淘汰掉,然后过一段时间,redis中的数据就是一些比较稳定的热点词了

  1.淘汰策略

1)FIFO(先进先出):类似于队列,我们那个热点数据最先进入redis中,当redis满了,就会把他淘汰掉

2)LRU(淘汰最久未使用的):记录每个key的最近访问时间,当redis满了,就会把最久没有访问的key淘汰掉

3)LFU(淘汰次数最少的):记录每个key的访问次数,当redis满了,就会把访问次数最少的key淘汰掉

4)Random(随机淘汰):从所有key中随机淘汰一个

 个人觉得,第三种按照次数淘汰的,还是比较合理的

那上述我们可以自己实现,也可以使用redis内置的淘汰策略

  那讲到redis内置淘汰策略,我们要记得我们设置key-value的时候是可以设置过期时间的,到时候这个key就会自动销毁

这就是redis内部给我们提供的淘汰策略,我们大概看一眼也可以很好的理解,大部分都是把我们上述讲到的四个淘汰策略,给分成了有过期时间和无过期时间的

(四)redis缓存中的一些问题(面试常见)

1.缓存预热

  我们在使用redis做mysql缓存的时候,我们说生成热点数据有定期生成和实时生成,但是这两种生成方法,我们在刚启动redis时,redis是没有热点数据的,所以需要先访问mysql然后生成热点数据,那么这就会导致mysql压力过大,所以我们需要提前把热点数据给准备一批,直接写到redis中,让redis在刚开始就开始给mysql缓解压力

  那这个提前准备的热点数据我们按照之前统计的数据作为热点数据先放到redis中,因为这一部分热点数据不需要特别准确,只要能帮mysql尽量抵挡请求即可,随着程序运行,我们真正的热点数据会保存到redis中的(类似于定期生成和实时生成的结合)

2.缓存穿透(Cache penetration)

 当客户端访问的key在redis和mysql中都不存在时,这样的key是不会被放到缓存上的,后续如果仍然在访问key,就会导致mysql一直被访问(这种情况就称为缓存穿透)

那产生缓存穿透的原因:

  1)业务涉及的不合理,比如缺少必要的参数校验环节,导致非法的key也被查询了

  2)工作人员的失误,把一些数据从mysql中删除了

  3)黑客的恶意攻击

解决方法:

 针对一些查询的参数进行校验,避免非法或者不合理的key被查询

 针对数据库中不存在的key我们也先存到redis中,但是value可以设置为空,避免多次重复访问把mysql搞挂了

 使用布隆过滤器判断key是否存在(把所有key放到布隆过滤器上),然后再考虑是否查询

3.缓存雪崩

短时间内,大量的key在缓存上失效,导致数据库压力增大,然后mysql挂了

产生原因 :

 那产生缓存雪崩的原因我们要从redis上分析,因为是redis上的缓存失效,才导致mysql挂了

1.redis挂了:当redis挂了,那么我们所有的请求都要去访问mysql

2.redis上的key同时过期:这种可能是同一时间设置了大量的key,而且这些key有着相同的过期时间

解决方法:部署redis集群(这样一个redis挂了,其他redis顶上),并且完善我们的监控报警体系

不给key设置过期时间,或者每个key的过期时间设置为不同的

4.缓存击穿

相当于缓存雪崩的特殊情况,热点key突然过期了,我们缓存雪崩是大量key失效(包含大量key过期了),导致大量请求直接访问数据库

解决方法:

设置key为永不过期,进行必要的服务降级,例如访问数据库的时候使用分布式锁,显示同时请求数据库的并发数

### 关于 Redis 缓存的使用教程和最佳实践 #### Spring Boot 整合 Redis 缓存的最佳实践 在现代应用开发中,缓存是提升系统性能和响应速度的关键技术之一。Redis 作为一种高性能的内存数据库和缓存服务器,在分布式系统特别是微服务架构中有广泛应用,可以显著减少数据库访问压力并提高系统的并发能力和稳定性[^1]。 为了有效利用 Redis 作为应用程序中的缓存解决方案,建议遵循以下几点: - **合理设置过期时间**:通过 `@Cacheable` 注解或其他方式设定合理的 TTL (Time To Live),防止数据长期占用内存资源。 - **选择合适的序列化机制**:默认情况下,Spring Data Redis 使用 JDK 序列化器来处理对象存储。然而,JDK 序列化的效率较低且生成的数据较大。推荐采用 JSON 或者 Protobuf 等更高效的序列化工具。 - **异常情况下的回退策略**:考虑到网络波动或者 Redis 集群不可用的情况,应该有相应的容错措施。例如,在尝试获取缓存失败时直接调用目标方法,并将结果重新放入缓存中[^3]。 ```java // Java代码示例:定义带有 @Cacheable 的业务逻辑类 import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service public class MyService { @Cacheable(value = "items", key = "#id") public Item getItemById(Long id) { // 如果缓存命中,则返回缓存的结果; // 否则查询数据库并将结果加入缓存后再返回给客户端 return repository.findById(id).orElseThrow(() -> new EntityNotFoundException()); } } ``` #### 将 Redis 缓存集成到 Apache Shiro 中 Apache Shiro 是一个强大的安全框架,支持认证、授权等功能。要将其与 Redis 结合起来用于会话管理和权限控制等方面,可以通过自定义 CacheManager 来完成这一过程[^2]。 具体做法是在项目初始化阶段创建一个新的 `RedisCacheManager` 实例并与之关联,从而使得所有的缓存操作都基于 Redis 完成。这不仅提高了安全性管理模块本身的运行效率,也便于跨多个节点共享同一套用户状态信息。 ```java // Java代码片段:配置Shiro以使用Redis作为其内部缓存组件 import org.apache.shiro.cache.CacheManager; import org.crazycake.shiro.RedisCacheManager; @Bean public CacheManager shiroCacheManager() { CacheManager cacheManager = new RedisCacheManager(redisManager); return cacheManager; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值