# 43. Redis 是如何通过 LRU(Least Recently Used)算法来回收内存的?

# 标准答案

Redis 通过 LRU(Least Recently Used)算法回收内存,确保较少使用的数据被淘汰。Redis 的 LRU 算法并非精确实现,而是通过近似算法来实现。Redis 在内存使用达到限制时,通过定期检查和淘汰较少被访问的数据来释放空间。LRU 算法通过标记数据的访问时间,确保最久未被访问的键被优先淘汰。Redis 提供了几种内存回收策略,包括 volatile-lruallkeys-lru,前者仅回收设置了过期时间的键,后者回收所有键。

# 答案解析

# 1️⃣ LRU 算法概述

LRU(Least Recently Used)算法的基本思想是将最久未使用的缓存数据淘汰,以确保系统内存中存储的是最近最常访问的数据。当 Redis 内存使用超过配置的限制时,LRU 算法会通过一定的机制自动回收部分数据,以避免发生内存溢出。Redis 并不会进行精确的 LRU 淘汰,而是采用了 近似 LRU 算法,通过定期检查和淘汰最久未使用的数据。

# 2️⃣ Redis 的内存回收策略

在 Redis 中,内存回收策略可以通过配置项 maxmemory-policy 来选择。Redis 提供了几种常见的回收策略,其中与 LRU 相关的策略包括:

  • volatile-lru:仅淘汰带有过期时间的键(即设置了 EXPIRE 的键),采用近似 LRU 算法回收这些键。
  • allkeys-lru:对所有的键(无论是否设置过期时间)都使用 LRU 淘汰策略,即采用近似 LRU 算法回收所有键。
  • volatile-ttl:优先回收设置了过期时间的键,并且回收时会优先选择即将过期的键。
  • noeviction:不进行淘汰操作,直到内存足够。

在选择 allkeys-lruvolatile-lru 策略时,Redis 会对一部分键进行 LRU 淘汰,来释放空间。

# 3️⃣ Redis 的近似 LRU 实现

Redis 并不是精确实现 LRU,而是通过一种 近似 LRU 算法来高效回收内存,具体方法如下:

  1. 哈希表的链表化:Redis 中的键值对存储结构为哈希表,在每次访问某个键时,Redis 会将这个键标记为“最近使用”的数据,并将其从链表中移到链表的头部。

  2. 定期扫描:由于精确实现 LRU 的成本较高,Redis 采用了一种近似的方式,即每次进行内存回收时,并不是检查所有键,而是通过定期扫描一部分键来找到最久未使用的键。例如,Redis 会每隔一定的时间(通过 maxmemory-samples 配置项指定样本数量)随机检查几个键,判断它们的使用时间,并根据使用时间的顺序淘汰最久未使用的数据。

  3. LRU 近似性:这种近似实现通过少量的样本数据,代替了全量的检查,因此减少了内存回收的性能开销。近似 LRU 保证了内存淘汰策略的合理性,且性能开销较低。

# 4️⃣ LRU 的性能影响

尽管 Redis 采用了近似 LRU 算法,但由于其是通过随机检查样本来模拟 LRU 机制,因此相比于精确的 LRU 算法,它具有更低的开销和较高的效率。Redis 中的 LRU 操作和内存回收操作是 异步 的,不会阻塞主线程的执行,保证了高并发操作时的性能。

# 5️⃣ LRU 的配置

可以通过以下配置选项来调整 Redis 的 LRU 机制和内存回收策略:

  • maxmemory:设置最大内存限制,超出该限制时,Redis 会根据配置的回收策略进行淘汰。
  • maxmemory-policy:配置内存回收策略,可以选择 volatile-lruallkeys-lruvolatile-ttlnoeviction 等。
  • maxmemory-samples:配置在 LRU 淘汰时,Redis 选择的随机样本数量。增大该值会提高 LRU 的精确度,但也会增加 CPU 开销。

# 6️⃣ 实际应用

LRU 算法在 Redis 中应用于多种实际场景:

  1. 缓存系统:当 Redis 作为缓存系统时,LRU 可以确保最常访问的数据优先留在内存中,最久未访问的数据被回收。
  2. 限流与缓存穿透防护:通过内存回收策略,可以避免缓存满时影响业务逻辑,保持一定的数据在内存中。
  3. 会话管理:在会话管理系统中,Redis 可以通过 LRU 淘汰老旧会话,保证活跃会话的数据保留在内存中。

# 深入追问

🔹 如何调整 Redis 的内存回收策略以适应高并发和不同业务场景?
🔹 在内存回收过程中,如何平衡精确 LRU 和性能开销?
🔹 Redis 的 LRU 近似算法与其他数据库(如 Memcached)采用的内存回收机制有何异同?

# 相关面试题

🔹 请简述 Redis 中的内存回收策略,并结合具体场景进行选择。
🔹 在高并发环境下,如何优化 Redis 内存使用及避免内存溢出?
🔹 Redis 如何实现高效的持久化机制,确保数据不丢失?

# 总结

  1. Redis 的 LRU 算法通过近似实现来高效回收内存,保证最久未访问的键优先被淘汰。
  2. 内存回收策略volatile-lruallkeys-lru 允许开发者根据场景选择合适的策略。
  3. Redis 使用 近似 LRU 算法,减少了精确 LRU 的高开销,并且通过定期扫描来保证内存的回收效率。