什么是Redis中的惰性删除?
Redis是非关系型数据库,在内存中存储数据。Redis中的惰性删除(Lazy free)是指在Redis占用内存时,并不会立即删除数据,而是会等到内存不足时才进行数据的删除操作。
对于内存中的数据,Redis会使用一个引用计数来记录该数据被多少个键所引用,如果没有引用计数时,Redis会自动将其删除。
Redis中为什么需要惰性删除?
在Redis中,内存是比较宝贵的资源,而且内存资源是有限的,如果Redis对数据进行实时删除,造成的开销是非常大的。
因此Redis将数据的删除操作延迟到内存不足时再执行,以此来提高Redis的性能和效率。
Redis惰性删除的优点
1. 提高Redis性能效率
Redis使用惰性删除的方式,可以有效的提高Redis的性能与效率,因为实时删除数据会导致Redis的性能下降,而惰性删除可以将删除操作的代价分摊到若干个操作中。
当Redis执行惰性删除操作时,它会将需要删除的数据标记为“已删除”,而不是立即进行删除。当Redis需要为其他数据腾出空间时,它就会回收已删除的数据所占用的内存空间。
2. 减少数据的二次删除
对于Redis中的某个数据,如果它还没有被任何键所引用,Redis就会自动将其删除。这种自动删除的方式往往会造成数据的二次删除。
因为Redis内部的复制机制,一个已经被删除了的数据还可能存在于某些节点的内存中,当这个节点向集群中传递数据的时候,他就有可能把已经被删除的数据再次传递出去。这会造成数据的二次删除,浪费Redis的内存空间。
而使用惰性删除的方式,能够减少数据的二次删除,因为 Redis 内部使用了引用计数器,它会记录每个键所引用的数据的引用次数。当一个键被删除时,Redis会自动将其引用计数减一,只有当引用计数器的引用次数变为0时,才会将其删除。
Redis惰性删除的实现方式
Redis内部的惰性删除是通过引用计数器来实现的。当一个数据被多个键所引用时,Redis会在内存中保存这个数据的引用计数。
当需要删除某个数据时,Redis会将这个数据的引用计数减一,只有当引用计数为0时,Redis才会将这个数据从内存中删除。
引用计数器的缺点:
引用计数器有一个比较明显的缺点,就是它无法处理循环引用的情况,这会导致一些数据无法被删除,从而浪费内存空间。
Redis的处理方式:
Redis中,遇到循环引用的情况,会使用定期删除和惰性删除相结合的方式。
1. 定期删除
定期删除是指Redis会周期性地检查内存中的数据是否已经过期或者是否需要删除。对于那些没有被访问过且存在时间超过了一定限制的数据,Redis会将其删除。这个时间限制,是由Redis内部的时间事件机制来实现的。
2. 惰性删除
Redis中的惰性删除实际上是一种优化手段,它不会实时删除数据,而是在内存不足时才会进行数据的删除操作。
当Redis分配新的内存空间时,如果当前内存已经使用了80%以上,Redis就会触发一个内存回收机制,将一些已经被删除但是依然占用内存空间的数据进行回收。
总结
Redis中的惰性删除可以有效地提高Redis的性能和效率。通过在删除数据时,不立即进行删除操作,而是等到内存不足时再进行删除,Redis可以避免实时删除操作对性能造成的影响,并且减少被删除数据的二次删除情况。
Redis中的惰性删除是通过引用计数器来实现的,但是引用计数器无法处理循环引用的情况。因此,Redis在惰性删除的基础上,采用了定期删除的方式,并将其两者进行结合,以此来保证Redis的数据不会出现严重的内存泄漏。
// 惰性删除的代码实现
void dictDelete(dict *ht, const void *key) {
// 查找要删除的键
dictht *ht = &ht->ht[table];
dictEntry *he = dictUnlink(ht,key);
if (he) {
// 只有在当前哈希表的rehash操作都完成才执行惰性删除操作
if (ht->dictRehashIndex == -1) {
dictFreeEntryKey(ht,he);
dictFreeEntryVal(ht,he);
zfree(he);
}
// 在rehash过程中等待惰性删除操作
else {
he->next = ht->delHashEntry;
ht->delHashEntry = he;
}
ht->used--;
return DICT_OK;
}
return DICT_ERR;
}