redis过期和内存淘汰策略

关于redis的过期和内存淘汰策略的笔记。集合了官方文档,网络资源和实体书里的内容

内存淘汰策略

内存淘汰是用于内存不足时淘汰数据使用

可以使用多大内存

redis通过以下配置决定内存使用量

1
maxmemory 100mb

可以在配置文件中注明,也可以在运行时通过config命令指定

如果设置为0,在64位系统上是无限制,就是可以使用所有的物理内存,在32位系统上最多使用3GB

什么时候淘汰内存

redis遵循以下逻辑

  • 客户端发送一个命令,该命令会导致内存占用增加
  • redis检查当前剩余内存是否够执行该命令,如果不够,则执行淘汰策略
  • redis执行命令,返回结果

有哪些淘汰策略

在4.0以后的版本中,有以下策略

  • noeviction: 可能导致内存增加的命令直接返回错误,所以不包括del和一些其他命令
  • allkeys-lru: 按照最近最少使用算法淘汰,淘汰范围为所有的key
  • volatile-lru: 按照最近最少使用算法淘汰,淘汰范围为设置了过期时间的key
  • allkeys-random: 随机淘汰,淘汰范围为所有的key
  • volatile-random: 随机淘汰,淘汰范围为设置了过期时间的key
  • volatile-ttl: 淘汰ttl最短的key
  • volatile-lfu: 按照最少访问频率淘汰,淘汰范围为设置了过期时间的key
  • allkeys-lfu: 按照最少访问频率淘汰,淘汰范围为所有的key

可以按照以下方式记忆:

redis淘汰策略有:不淘汰最近最少使用(lru)随机淘汰最短过期时间(ttl)最少访问频率(lfu)

除了不淘汰ttl,剩下的又有两种分类,所有的key(allkeys)、有过期时间的key(volatile)


其中noeviction是默认的淘汰策略,同时如果其他淘汰策略无法淘汰合适的内存大小,也会进入该模式

如何选择淘汰策略

  • 如果你不知道怎么选,直接使用allkeys-lru。这是官方推荐的策略(This is a good pick if you are unsure)。

  • 如果所有的key都会被持续地、周期性地被访问,或者你希望分布是均匀的(所有的节点都有相同的访问概率)。这里应该是想说数据没有热点,那就使用allkeys-random

  • 当你创建缓存对象的时候,你可以通过不同的ttl告诉redis哪些数据更应该被淘汰,这时使用volatile-ttl

LRU如何工作

redis的LRU不是标准的lru,而是一种近似算法。

基本原理是,在每个key中记录最后一次访问时间,然后每次随机选出N个key,把N个key中访问时间最小的淘汰。

其中取样个数N可通过CONFIG SET maxmemory-samples <count>或者配置文件中配置。

官网的例子是如果取样是10,那么就非常接近标准LRU算法了

LFU如何工作

LRU仅按照最后一次访问时间作为判断标准,对于部分情况是不够准确的。

假设有个key实际上很少使用,但就在淘汰开始前突然被访问了一次,那么LRU不会淘汰这个key。这里潜藏的风险就是很可能删除了一个当时暂时未被访问,但是以后可能会被高频访问的数据。

以上是对官方文档的不标准翻译


LFU使用8位来记录访问频率。为了实现如此少的位保存足够高的频率,redis使用了一种叫做Morris counter的算法,具体原理暂时不去深究。

redis提供了两个配置项来调整LFU算法

1
2
lfu-log-factor 10
lfu-decay-time 1

decay-time 意为衰退时间,如果不做衰退处理,频率记录只会越来越高,直到上限。文档特别指出不要把这个值设置为0

log-factor 这个值用来限定能够记录的最高频率。redis只用了8位记录频率,那么最高就是255,当访问频率高到一定程度后,频率记录就始终是255,分辨不出高低了。这个值越高,一定程度就会越高。官方给了一个表

factor100 hits1000 hits100K hits1M hits10M hits
0104255255255255
11849255255255
101018142255255
10081149143255

过期策略

redis过期策略有两种:懒删除和定时扫描。官方称其为passive wayactive way

懒删除

每次访问key时,判断key是否已经过期,过期了就删除

定时扫描

redis将会每秒进行10次扫描,每次扫描按照以下流程

  • 从过期字典(记录了所有设置了过期时间的key)中随机挑选20个key
  • 删除其中过期的key
  • 如果过期的数据占据了25%,那么重复步骤1

除了官网内容外,书中还提及redis为了防止过度扫描,规定了一次扫描不能超过25毫秒,这25毫秒内是停止服务的。此外扫描还可能由于内存回收导致卡死。

因此如果发生了缓存雪崩,除了请求击穿到数据库外,redis本身也可能出现一定程度的卡顿

从节点和AOF

当有key过期时,redis会写入一条DEL命令,这个命令会被写入AOF文件以及发送给从节点。所以从节点不会主动进行过期处理,全部依赖主节点的同步

参考文件


redis过期和内存淘汰策略
http://blog.inkroom.cn/2021/06/10/SJBJBC.html
作者
inkbox
发布于
2021年6月10日
许可协议