Redis 缓存
Redis 缓存
1. 说一下缓存的分类?
如果按照缓存是否参与业务写入,可以分为两类:
- 只读缓存;
- 读写缓存。
这里的“只读”是指业务写请求不把缓存作为权威数据源,并不是说缓存内部完全不会发生写入。
只读缓存
只读缓存最常见的实现是 Cache Aside(旁路缓存)。数据库是权威数据源,缓存只用于加速读取。
读取流程
- 先查询缓存;
- 缓存命中,直接返回数据;
- 缓存未命中,查询数据库;
- 将查询结果写入缓存并返回。

写入流程
- 先更新数据库;
- 数据库事务提交成功后,再删除缓存;
- 下一次读取发生缓存未命中,重新从数据库加载最新数据。

通常选择“更新数据库,再删除缓存”,而不是同时更新数据库和缓存,因为删除操作更加简单,可以降低并发更新时写入旧缓存的概率。
优点
- 实现简单,适合读多写少的场景;
- 数据库是权威数据源;
- 缓存丢失后可以从数据库重新构建;
- 不需要保证缓存中的每次修改都被持久化。
缺点
这种模式只能实现最终一致性,不能保证缓存与数据库始终完全一致。例如:
- 数据库更新成功,但缓存删除失败,缓存中会保留旧数据;
- 一个读请求查到旧数据后,另一个请求更新数据库并删除缓存,前一个读请求随后又将旧数据写回缓存;
- 删除缓存与下一次重新加载之间存在短暂的不一致窗口。
常见的改进手段包括:
- 为缓存设置合理的过期时间;
- 删除失败时进行重试;
- 通过消息队列或数据库 Binlog/CDC 异步删除缓存;
- 使用互斥锁或 SingleFlight 防止大量请求同时回源;
- 在对一致性要求较高的场景中使用版本号,避免旧数据覆盖新数据。
读写缓存不仅用于读取,业务写操作也会先进入缓存。根据数据写回数据库的时机,可以继续分为同步写回和异步写回。
读写缓存-同步写回:Write Through
写请求到达缓存后,缓存层同步将数据写入数据库。只有数据库写入成功后,整个写操作才返回成功。

优点
- 数据写入成功时,缓存和数据库通常已经完成同步;
- 数据丢失风险相对较低;
- 一致性通常好于异步写回。
缺点
- 每次写入都需要等待数据库,写入延迟较高;
- 系统吞吐量仍然受到数据库写入能力限制;
- Redis 本身不会自动将缓存数据同步到业务数据库,需要由应用或专门的缓存层实现。
需要注意,不能简单认为“加一个事务”就能保证 Redis 和数据库绝对一致。普通数据库本地事务无法同时覆盖 Redis 和数据库两个独立系统。发生网络异常或进程崩溃时,仍可能出现一边成功、另一边失败的情况。
通常需要结合重试、补偿、幂等、消息队列或分布式事务等机制保证一致性。
读写缓存-异步写回:Write Back / Write Behind
写请求只需要先更新缓存就可以返回成功,缓存中的数据随后再异步批量写入数据库。

