Redis-典型应用-缓存cache

发布于:2025-07-18 ⋅ 阅读:(20) ⋅ 点赞:(0)

1.什么是缓存?

把一些常用的数据放到触手可得的地方,方便随时读取.

缓存是计算机中的一个典型应用场景,很多场景中都会涉及.

硬件的访问速度:  cpu寄存器 > 内存 > 硬盘 > 网络. 

对硬件来说,内存相对于硬盘来说,就是触手可及的地方.内存就是硬盘的缓存;对内存来说,cpu寄存器就是触手可及的地方,cpu寄存器就是内存的缓存.

内存虽然访问速度快,但是他的存储空间小,只能存放一些热点数据.

由于"二八定律" : 20%的热点数据可以处理80%的应用场景 .

因此,只需要将少量的热点数据寸放大缓存里,在整体上就能有明显的提升.

2.使用redis作为缓存

我们经常使用关系型数据库(如 mysql)来存储数据. 关系型数据库虽然功能强大,但存在一个很大的缺陷,就是性能不高.进行一次查询需要消耗非常高的系统资源.

关系型数据库查询效率低的原因:

1.  关系型数据库的数据是存储在磁盘上的,磁盘的IO速度比较慢,特别是随机访问.

2. 当查询不能命中索引时,就需要遍历全表,这就会大大增加磁盘的IO次数.

3. 关系型数据库对于sql执行会做出一系列的解析优化工作.

4. 针对一些复杂查询,进行笛卡尔积,效率会更低.

当访问数据库的并发量很高的情况下, 对数据库的压力会很大,很容易使数据库服务宕机.

提高数据库并发量有两个思路:

1. 开源: 使用更多的机器,部署更多的数据库实例.(主从复制,分库分表)

2. 节流: 引入缓存,使用其他方式保存经常访问的热点数据, 降低直接访问数据库的请求量.

redis就是一个用来作为数据库缓存的常见方案.

redis的数据存放在内存中,读取数据速度快,处理同一个请求消耗的系统资源比mysql少,因此,redis能支持更大的并发量.

每次查询先在redis上查询,查不到时,再想mysql上查询.

3.缓存更新策略

要在redis上存储一些热点数据,又如何知道哪些数据时热点数据呢?

这里有两种缓存更新策略:

1.定期更新:

每隔一定的周期,对访问的数据频次进行统计,挑选出前N%的数据,写一套离线流程,通过定期触发更新redis数据库上的数据.

优点: 实施简单,过程可控,方便排除问题.

缺点: 实时性不够,当突发一些突发事件,有些不是热点词的数据变成热点词了,此时还没来得及更新redis数据库,新的热点词就会给数据库带来较大的压力.

2.实时更新:

查询数据时,先在redis中查找,找到了就直接返回;查不到就去msql中查找,把查询的结果返回并写到redis中.

这种实时更新策略能随时更新redis数据库中的数,但是随着向redis中不断的写入,就会使redis内存占用越来越多.当内存达到上限时,就会出现问题.

为了解决上述问题,redis引入了"内存淘汰策略"来处理:

内存淘汰策略:

1.FIFO(first in first out):

先进先出.把缓存中存放时间最久的数据淘汰.

2.LRU(least recently used):

淘汰最久未使用的: 记录每个key的最近访问时间,淘汰访问时间最老的数据

3.LFU(least frequently used) :

淘汰访问次数最少的, 记录每个key最近一段时间内的访问次数,淘汰访问次数最少的key

4.Random:

随机淘汰, 从所有的key中随机抽取一个数据淘汰.

这些淘汰策略,redis也提供了内置的淘汰策略,可以直接使用:

1>.volatile-lru: 当内存不足的时候,从设置了过期时间的key中,使用LRU(最近最少使用)策略进行淘汰.

2>. allkeys-lru: 内存不足时,从所有key中使用LRU(最近最少使用)策略进行淘汰.

3>.volatile-lfu: 当内存不足的时候,从所有过期的key中,使用LFU(最近最少访问次数)算法进行淘汰.

4> allkeys-lfu: 当内存不足的时候,从所有的key中,使用LFU(最近访问次数最少)算法进行淘汰.

5>. volatile-random: 当内存不足时,从设置了过期时间的key中,随机淘汰.

6>.allkeys-random: 当内存不足时,从所有的key中随机淘汰.

7>.volatile-ttl: 在设置了过期时间的key中,根据过期时间进行淘汰.越早过期的优先被淘汰.(FIFO)

8>. noeviction: 默认策略,当内存不足时,写入新数据会报错.(这个是默认选项,不适用于实时更新缓存).

关于redis缓存存在几个问题:

1.缓存预热Cache preheating:

缓存预热问题是在实时更新的时候出现的.定期更新不涉及缓存预热.

采用实时更新策略时,在刚开始的时候,redis中没有数据,所有的查询都要向mysql访问.导致mysql刚开始的压力较大.

可以采用缓存预热: 通过离线的方式,先统计一波热点数据,导入到redis中,导入的热点数据能帮mysql承担很大的压力.随着时间的推移,逐渐使用新的热点数据淘汰旧的数据.

2.缓存穿透Cache penetration:

查询某个数据key时,在redis中未查到,在mysql中也未查到,就无法更新到redis中,那么这个key在下次查,还是查不到.当存在很多这样的key,并且反复查询,一样会给mysql带来很大的压力.

出现这样的情况的原因:

1. 业务设计部合理,缺少必要的参数校验,导致非法的key也被进行查询了.

2. 误操作导致数据被删除.

3.黑客的恶意攻击.

解决方法:

1. 当发现key在redis和mysql上都不存在时,也将其写到redis上,为器设置一个非法的value.

2. 引入"布隆过滤器" , 每次在查询redis和mysql之前,都先判定一下key是否在布隆过滤器上存在.

把所有的key都存放到布隆过滤器上,布隆过滤器的本质是结合了hash和bitmap,使用较小的空间开销,较快的查询速度,针对key是否存在对出判定.

3. 缓存雪崩Cache avalanche:

在较短的时间内,redis上大规模的key失效,导致redis命中率下降,mysql命中率迅速上升,甚至宕机.

出现的原因:

1. redis挂了.

2.redis上大量的key同时过期.

在往redis上存储key的时候,很多时候,会为其设置过期时间,为大量的key设置了相同的过期时间,当同一时间大量的key同时失效.导致redis的命中率下降.出现缓存雪崩.

解决方案:

1 . 部署高可用的redis集群,完善监控报警系统.

2. 不给key设置过期时间,或设置过期时间时,添加随机时间因子.

4.缓存击穿Cache breakdown:

缓存击穿,是缓存雪崩的一种特殊情况,是针对热点key,突然过期了,导致密集的访问都直接通过mysql查找,导致数据库宕机.

解决方案:

1 . 对热点key,设置永不过时期.

2. 进行必要的服务降级.例如:访问数据库的时候使用分布式锁; 限制同时访问数据库的并发数.


网站公告

今日签到

点亮在社区的每一天
去签到