Redis - 过期和淘汰策略

过期删除策略

如何判断 key 过期

当对一个 key 设置了过期时间,Redis 会把该 key 和过期时间存储到「过期字典」,过期字典保存了所有 key 的过期时间

当我们查询一个 key 的时候,Redis 先检查是否存在于过期字典

  • 不在则正常读取
  • 如果存在,则判断是否过期

删除策略

定时删除

在设置 key 过期时间时,同时创建一个定时事件,由事件自动执行 key 的删除操作

优点 可以保证 key 尽快删除,内存尽快释放

缺点 过期 key 较多的情况,删除过期 key 会占用相当一部分 CPU 事件

惰性删除

不主动删除过期键,每次从数据库访问 key 时,检测 key 是否过期,如果过期则删除

优点 分散了过期 key 的删除时间,每次只占用很少的系统资源

缺点 如果一个 key 过期后没有被访问,就会一直占用内存

定期删除

每隔一段时间「随机」从数据库取出一定数量的 key 检查,并删除其中的过期 key

优点 通过限制删除操作的时长和频率,减少 CPU 占用,也能删除一部分 key 来减少空间占用

缺点 内存清理不如定时删除,CPU 占用不如惰性删除;难以确认操作执行的时长和频率,间隔过长或过短都不合适

Redis 在用的删除策略

Redis 结合了惰性删除和定期删除搭配使用

内存淘汰策略

内存淘汰策略是指在 Redis 的运行内存已经超过 Redis 设置的最大内存之后,删除符合条件的 key 以保证 Redis 运行的策略

设置最大内存

可以在配置文件中通过 maxmemory 参数设置最大内存

淘汰策略

  • noeviction: 表示不淘汰任何数据,在超过最大内存后如果有新的数据写入,会报错禁止写入
  • volatile-random: 随机淘汰设置了过期时间的任意键值
  • volatile-ttl: 优先淘汰更早过期的键值
  • volatile-lru: 淘汰设置了过期时间的键值中,最久未使用的键值
  • volatile-lfu: 淘汰设置了过期时间的键值中,最少使用的键值
  • allkeys-random: 随机淘汰任意键值
  • allkeys-lru: 淘汰所有键值中,最久未使用的键值
  • allkeys-lfu: 淘汰所有键值中,最少使用的键值

LRU

LRU 全称是 Least Recently Used

传统的 LRU 实现基于链表结构,最新操作的键会被移动到表头,这样需要内存淘汰时,只需要淘汰表尾元素

存在问题

  • 需要链表管理所有缓存数据,额外的空间开销
  • 大量数据被访问时,会频繁移动链表元素

Redis 实现的是近似 LRU 算法,它在 Redis 的对象结构中额外添加了一个字段,记录数据的最后一次访问时间

当 Redis 进行内存淘汰时,会使用随机采样的方式,取 N 个值(可配置),并淘汰其中最久没有使用的值

优点

  • 不需要维护链表,节约空间占用
  • 不需要移动链表,提升性能

缺点 无法解决缓存污染问题,例如一个应用一次读取了大量数据,这些数据可能之后不会被读取了,但却会在 Redis 中存在很长时间,造成缓存污染

LFU

LFU 全称是 Least Frequently Used

LFU 是根据数据访问次数来淘汰数据的。在 Redis 中,相比 LRU 的实现,多记录一个「数据访问频次」的数据

Licensed under CC BY-NC-SA 4.0
最后更新于 Nov 11, 2020 00:00 UTC