优点
- 写请求不需要等待数据库,响应速度快;
- 可以合并多次更新,批量写入数据库;
- 能够降低数据库的写入压力;
- 适合写入频繁、允许短暂延迟的场景。
缺点
- 缓存故障可能导致尚未写回数据库的数据丢失;
- 缓存和数据库之间存在更长的不一致窗口;
- 需要处理消息重复、乱序、写入失败和重试问题;
- 实现和运维复杂度较高。
如果业务对数据可靠性要求较高,通常需要使用持久化日志或消息队列记录待写回的数据,并通过幂等操作、失败重试和监控告警保证最终写入数据库。
对比
| 类型 | 写入路径 | 一致性 | 写入性能 | 数据丢失风险 |
|---|---|---|---|---|
| 只读缓存 / Cache Aside | 更新数据库后删除缓存 | 最终一致性 | 取决于数据库 | 较低 |
| 同步写回 / Write Through | 缓存同步写入数据库 | 相对较强 | 较低 | 较低 |
| 异步写回 / Write Back | 先写缓存,再异步写数据库 | 最终一致性 | 高 | 较高 |
总结
只读缓存一般采用 Cache Aside 模式,数据库是权威数据源,写入时更新数据库并删除缓存;读写缓存则允许写请求进入缓存,根据写回数据库的时机,又可以分为同步写回和异步写回。同步写回一致性相对更好,但写入延迟较高;异步写回性能更高,但需要承担数据丢失和一致性处理的成本。
2. 说一下 Redis 的缓存淘汰机制?
缓存淘汰是指 Redis 达到配置的内存上限后,按照指定策略删除一部分 Key,为新数据释放空间。
Redis 通过以下配置控制内存上限和淘汰策略:
maxmemory 2gb
maxmemory-policy allkeys-lru
如果没有设置有效的 maxmemory 限制,淘汰策略通常不会被触发。
Redis 的淘汰策略
Redis 的淘汰策略可以从两个维度理解:
allkeys-*:从全部 Key 中选择淘汰对象;volatile-*:只从设置了过期时间的 Key 中选择淘汰对象。
经典版本的 Redis 主要支持以下 8 种策略:
| 淘汰策略 | 说明 |
|---|---|
noeviction | 不淘汰数据,内存不足时拒绝会增加内存的写命令,读命令通常仍可执行 |
allkeys-lru | 从全部 Key 中淘汰最近最少使用的 Key |
volatile-lru | 从设置了 TTL 的 Key 中淘汰最近最少使用的 Key |
allkeys-lfu | 从全部 Key 中淘汰访问频率最低的 Key |
volatile-lfu | 从设置了 TTL 的 Key 中淘汰访问频率最低的 Key |
allkeys-random | 从全部 Key 中随机淘汰 |
volatile-random | 从设置了 TTL 的 Key 中随机淘汰 |
volatile-ttl | 从设置了 TTL 的 Key 中优先淘汰剩余生存时间最短的 Key |
如果使用 volatile-* 策略,但当前没有任何设置了过期时间的 Key,那么它的表现类似于 noeviction:无法找到可淘汰对象,相关写命令会失败。

Redis 8.6 新增 LRM 策略
Redis 8.6 增加了两种 LRM(Least Recently Modified,最近最少修改)策略:
| 淘汰策略 | 说明 |
|---|---|
allkeys-lrm | 从全部 Key 中淘汰最久没有被修改的 Key |
volatile-lrm | 从设置了 TTL 的 Key 中淘汰最久没有被修改的 Key |
LRU 会在读取或写入 Key 时更新访问时间,而 LRM 只关注最后修改时间。
因此,即使一个 Key 经常被读取,只要很久没有被修改,LRM 仍可能将其淘汰。它适合需要优先保留近期更新数据的场景。
如果面试讨论的是 Redis 8.6 以前的版本,通常回答经典的 8 种策略即可。
LRU 的实现
LRU(Least Recently Used)表示淘汰最长时间没有被访问的数据。
Redis 没有维护一个严格的全局 LRU 链表,因为精确 LRU 会增加内存占用,并且每次访问都需要调整链表。
Redis 使用的是近似 LRU:
- 随机采样一部分 Key;
- 比较这些 Key 的空闲时间;
- 将较久未访问的 Key放入候选池;
- 从候选对象中选择合适的 Key 淘汰。
采样数量可以通过 maxmemory-samples 调整。采样数量越大,结果越接近精确 LRU,但需要消耗更多 CPU。
LFU 的实现
LFU(Least Frequently Used)表示淘汰访问频率最低的数据。
Redis 使用概率计数器估算访问频率,而不是精确记录每个 Key 的访问次数。同时,访问频率会随时间衰减,避免一个曾经很热门、现在已经很少访问的 Key 永久占据缓存。
因此,Redis 的 LFU 也是近似算法。
如何选择淘汰策略?
- 数据具有明显的冷热特征:使用
allkeys-lru; - 希望长期保留访问频率较高的数据:使用
allkeys-lfu; - 希望保留最近修改的数据:Redis 8.6 之后可以使用
allkeys-lrm; - 所有 Key 的访问概率接近:可以使用
allkeys-random; - 业务能够通过 TTL 表达数据价值:可以使用
volatile-ttl; - 同一个实例同时存放缓存数据和不可淘汰数据:可以考虑
volatile-*; - Redis 用作重要数据存储,不允许自动删除 Key:使用
noeviction。
如果没有特殊需求,并且 Redis 中的数据都可以被重新加载,allkeys-lru 通常是比较合适的通用选择。
不过,如果同一个实例同时保存可淘汰缓存和不可淘汰数据,最好优先考虑拆分成不同的 Redis 实例,而不是完全依赖 volatile-* 策略隔离。
FIFO 是否属于 Redis 的淘汰策略?
FIFO 是通用缓存算法,表示最早进入缓存的数据最先被淘汰。但 Redis 的经典 maxmemory-policy 中没有独立的 FIFO 策略,因此面试回答 Redis 淘汰机制时,不应把 FIFO 列为 Redis 原生配置。
淘汰和过期的区别
淘汰和过期不是同一个概念:
- 过期:Key 到达 TTL 后失效,与内存是否充足无关;
- 淘汰:Redis 达到
maxmemory限制后,根据淘汰策略主动删除 Key。

