Redis纪元以自增的方式清除数据(redis自增清除)

2023-05-12 04:42:21 方式 清除 纪元

Redis纪元:以自增的方式清除数据

Redis是一个高性能的key-value存储系统,也是一个基于内存的数据结构服务,常用于缓存、消息队列等场景。然而,随着Redis存储数据量的增加,其内存占用也会不断增加,导致系统性能下降,甚至出现OOM(Out Of Memory)等问题。为此,Redis提供了一种自增的方式清除数据的功能,其中包括主动清除过期数据和内存不足时自动清除数据。

1. 主动清除过期数据

Redis支持key的过期时间,即在指定时间后自动删除key和对应的value。可以通过EXPIRE命令设置key的过期时间,单位为秒。例如,设置key“foo”的过期时间为60秒:

> SET foo bar
OK
> EXPIRE foo 60
(integer) 1

在Redis中有一个定时事件,会定期清除已过期的key,该事件的周期由服务器的配置参数“hz”决定。当一个key被检测到已过期时,服务器会在清除该key之前检查是否设置了该key的watcher(通过REDIS WATCHER命令可以为一个key添加watcher)。如果设置了watcher,则在删除该key之前,服务器会将watcher加入到一个队列中,等到key真正被删除后,通知与之相关的客户端,让其处理相关业务逻辑。

2. 内存不足时自动清除数据

Redis的内存管理算法采用的是“all or nothing”的方式,即当Redis内存不足时,会使用尽可能少的内存保证master和slave节点的同步(一致性)。如果仍然无法满足需求,则会删除最久没有使用的key,以释放更多内存空间。这个过程中,Redis会从Redis数据库中随机选择key并检查其是否过期,如果过期则直接删除,否则则计算该key最后一次被访问的时间戳,选择最久没有访问的key进行删除。在检查key是否过期和最后一次被访问的时间戳时,Redis会为每个key设置一个计数器(epoch),用于记录某个时间段内该key被访问的次数并排名,以便选择最久没有使用的key进行删除。

以下是Redis内存管理算法的核心代码实现:

“`c

struct evictionPoolEntry *pool = NULL;

long long evictionPoolSize = 0;

// 初始化pool和poolSize

static void evictionPoolAlloc(void) {

pool = zcalloc(sizeof(*pool) * server.maxmemory_samples);

}

// 添加entry到pool中

void evictionPoolAppendEntry(const sds key, const unsigned long long val) {

struct evictionPoolEntry *sep; //sep指向pool的最后一项

sep = &pool[evictionPoolSize++];

sep->key = sdsdup(key);

sep->key_len = sdslen(key);

sep->val = val;

}

// 更新entry在pool中的val

int evictionPoolTouchItem(const sds key, const unsigned long long val) {

int j;

for (j = 0; j

if (sdslen(pool[j].key) == sdslen(key) &&

memcmp(pool[j].key,key,sdslen(key)) == 0) // 找到匹配的key

{

pool[j].val = val; // 更新val

return 1;

}

}

return 0;

}

// 从pool中选择最久没使用的entry并删除

int tryEviction(void) {

int i, j;

struct evictionPoolEntry *victim = NULL;

// 根据epoch排序pool中的entry,并选择最久没使用的entry

qsort(pool, evictionPoolSize, sizeof(struct evictionPoolEntry), evictionPoolCompare);

for (i = 0; i

// delete the key with the smaller epoch (less recently accessed).

if (canEvict && pool[i].val != 255) {

victim = &pool[i];

break;

}

}

// 删除victim对应的key

if (victim) {

serverAssert(lazyfreeGetPendingObjectsCount() == 0);

int deleted = dbSyncDelete(server.db+id, sdsdup(victim->key), sdslen(victim->key));

if (deleted) server.stat_evictedkeys++;

sdsfree(victim->key);

victim->val = 255;

return 1;

}

return 0;

}


通过上述代码可以看到,Redis内存管理算法主要分为三个步骤:

1.将所有key计入evictionPool,为每个key添加epoch和触发条件;

2. 当内存不足时,检查evictionPool中的所有key,选择最久没有使用的key进行删除,并将其epoch设置为255(即不能再次删除);

3. 当新的key被添加到evictionPool时,会将其epoch初始化为0。

以上就是Redis自增方式清除数据的核心实现,通过定期清除过期数据和在内存不足时自动清除数据,Redis能够更好地管理内存,提高系统性能和稳定性。

相关文章