0
点赞
收藏
分享

微信扫一扫

Redis过期key删除和逐出策略

删除策略

Redis对于过期key主要有三种删除策略

1.立即删除

在设置键的过期时间时,创建一个回调事件,当过期时间达到时,由时间处理器自动执行键的删除操作。立即删除能保证内存中数据的最大新鲜度,因为它保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。但是立即删除会占用cpu事件,如果有大量的连接或数据写入,就会给cpu造成额外的压力。Redis事件处理器对时间事件的处理方式--无序链表,查找一个key的时间复杂度为O(n),所以并不适合用来处理大量的时间事件。

2.惰性删除

某个键值过期后,此键值不会马上被删除,而是等到下次被访问时,才会被检查到过期,所以惰性删除的缺点就是浪费内存,不能及时释放内存

3.定时删除。

每隔一段时间执行一次删除操作,并通过限制删除操作执行的cpu时长和频率,来减少删除操作对cpu的影响。另一方面定时删除也有效的减少了因惰性删除带来的内存浪费。

过期key清理算法

过期key的清理算法,都是在尽量不影响正常服务情况下进行清理,以达到最优的性能,会周期性的随机测试一批具体过期时间的key进行清理,具体的算法如下:

  • Redis会根据频率hz参数定义了servercron函数进行定时任务的执行周期,该默认值为10,最小为1,最大为500,在cpu空闲时将每秒执行10次,

  • 每次过期key清理的cpu时间占用不会超过25%,。默认hz等于10,则一次清理时间最大为25ms。
  • 从一个库中随机抽取20个Key,判断是否过期,若过期,则逐出过期Key。

  • 每次清理过期Key时都会依次遍历所有的库。
  • 在清理过程中,若达到了CPU时间的25%,则退出清理过程。

数据逐出策略

当超过redis设置的maxmeory的值时,配置参数maxmemory-policy,选出待逐出的key,直到当前内存小于最大内存值为止,如果maxmemory设置为0,逐出策略不生效,maxmemory-policy参数值如下6种:

  • noeviction:当内存使用达到阈值的时候,当内存不足时会抛出OOM command not allowed when used memory > 'maxmemory'.。
  • allkeys-lru:在主键空间中,优先移除最近未使用的key。
  • volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
  • allkeys-random:在主键空间中,随机移除某个key。
  • volatile-random:在设置了过期时间的键空间中,随机移除某个key。
  • volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。

没有符合清除条件的key时,回收策略 volatile-lru, volatile-random 和volatile-ttl 将会和策略 noeviction 一样直接返回错误。

过期key清理代码分析

惰性删除,当访问key时,会判断key的是否过期,过期则逐出key

robj *lookupKeyRead(redisDb *db, robj *key) {
robj *val;
expireIfNeeded(db,key);
val = lookupKey(db,key);
...
return val;
}

定时删除,通过servercron定时任务进行逐出

aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL)

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
...
databasesCron();
...
}

void databasesCron(void) {
/* Expire keys by random sampling. Not required for slaves
+ as master will synthesize DELs for us. */
if (server.active_expire_enabled && server.masterhost == NULL)
activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
...
}

立即删除,每次都在事件循环执行后,逐出部分过期key

void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
aeProcessEvents(eventLoop, AE_ALL_EVENTS);
}
}

void beforeSleep(struct aeEventLoop *eventLoop) {
...
/* Run a fast expire cycle (the called function will return
- ASAP if a fast cycle is not needed). */
if (server.active_expire_enabled && server.masterhost == NULL)
activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);
...
}


举报

相关推荐

0 条评论