过期 Key 主要通过惰性删除和主动过期扫描进行清理,而内存淘汰由 maxmemory-policy 控制。
Redis 达到
maxmemory上限后,会根据maxmemory-policy选择 Key 淘汰。经典策略包括noeviction,以及基于 LRU、LFU、Random 和 TTL 的allkeys或volatile策略。Redis 的 LRU 和 LFU 都是近似算法;Redis 8.6 又新增了基于最近修改时间的 LRM 策略。
推荐阅读
3. 如何解决缓存和数据库内容不一致的问题?
缓存和数据库是两个独立系统,普通数据库事务无法同时保证数据库与 Redis 的原子性。因此,工程上通常以数据库作为权威数据源,通过合理的更新顺序、可靠重试和过期时间实现最终一致性。
使用 Cache Aside 模式
这是最常见的方案。
读取流程
- 先查询缓存;
- 缓存命中,直接返回;
- 缓存未命中,查询数据库;
- 将数据库结果写入缓存。
写入流程
- 先更新数据库;
- 数据库事务提交成功后,再删除缓存;
- 后续读请求缓存未命中时,从数据库加载最新数据。
更新数据库 -> 事务提交成功 -> 删除缓存
通常选择删除缓存,而不是更新缓存,原因包括:
- 更新缓存需要同时维护两份数据,逻辑更加复杂;
- 多个并发写请求可能以不同顺序完成,导致旧数据最后写入缓存;
- 有些缓存数据由多个数据库字段计算得出,直接更新成本较高;
- 删除缓存是幂等操作,失败后容易重试。
为什么推荐“先更新数据库,再删除缓存”?
如果先删除缓存,再更新数据库,可能出现以下情况:
- 写请求删除缓存;
- 读请求发现缓存不存在;
- 读请求从数据库读取到旧数据;
- 读请求将旧数据写入缓存;
- 写请求更新数据库。
最终数据库中是新数据,缓存中却是旧数据,并且可能一直持续到缓存过期。
先更新数据库再删除缓存,可以缩小这种不一致窗口。但它仍然不能保证绝对一致,因为数据库更新成功后,删除缓存的操作仍有可能失败。
保证缓存删除最终成功
数据库更新成功、缓存删除失败,是 Cache Aside 中最常见的不一致原因。可以通过以下方式解决:
失败重试
缓存删除失败后进行有限次数重试,并记录日志和监控告警。
删除缓存通常是幂等操作,同一个 Key 重复删除不会产生副作用。
消息队列
数据库提交成功后发送缓存失效消息,由消费者负责删除缓存。消费者删除失败时可以重试,并通过死信队列处理长期失败的任务。
需要注意,如果业务数据已经提交,但消息发送失败,仍然可能丢失失效通知。因此可以进一步使用事务消息或本地消息表。
Transactional Outbox
在同一个数据库事务中:
- 更新业务数据;
- 向 Outbox 表写入一条缓存失效事件;
- 提交事务;
- 后台任务读取 Outbox 事件并删除缓存;
- 删除成功后将事件标记为已完成。
由于业务数据和 Outbox 事件在同一个本地事务中提交,可以避免“数据库更新成功,但失效消息丢失”的问题。
监听 Binlog 或 CDC
通过 Canal、Debezium 等工具监听数据库提交后的变更日志,再异步删除或更新缓存。
这种方式可以将缓存失效逻辑与业务代码解耦,但仍要保证消息消费幂等、失败重试和监控告警。
设置合理的过期时间
即使缓存删除失败,TTL 也能让旧数据在一定时间后自动失效,因此每个缓存 Key 通常都应该设置合理的过期时间。
不过,TTL 只能作为兜底手段,不能保证实时一致性。在缓存过期前,用户仍然可能读到旧数据。
一致性要求越高,TTL 通常应越短,但过短又会增加数据库压力,需要在一致性和缓存命中率之间权衡。
防止旧数据回填缓存
即使采用“更新数据库,再删除缓存”,仍可能出现以下并发情况:
- 读请求缓存未命中,并读取到数据库旧值;
- 写请求更新数据库;
- 写请求删除缓存;
- 之前的读请求把旧值写入缓存。
可以采用以下方式降低风险:
- 为缓存数据携带版本号或更新时间,只允许新版本覆盖旧版本;
- 对热点 Key 的缓存重建使用互斥锁或 SingleFlight;
- 写入缓存前再次校验数据库版本;
- 通过 CDC 在数据库变更后再次删除缓存;
- 使用短 TTL 限制旧数据的存活时间。
“延迟双删”也可以作为一种简单补偿方案,即更新数据库并删除缓存后,延迟一段时间再次删除缓存。但延迟时间难以准确设置,也不能覆盖所有异常,因此不能把它当作严格一致性方案。
缓存锁不能单独解决一致性问题
分布式锁可以让同一时刻只有一个线程重建或修改某个缓存,减少并发覆盖和缓存击穿,但它不能自动保证数据库与缓存的一致性。
因为仍然可能出现:
- 数据库更新成功后进程崩溃;
- 缓存删除失败;
- 锁过期后旧请求继续执行;
- 网络超时导致无法判断操作是否成功。
因此,锁通常需要与版本号、重试、TTL 或消息机制配合使用。
数据库事务不能覆盖普通 Redis 操作
数据库本地事务只能保证数据库内部操作的原子性,不能把 Redis 操作自动纳入同一个事务。
下面这种流程仍然可能不一致:
开启数据库事务
更新数据库
更新或删除 Redis
提交数据库事务
例如,Redis 操作成功后数据库事务回滚,或者数据库提交成功后进程在删除 Redis 前崩溃,都会导致数据不一致。
如果业务必须保证强一致性,可以考虑:
- 关键读取直接查询数据库,不经过缓存;
- 在一致性敏感时间窗口内临时绕过缓存;
- 使用能够统一协调数据库和缓存的分布式事务,但实现成本较高;
- 调整系统设计,避免让缓存承担强一致性的权威存储职责。
解决缓存与数据库不一致的常用方案是以数据库为权威数据源,读取时采用 Cache Aside,写入时先提交数据库事务,再删除缓存。同时通过重试、消息队列、Transactional Outbox 或 CDC 保证缓存最终失效,并使用 TTL 作为兜底。普通数据库事务和缓存锁都不能单独保证 Redis 与数据库的强一致性。
4. 什么是缓存穿透、缓存雪崩和缓存击穿?

