Redis缓存详解:内存淘汰和缓存的预热、击穿、雪崩、穿透的原理与策略

发布于:2025-08-11 ⋅ 阅读:(30) ⋅ 点赞:(0)

目录

缓存的概念

使用redis作为缓存

缓存更新策略

缓存淘汰策略

关于缓存常见问题及解决方案

缓存预热(Cache preheating)

缓存穿透(Cache penetration)

缓存雪崩(Cache avalanche)

缓存击穿(Cache breakdown)

缓存的概念

缓存和磁盘功能相似,同样是具有存储数据,写入数据,获取数据的特点。缓存相较于磁盘来说,传统缓存不具备持久化保存数据(redis提供持久化的功能),容量也远远小于磁盘的容量,但是却又着访问速度极快的特点。

例子:

行李箱和身上衣服的口袋分别可以看作磁盘和缓存,行李箱相较于口袋能够装下很多东西,但是从行李箱中拿东西确比较慢,而衣服口袋容量虽然很小,但是能很快把里面的东西拿出来。

使用redis作为缓存

通常在网站开发中我们会使用关系型数据库(例如MySQL)来存储数据,这种数据库虽然功能强大但有一个很大的缺陷,就是性能不高,一次查询消耗资源比较多,在面对高并发场景对于数据库的压力是很大的, 很容易就会使数据库服务器宕机。

解决数据库承担高并发的思路通常有两种:

开源

①提高单台数据库服务器的硬件配置,增强处理能力。

②引入更多机器设备,读写分离,分库分表,构建数据库机器,分散压力。

节流

引入缓存,在缓存中保存访问频繁的热点数据,降低直接对数据量访问的请求量(“二八定律”,20%的热点数据能满足80%的访问需求)。

Redis 就是⼀个用来作为数据库缓存的常见方案

客户端访问业务服务器, 发起查询请求。

业务服务器先查询 Redis, 看想要的数据是否在 Redis 中存在。如果已经在 Redis 中存在了,就直接返回,此时不必访问 MySQL 了。如果在 Redis 中不存在,再查询 MySQ。

注意:

缓存是用来加快 "读操作" 的速度的,如果是 "写操作",还是要老老实实写数据库,缓存并不能提高性能。

缓存更新策略

定期生成

每隔一段时间(根据实际需求进行配置),对于访问的数据频次进行统计,挑选出前N%的数据更新到缓存中。适用于一些对实时性要求不高,但访问频繁的数据

实时生成

设置好缓存的容量上限,在接收用户请求的过程中,存在缓存的数据就直接返回给用户,如果不存在则去数据库中查,再将结果写到redis缓存中。

当缓存中的容量已达上限,就需要根据不同的策略对旧数据进行淘汰删除。

缓存淘汰策略

FIFO (First In First Out) 淘汰最先进来的

把缓存中存在时间最久的 (也就是最先来的数据) 淘汰掉。

LRU (Least Recently Used) 淘汰最久未使用的

记录每个 key 的最近访问时间,把最近访问时间最老的 key 淘汰掉。

LFU (Least Frequently Used) 淘汰访问次数最少的

记录每个 key 最近⼀段时间的访问次数,把访问次数最少的淘汰掉。

Random 随机淘汰

从所有的 key 中抽取幸运儿被随机淘汰掉。

Redis 通过配置 maxmemory-policy 来决定淘汰策略:

  • volatile-lru:淘汰设置了过期时间的 key 中最久未使用的

  • allkeys-lru:淘汰最久未使用的 key

  • volatile-lfu:淘汰设置了过期时间的 key 中访问次数最少的

  • allkeys-lfu:淘汰访问次数最少的 key

  • volatile-random:随机淘汰设置了过期时间的 key

  • allkeys-random:随机淘汰 key

  • volatile-ttl:淘汰设置了过期时间,即将过期的 key

  • noeviction:超出内存后,写操作报错(默认策略)

关于缓存常见问题及解决方案

缓存预热(Cache preheating)

缓存预热指的是,在服务上线/重启或热点产生前,主动把数据写入缓存,避免上线瞬间大量穿透 mysql。

成因:

对于定期生成的情况不涉及预热,主要是针对实时生成下需要进行缓存预热。在redis服务器首次接入后,服务器里还没有数据,此时如果接收了客户端发来的大量请求,缓存命中失败就会直接打给mysql。

解决方式

把定期生成和实时生成结合一下,先通过离线的方式,统计热点数据,将热点数据导入redis中。

缓存穿透(Cache penetration)

缓存穿透指的是,在查询某个key时,redis中没有,而mysql中也没有,这个key也不会被更新到redis中,如果这样的请求很多也会给mysql带来很大压力。

成因:

  1. 业务涉及不合理,可能缺少必要的参数检验环节,导致非法的key也被进行查询了。

  2. 操作失误,将数据库部分数据勿删了。

  3. 黑客恶意攻击。

解决方式:

  1. 当发现这个key在redis和mysql上都不存在时,任然写入redis,将value值设为一个非法值(例如“”)。

  2. 引入布隆过滤器,将合法的key预装到布隆过滤器中,请求先询问布隆过滤器,不存在就直接返回,不去访问mysql。

缓存雪崩(Cache avalanche)

缓存雪崩指的是,由于在短时间内,redis上大规模的key失效,导致缓存命中率直线下降,打到mysql的请求激增压力迅速上升,引发mysql宕机。

成因:

  1. redis 上的大量的 key同时过期。

  2. redis 节点重启或挂了

  3. 缓存被清空或缓存容量不足导致大规模淘汰

解决方式:

  1. 设置key的过期时间随机化,避免同一时刻过期。

  2. 加强监控报警,提高redis集群的可用性。

缓存击穿(Cache breakdown)

缓存击穿指的是,某个热点的 key 在过期瞬间产生大量请求去 mysql,短时间内对该单key的mysql访问量激增。与雪崩区别,雪崩是大量 key 同时过期,而击穿是单 key(或少数几个热 key)的问题。

成因:

某个热点key设置了过期时间,过期后仍然有大量访问。

解决方式:

  1. 将热点数据设置为永不过期。

  2. 进行必要的降级服务,访问数据库的的时候使用分布式锁,限制同时请求数据库的并发数。


网站公告

今日签到

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