淘汰策略
Redis 当内存达到 maxmemory 上限时,会按配置触发淘汰策略
- volatile-lru:仅在设置了过期时间的键中,淘汰 LRU「最长时间没有使用的数据」
- volatile-ttl:仅在有 TTL 的键中,优先淘汰离过期时间最近的键
- volatile-random:在有 TTL 的键中随机淘汰
- volatile-lfu:仅在有 TTL 的键中,淘汰 LFU 「最不常用」
- allkeys-lru:在所有键中,淘汰 LRU
- allkeys-random:在所有键中随机淘汰
- allkeys-lfu:在所有键中,淘汰 LFU
- noeviction:不淘汰,超过内存时写入报错
LRU 的实现方式
每一个键的对象头中有一个 24 位的“最近访问时钟”字段;服务器维护一个全局的lrulock,每当对象被访问是更新时间。
淘汰机制:候选集合中随机抽取 maxmemory-samples 个键(默认 5)。计算键的未使用时长,维护一个淘汰池(通常为 16),将对象逐个尝试插入淘汰池。删除最久未使用的键,如果仍然超限,就再次更新淘汰池;通过内存足够,淘汰循环退出,池中的剩余项保存。
evict.c
int freeMemoryIfNeeded(void)
LFU 的实现方式
复用对象头的 24 位,低 8 位为频率计数器(0~255,默认初始化为 1),高 16 位为最近衰减时间(分钟)。
访问时,先计算已分钟为单位,计算上次访问时间和经过的lfu_decay_time周期数,,每周期计数减 1,最小到 0。(lfu_decay_time默认为 1,也就是每分钟未访问衰减一次)。每个周期频率计数器减一。最后再按照对数概率p,为频率计数器加一,计数器越大,加一的概率越小。
uint8_t LFULogIncr(uint8_t counter) {
if (counter == 255) return 255;
double r = (double)rand()/RAND_MAX;
double baseval = counter - LFU_INIT_VAL;
if (baseval < 0) baseval = 0;
double p = 1.0/(baseval*server.lfu_log_factor+1);
if (r < p) counter++;
return counter;
}
淘汰机制:与 LRU 相同采取采样,每轮随机取 maxmemory-samples 个候选键,255 - 频率计数器,越高放在淘汰池的位置越前。