缓存雪崩
是指缓存中大量键到期,而查询量过大,发现缓存中没有该键,则会去请求后台,引起数据库压力过大甚至宕机。
解决方案
过期时间设置为随机,这样就不会出现短时间内大量过期的情况。
使用分布式数据库,分别请求不同的数据库,则会减少某一数据库的压力。
设置热点数据永远不过期
核心数据可以访问数据库,非核心直接返回,进行一个降级
采用 本地缓存(Caffeine) + Redis + 数据库 的多级缓存架构,即使 Redis 崩溃,本地缓存仍能扛住部分流量。
当 Redis 不可用时,启用 降级策略(如返回默认数据、限流),避免数据库被打爆。
缓存击穿
缓存击穿是指,针对某个访问非常频繁的热点数据的请求,无法在缓存中进行处理,紧接着,访问该数据的大量请求,一下子都发送到了后端数据库,导致了数据库压力激增,会影响数据库处理其他请求。
设置热点数据永远不过期,但后台定期更新缓存
缓存不设置物理过期时间,而是存储 逻辑过期时间,由业务代码判断是否重新加载。
加锁,当缓存失效时,只允许一个线程去查询数据库,其他线程等待并复用结果。
缓存穿透
缓存雪崩和缓存击穿都是因为键过期的情况,虽然缓存中没有该数据了,但是数据库中还有,虽然会对数据库造成压力,但是还是有机会解决。
情况如下,我们访问缓存时,发现缓存中没有该数据,则去查找数据库,发现数据库中也没有该数据,这样就会给缓存和数据库造成很大的压力。
发生这种事情有两种情况
误删除:被管理员一不小心将缓存中和数据库的数据都删了
恶意攻击:另一种情况就是被别人恶意攻击,故意拿数据库和缓存中没有的数据进行发出请求。
设定空值和缺省值,如果数据库查询不到数据,仍然在 Redis 中缓存一个空值(如
key:null),并设置较短的过期时间(如 5 分钟)。使用布隆过滤器判断是否含有该键,多用于缓存更新较少的情况,因为需要同步更新布隆过滤器
入口处检测(前端界面过滤,过滤掉部分)
注:布隆过滤器的原理:使用N个哈希函数,得出N个哈希值,并将哈希表的N个位置标记成 1,如果已经为 1 则无需标记,判断值是否存在时,计算N个哈希值,对应的位是否存在 0 ,存在 0 则表明该值不存在。
5. 说一下什么是缓存污染?
缓存污染的概念
缓存污染是指缓存中存在大量不经常被访问的数据,这些数据占据了缓存空间,导致真正有价值(经常被访问)的数据被挤出缓存,从而降低了缓存的命中率。
既然我们知道了什么是缓存污染,我们来看一下出现缓存污染的原因

