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

目录

缓存的概念

使用redis作为缓存

缓存更新策略

缓存淘汰策略

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

[缓存预热(Cache preheating)](#缓存预热(Cache preheating))

[缓存穿透(Cache penetration)](#缓存穿透(Cache penetration))

[缓存雪崩(Cache avalanche)](#缓存雪崩(Cache avalanche))

[缓存击穿(Cache breakdown)](#缓存击穿(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. 进行必要的降级服务,访问数据库的的时候使用分布式锁,限制同时请求数据库的并发数。

相关推荐
爱怪笑的小杰杰1 天前
浏览器端缓存地图请求:使用 IndexedDB + ajax-hook 提升地图加载速度
ajax·okhttp·缓存
TDengine (老段)1 天前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349841 天前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE1 天前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy12393102161 天前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎1 天前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP1 天前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql
l1t1 天前
利用DeepSeek辅助修改luadbi-duckdb读取DuckDB decimal数据类型
c语言·数据库·单元测试·lua·duckdb
睡前要喝豆奶粉1 天前
在.NET Core Web Api中使用redis
redis·c#·.netcore
安当加密1 天前
Nacos配置安全治理:把数据库密码从YAML里请出去
数据库·安全