Redis纪元以自增的方式清除数据(redis自增清除)
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能够更好地管理内存,提高系统性能和稳定性。