产生缓存污染的原因
访问模式发生改变
应用程序的数据访问模式可能会随着时间、业务逻辑或用户行为的改变而变化。
例如,在一个电商平台的促销活动期间,某些商品的访问量会急剧增加,而活动结束后,如果缓存没有及时更新或清理,之前促销商品的相关数据可能仍然占据缓存空间,此时用户更关注的日常商品数据却无法有效缓存。
恶意攻击或异常流量
攻击者可能会故意发送大量不同的请求,导致缓存中存储了许多一次性或很少被再次访问的数据。
比如,通过不断地查询一些随机生成的商品ID对应的信息,使这些无用的数据填满缓存。
另外,一些异常流量,如爬虫程序的过度爬取或者系统故障导致的大量重复但无价值的请求,也可能引起缓存污染。
缓存策略的不完善
如果缓存的过期时间设置过长,一些不再有价值的数据可能会长时间占据缓存空间。例如,对于新闻类应用,一篇时效性很强的新闻,若其缓存过期时间设置为一周,那么在新闻热度过去后,它仍然会在缓存中存在很长时间,浪费缓存资源。缺乏基于访问频率的缓存淘汰机制也容易导致缓存污染。缓存影响还会带来性能下降和资源浪费的问题。
解决缓存污染的策略
优化缓存过期策略
根据数据的特点和访问频率设置合理的过期时间。对于时效性强的数据,如新闻资讯、实时股价等,应该设置较短的过期时间,确保缓存中的数据始终是最新且有价值的。可以采用动态过期时间的策略,例如根据数据的最后访问时间来调整过期时间,对于长时间未访问的数据,缩短其过期时间。
采用合适的缓存淘汰算法
常用的缓存淘汰算法有LRU(最近最少使用)、LFU(最不经常使用)等。
LRU算法会淘汰最近最少使用的数据,它基于这样的假设:如果一个数据在最近一段时间内没有被访问,那么它在未来被访问的可能性也比较小。
LFU算法则是根据数据的访问频率来进行淘汰,将访问频率最低的数据从缓存中移除。Redis提供了多种缓存淘汰策略,通过合理配置这些策略,可以有效地减少缓存污染。
数据预热和预缓存
在系统启动或业务高峰期来临之前,可以对一些预期会被频繁访问的数据进行预热和预缓存。例如,对于一个电商平台,在大型促销活动前,可以提前将热门商品的信息缓存起来。同时,对于一些固定的基础数据,如系统配置信息、常用字典数据等,也可以进行长期预缓存,确保这些关键数据始终在缓存中,避免被污染。
流量控制和请求过滤
针对恶意攻击或异常流量导致的缓存污染,可以在应用层或网络层设置流量控制和请求过滤机制。例如,通过设置IP访问频率限制、识别和拦截恶意请求的特征等方式,减少无价值请求进入缓存系统,从而降低缓存污染的风险。
6. 说一下 Redis 的过期删除策略?
什么是过期删除?
Redis 可以通过 EXPIRE、PEXPIRE 或 SET EX/PX 等命令为 Key 设置生存时间 TTL。
当 TTL 到期后,这个 Key 在逻辑上就已经失效。过期删除就是 Redis 识别并删除这些过期 Key、回收其内存的机制。
过期删除解决什么问题?
Redis 不能只判断 Key 是否过期,却一直不释放它占用的内存,否则大量过期 Key 会滞留在内存中,造成内存浪费。
但 Redis 也不能持续遍历所有 Key 检查过期时间,否则会消耗大量 CPU,阻塞正常请求。
因此,过期删除需要在两方面之间进行权衡:
- 尽快删除过期 Key,回收内存;
- 避免检查过期 Key 占用过多 CPU。
从通用理论上看,过期删除主要有定时删除、惰性删除和定期删除三种策略。Redis 实际采用的是惰性删除和定期主动删除相结合的方式。
定时删除
定时删除是指为每个设置了 TTL 的 Key 创建一个定时任务,到达过期时间后立即删除。
优点
- 能够及时删除过期 Key;
- 过期 Key 占用内存的时间很短;
- 内存利用率较高。
缺点
- 每个 Key 都需要维护定时任务,管理成本较高;
- 大量 Key 同时过期时,会集中执行大量删除操作;
- 删除操作可能占用大量 CPU,影响正常请求;
- 如果使用时间堆等结构管理任务,还需要承担额外的数据结构维护成本。
Redis 并没有为每个 Key 单独创建定时器,因此严格意义上的定时删除不是 Redis 的主要实现策略。
惰性删除
惰性删除也叫被动过期。客户端访问某个 Key 时,Redis 会检查它是否已经过期:
- 如果没有过期,则正常返回数据;
- 如果已经过期,则删除该 Key,并将其视为不存在,通常返回空结果。
客户端访问 Key
↓
检查是否过期
├─ 未过期 → 返回数据
└─ 已过期 → 删除 Key → 返回空结果

