Redis内存回收机制

Redis之所以性能强,最主要的原因就是基于内存存储。然而单节点的Redis其内存大小不宜过大,会影响持久化或主从同步性能。当内存达到上限,就无法存储更多数据了。因此,Redis内部会有两套内存回收的策略:

  • 内存过期策略

  • 内存淘汰策略

我们可以通过修改redis.conf文件,添加下面的配置来配置Redis的最大内存:

maxmemory 1gb

内存过期处理

存入Redis中的数据可以配置过期时间,到期后再次访问会发现这些数据都不存在了,也就是被过期清理了。

过期命令

Redis中通过 expire 命令可以给KEY设置 TTL(过期时间):

# 写入一条数据
set num 123
# 设置20秒过期时间
expire num 20

不过set命令本身也可以支持过期时间的设置:

# 写入一条数据并设置20s过期时间
set num EX 20

过期策略

Redis不管有多少种数据类型,本质是一个 KEY_VALUE 的键值型数据库,而这种键值映射底层正式基于HashTable来实现的,在Redis中叫做Dict.

:Redis如何判断KEY是否过期呢?

:在Redis中会有两个Dict,也就是HashTable,其中一个记录KEY-VALUE键值对,另一个记录KEY和过期时间。要判断一个KEY是否过期,只需要到记录过期时间的Dict中根据KEY查询即可。

问:Redis是何时删除过期KEY的呢?

答:Redis并不会在KEY过期时立刻删除KEY,因为要实现这样的效果就必须给每一个过期的KEY设置时钟,并监控这些KEY的过期状态。无论对CPU还是内存都会带来极大的负担。

Redis的过期KEY删除策略有两种:

  • 惰性删除:过期后不会立刻删除,Redis会在每次访问KEY的时候判断当前KEY有没有设置过期时间,如果有,过期时间是否已经到期。

  • 周期删除:通过一个定时任务,周期性的抽样部分过期的key,然后执行删除。

    执行周期有两种:

    • SLOW模式:Redis会设置一个定时任务 serverCron(),按照 server.hz 的频率来执行过期 key 清理

    • FAST模式:Redis 的每个事件循环前执行过期 key 清理(事件循环就是 NIO 事件处理的循环)。

SLOW模式规则:

  • ① 执行频率受server.hz影响,默认为10,即每秒执行10次,每个执行周期100ms。

  • ② 执行清理耗时不超过一次执行周期的25%,即25ms.

  • ③ 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期

  • ④ 如果没达到时间上限(25ms)并且过期key比例大于10%,再进行一次抽样,否则结束

FAST模式规则(过期key比例小于10%不执行):

  • ① 执行频率受beforeSleep() 调用频率影响,但两次FAST模式间隔不低于2ms

  • ② 执行清理耗时不超过1ms

  • ③ 逐个遍历db,逐个遍历db中的bucket,抽取20个key判断是否过期

  • ④ 如果没达到时间上限(1ms)并且过期key比例大于10%,再进行一次抽样,否则结束

 内存淘汰策略

 对于某些特别依赖于Redis的项目而言,仅仅依靠过期KEY清理是不够的,内存可能很快就达到上限。因此Redis允许设置内存告警阈值,当内存使用达到阈值时就会主动挑选部分KEY删除以释放更多内存。这叫做内存淘汰机制。

内存淘汰时机 

 Redis每次执行任何命令时,都会判断内存是否达到阈值:

// server.c中处理命令的部分源码
int processCommand(client *c) {
    // ... 略
    if (server.maxmemory && !server.lua_timedout) {
        // 调用performEvictions()方法尝试进行内存淘汰
        int out_of_memory = (performEvictions() == EVICT_FAIL);
        // ... 略
        if (out_of_memory && reject_cmd_on_oom) {
            // 如果内存依然不足,直接拒绝命令
            rejectCommand(c, shared.oomerr);
            return C_OK;
        }
    }
}

 淘汰策略

 Redis支持8种不同的内存淘汰策略:

  • noeviction: 不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。 volatile-ttl: 对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰。
  • allkeys-random:对全体key ,随机进行淘汰。也就是直接从db->dict中随机挑选。
  • volatile-random:对设置了TTL的key ,随机进行淘汰。也就是从db->expires中随机挑选。 allkeys-lru: 对全体key,基于LRU算法进行淘汰。
  • volatile-lru: 对设置了TTL的key,基于LRU算法进行淘汰。
  • allkeys-lfu: 对全体key,基于LFU算法进行淘汰。
  • volatile-lfu: 对设置了TTL的key,基于LFI算法进行淘汰。

其中比较容易混淆的有两个算法:

  • LRU(Least Recently Used),最近最久未使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。

  • LFU(Least Frequently Used),最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fittt_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值