概述
Redis 作为一种高性能的内存数据库,提供了数据过期和淘汰策略以管理存储的数据。本文将详细探讨 Redis 中数据失效的基本原理、实现方式,并结合源码进行分析,帮助读者更深入地理解和优化 Redis 的使用。
数据过期机制
过期键的存储方式
Redis 中每个数据库都有一个 expires
字典,用于保存设置了过期时间的键及其对应的过期时间戳。这个字典的作用类似于索引,通过它能够快速判断某个键是否已过期。
typedef struct redisDb {dict *dict; // 存储键值对dict *expires; // 存储键的过期时间// 其他成员...
} redisDb;
定时删除 vs 惰性删除 vs 定期删除
定时删除(Active Expiration / Timer-based Deletion)
定时删除是一种“主动式”删除机制。当用户为一个键设置过期时间时,Redis 会记录该键的过期时间戳,并注册一个定时器,在指定时间到达后自动触发删除操作。虽然这种方法能及时释放内存资源,但可能会导致 CPU 使用率飙升。
// 设置键的过期时间
void setExpire(client *c, robj *key, long long when) {dictEntry *de;de = dictFind(c->db->dict,key->ptr);serverAssertWithInfo(c,key,de != NULL);dictSetVal(c->db->expires,dictAddRaw(c->db->expires,key->ptr,&de),when);
}
惰性删除(Lazy Expiration / On-access Deletion)
惰性删除是一种“被动式”机制。只有在访问某个键时才会检查其是否已经过期,如果已过期则立即删除。这种方式可以显著降低 CPU 的消耗,但代价是部分过期键会长时间保留在内存中。
int expireIfNeeded(redisDb *db, robj *key) {if (!keyIsInHashtable(db->expires, key)) return 0;mstime_t when = getExpire(db, key);mstime_t now = mstime();if (now > when) {deleteExpiredKey(db, key);return 1;}return 0;
}
定期删除(Periodic Expiration)
定期删除是 Redis 主动清理过期键的主要方式之一。Redis 在后台每隔一段时间扫描部分设置了过期时间的键,随机选取一部分进行过期检测,并删除其中已经过期的键。
void activeExpireCycle(int type) {static unsigned int current_db = 0;unsigned int j, iteration = 0;unsigned int dbs_per_call = CRON_DBS_PER_CALL;int start = ustime(), timelimit, noexpire = 0;if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum;timelimit = 1000000 * ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC / 100;timelimit -= (ustime() - start);for (j = 0; j < dbs_per_call && timelimit > 0 && !noexpire; j++) {redisDb *db = server.db + (current_db % server.dbnum);current_db++;int num = dictSize(db->expires);int slots = ceil(num / 16.0); // 随机选择 slot 数量while (slots--) {dictEntry *de;long long ttl;if ((de = dictGetRandomKey(db->expires)) == NULL) break;robj *key = dictGetKey(de);ttl = dictGetSignedIntegerVal(de) - mstime();if (ttl < 0) {dbDelete(db, key);}}if ((iteration++ % 10) == 0) {long long elapsed = ustime() - start;if (elapsed >= timelimit) break;}}
}
内存淘汰机制
当 Redis 使用的内存超过 maxmemory
限制时,将会根据配置的淘汰策略来决定移除哪些键值对。常见的淘汰策略包括:
volatile-lru
:从设置了过期时间的数据集中挑选最近最少使用的数据淘汰。allkeys-lru
:从所有数据集中挑选最近最少使用的数据淘汰。volatile-random
:从设置了过期时间的数据集中任意选择数据淘汰。allkeys-random
:从所有数据集中任意选择数据淘汰。
UML图解 Redis 过期键处理流程
以下是使用 UML 绘制的简化版 Redis 过期键处理流程图,包括定时删除、惰性删除和定期删除的工作流程:
定时删除:
惰性删除:
定期删除:
结语
Redis 通过一系列复杂的机制来管理数据的生命周期和内存使用情况,旨在提供高效的数据管理和查询服务。理解这些基本概念和机制对于优化性能、避免内存溢出等问题至关重要。希望这篇文章能为你提供有价值的参考信息,帮助你更好地利用 Redis 提供的功能。