Redis 可以通过一个叫做过期字典(可以看作是 hash 表)的东西来保存存储数据时设置的过期时间。过期字典的 key 指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。
过期的数据的删除策略
假设我们设置了一批 key,为这些 key 设置的过期时间是 1 分钟,那么 1 分钟后,Redis 是怎么对这批 key 进行删除的呢?
常用的过期数据的删除策略就两个:
- 惰性删除 :这种方法只会在获取 key 的时候才对数据进行过期检查,如果该 key 已经过期了,那么就删除;如果过了 1 分钟的时间甚至更久,这个 key 都没有被获取过,那么就会一直保留着。这样删除策略对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。
- 定期删除 :这种方法是每隔一段时间抽取一批 key 执行过期检查并删除的操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
定期删除对内存更加友好,惰性删除对 CPU 更加友好。两者各有千秋,所以 Redis 采用的是两种策略结合的一种更优策略,即定期删除+惰性/懒汉式删除。
但是,仅仅通过判断给 key 设置的过期时间来进行过期数据的删除还是有很大问题的。因为还是可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致大量过期 key 堆积在内存里,然后就 Out of memory 了。
为了弥补这种缺陷,于是 Redis 推出了内存淘汰机制。
Redis 内存淘汰机制
Redis 提供了 6 种数据淘汰策略:
1.volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据执行淘汰操作;
2.volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选即将要过期的数据执行淘汰操作;
3.volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据执行淘汰操作;
4.allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
5.allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
6.no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。
Redis 4.0 版本后又增加了两种:
7.volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据执行淘汰操作
8.allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key
本文参考自:Redis知识点&面试题总结 | JavaGuide