注意,这里返回的 nil ,只是 redis 层面的,不是系统层面的,真正的业务系统通常在接收到 redis 返回的 nil 之后,会继续执行查数据库 + 回填缓存的逻辑
优点
- 只在访问 Key 时进行检查,对 CPU 比较友好;
- 不需要持续扫描所有设置了 TTL 的 Key;
- 实现相对简单。
缺点
- 如果一个 Key 过期后再也没有被访问,它就不会因为惰性策略而被删除;
- 大量无人访问的过期 Key 可能长期占用内存。
因此,只使用惰性删除无法有效回收所有过期数据。
定期删除
定期删除是指 Redis 周期性运行主动过期任务,从设置了过期时间的 Key 中进行抽样检查,并删除已经过期的 Key。
需要注意,Redis 并不是定期遍历所有 Key,而是从保存过期时间的数据中抽取一部分进行检查。
其基本流程可以概括为:
- 从设置了过期时间的 Key 中抽样;
- 检查样本是否已经过期;
- 删除样本中的过期 Key;
- 如果过期 Key 比例仍然较高,则继续检查;
- 达到时间或工作量限制后暂停,将执行机会交还给正常请求。
Redis 的主动过期过程是自适应的:
- 过期 Key 较少时,减少检查,节省 CPU;
- 过期 Key 较多时,增加检查力度,尽快回收内存;
- Redis 还会限制单轮处理时间,避免过期删除长时间占用主线程;
- 可以通过
active-expire-effort调整主动过期清理力度。
优点
- 能够清理不再被访问的过期 Key;
- 不需要为每个 Key 单独维护定时器;
- 通过抽样和时间限制,在 CPU 开销与内存回收之间取得平衡。
缺点
- 抽样检查不能保证 Key 到期后立即从内存中删除;
- 在过期 Key 较多时,主动删除仍会消耗一定 CPU;
- 如果清理速度低于 Key 过期速度,部分过期 Key 可能暂时滞留在内存中。
Redis 的实际方案
Redis 使用:
惰性删除 + 定期主动删除
两种策略互相补充:
- 惰性删除保证客户端不会读取到已经过期的数据;
- 定期删除负责清理那些过期后不再被访问的 Key;
- 主动删除采用抽样和时间限制,避免检查过程长时间阻塞主线程。
这种设计不能保证 Key 在 TTL 到期的瞬间就立即从内存中消失,但可以在保证请求性能的同时,逐步回收过期数据占用的内存。
过期删除与内存淘汰的区别
过期删除和内存淘汰是两个不同的概念:
| 对比项 | 过期删除 | 内存淘汰 |
|---|---|---|
| 触发条件 | Key 的 TTL 已到期 | Redis 达到 maxmemory 限制 |
| 删除对象 | 已经过期的 Key | 根据淘汰策略选出的 Key |
| 是否要求设置 TTL | 是 | 不一定 |
| 主要目的 | 清理失效数据 | 在内存不足时释放空间 |
| 典型策略 | 惰性删除、定期删除 | LRU、LFU、Random、TTL |
因此,LRU、LFU 和随机淘汰属于内存淘汰策略,不能归类为过期删除策略。
即使一个 Key 没有过期,在 Redis 达到内存上限时,也可能被淘汰;反过来,即使 Redis 内存充足,TTL 到期的 Key 也应被过期机制删除。
另外需要注意的是
Redis 保存的是 Key 的绝对过期时间,而不是单纯记录剩余时长。因此,即使 Redis 停机一段时间,重新启动后也会根据当前时间判断 Key 是否已经过期。
在主从复制场景中,通常由主节点负责决定 Key 过期,并将相应的删除操作传播给从节点,从而保持数据集一致。
过期删除是 Redis 清理 TTL 已到期 Key、回收内存的机制,主要解决过期数据长期占用内存的问题。理论上有定时删除、惰性删除和定期删除三种策略;Redis 没有为每个 Key 单独设置定时器,而是采用惰性删除与定期主动删除相结合的方案:访问 Key 时检查是否过期,同时周期性抽样清理过期 Key,在 CPU 消耗和内存回收之间取得平衡。LRU、LFU 和随机删除属于内存淘汰策略,不属于过期删除策略。
推荐阅读
阅读导航
上一章:Redis 数据结构
下一章:Redis 集群




