Redis 过期策略与内存淘汰算法全解析
前言
Redis 作为高性能的内存数据库,内存管理是其核心功能之一。当数据写入 Redis 后,如何处理过期的键?当内存不足时,如何淘汰数据?这两个问题直接关系到 Redis 的性能和稳定性。本文将深入剖析 Redis 的过期策略和内存淘汰算法,结合源码分析其实现原理。
标签: Redis,过期策略,内存淘汰,LRU,LFU
一、Redis 过期策略
1.1 设置过期时间的方式
Redis 提供了四种设置过期时间的命令:
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key# 1. EXPIRE - 设置秒级过期时间
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST keyEXPIRE key 60
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key# 2. PEXPIRE - 设置毫秒级过期时间
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST keyPEXPIRE key 60000
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key# 3. EXPIREAT - 设置秒级过期时间戳
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST keyEXPIREAT key 1672531200
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key# 4. PEXPIREAT - 设置毫秒级过期时间戳
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST keyPEXPIREAT key 1672531200000
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key# 5. TTL 和 PTTL - 查看剩余时间
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST keyTTL key # 返回秒
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST keyPTTL key # 返回毫秒
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST key# 6. PERSIST - 移除过期时间
# 1. EXPIRE - 设置秒级过期时间
EXPIRE key 60
# 2. PEXPIRE - 设置毫秒级过期时间
PEXPIRE key 60000
# 3. EXPIREAT - 设置秒级过期时间戳
EXPIREAT key 1672531200
# 4. PEXPIREAT - 设置毫秒级过期时间戳
PEXPIREAT key 1672531200000
# 5. TTL 和 PTTL - 查看剩余时间
TTL key # 返回秒
PTTL key # 返回毫秒
# 6. PERSIST - 移除过期时间
PERSIST keyPERSIST key
源码实现(Redis 7.2.0):
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}// db.c (Redis 7.2.0) - EXPIRE 命令实现
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}void expireCommand(client *c) {
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} expireGenericCommand(c, 0, 0);
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}}
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}void pexpireCommand(client *c) {
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} expireGenericCommand(c, 0, 1);
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}}
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}void expireGenericCommand(client *c, long long basetime, int unit) {
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} robj *key = c->argv[1];
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} long long when; /* 过期时间(毫秒时间戳) */
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} /* 1. 解析过期时间参数 */
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} return;
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} /* 2. 转换为绝对时间戳 */
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} if (unit == 0) { /* EXPIRE 秒级 */
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} when *= 1000;
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} }
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} /* 3. 设置过期时间 */
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} if (setExpire(c->db, key, when) == 1) {
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} addReply(c, shared.cone);
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} propagateExpire(key, when);
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} server.dirty++;
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} } else {
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} addReply(c, shared.czero);
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
} }
#// db.c (Redis 7.2.0) - EXPIRE 命令实现
void expireCommand(client *c) {
expireGenericCommand(c, 0, 0);
}
void pexpireCommand(client *c) {
expireGenericCommand(c, 0, 1);
}
void expireGenericCommand(client *c, long long basetime, int unit) {
robj *key = c->argv[1];
long long when; /* 过期时间(毫秒时间戳) */
/* 1. 解析过期时间参数 */
if (getLongLongFromObjectOrReply(c, c->argv[2], &when, NULL) != C_OK)
return;
/* 2. 转换为绝对时间戳 */
if (unit == 0) { /* EXPIRE 秒级 */
when *= 1000;
}
when += basetime; /* 加上基准时间(EXPIREAT 时使用) */
/* 3. 设置过期时间 */
if (setExpire(c->db, key, when) == 1) {
addReply(c, shared.cone);
propagateExpire(key, when);
server.dirty++;
} else {
addReply(c, shared.czero);
}
}}
1.2 过期键的存储结构
Redis 在 redisDb 结构中维护了一个过期字典:
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb;// server.h (Redis 7.2.0)
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb;typedef struct redisDb {
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb; dict *dict; /* 键空间字典:key -> value */
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb; dict *expires; /* 过期字典:key -> 过期时间戳 */
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb; dict *blocking_keys; /* 阻塞操作 */
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb; dict *ready_keys; /* 准备好的键 */
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb; dict *watched_keys; /* WATCH 命令 */
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb; int id; /* 数据库 ID */
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb; long long avg_ttl; /* 平均 TTL */
#// server.h (Redis 7.2.0)
typedef struct redisDb {
dict *dict; /* 键空间字典:key -> value */
dict *expires; /* 过期字典:key -> 过期时间戳 */
dict *blocking_keys; /* 阻塞操作 */
dict *ready_keys; /* 准备好的键 */
dict *watched_keys; /* WATCH 命令 */
int id; /* 数据库 ID */
long long avg_ttl; /* 平均 TTL */
} redisDb;} redisDb;
过期字典的结构:
graph LR
subgraph "键空间 dict"
K1["name"] --> V1["Alice"]
K2["age"] --> V2["25"]
K3["token"] --> V3["xyz123"]
end
subgraph "过期字典 expires"
K1 --> E1[1704067200000]
K3 --> E3[1704067260000]
end
style K1 fill:#f9f,stroke:#333
style K3 fill:#f9f,stroke:#333
style E1 fill:#ff9,stroke:#333
style E3 fill:#ff9,stroke:#333
1.3 三种过期删除策略
| 策略 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| 定时删除 | 设置过期时间时,创建定时器,到期立即删除 | 内存友好,过期键立即释放 | CPU 不友好,大量过期键会影响性能 |
| 惰性删除 | 访问键时检查是否过期,过期则删除 | CPU 友好,只在访问时检查 | 内存不友好,过期键可能长时间占用内存 |
| 定期删除 | 每隔一段时间,随机抽查过期键并删除 | 折中方案,平衡 CPU 和内存 | 需要合理设置删除频率和范围 |
Redis 采用的策略:惰性删除 + 定期删除
graph TB
A[客户端访问 key] --> B{key 存在?}
B -->|不存在| C[返回 nil]
B -->|存在| D{检查过期字典}
D -->|未设置过期| E[返回 value]
D -->|已过期| F[删除 key]
F --> G[返回 nil]
H[定时任务<br/>每 100ms 执行一次] --> I[随机抽查 20 个 key]
I --> J{发现过期 key?}
J -->|是| K[删除过期 key]
J -->|否| L[结束]
K --> M{过期 key 比例 > 25%?}
M -->|是| I
M -->|否| L
style F fill:#f99,stroke:#333
style K fill:#f99,stroke:#333
二、惰性删除实现
2.1 源码分析
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}// db.c (Redis 7.2.0) - 惰性删除入口
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}int expireIfNeeded(redisDb *db, robj *key) {
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} /* 1. 检查是否设置了过期时间 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} long long when = getExpire(db, key);
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} if (when < 0) return 0; /* 没有过期时间 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} /* 2. 检查是否正在加载 RDB 或 AOF */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} if (server.loading) return 0;
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} /* 3. 当前时间与过期时间比较 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} long long now = commandTimeSnapshot();
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} if (now <= when) return 0; /* 未过期 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} /* 4. 删除过期键 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} server.stat_expiredkeys++;
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} propagateExpire(key, when);
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} return dbDelete(db, key); /* 从键空间和过期字典中删除 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}}
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}// 在所有读写命令中调用
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} robj *val;
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} /* 惰性删除检查 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} if (expireIfNeeded(db, key)) {
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} /* key 已被删除 */
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} return NULL;
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} }
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} val = lookupKey(db, key, flags);
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
} return val;
#// db.c (Redis 7.2.0) - 惰性删除入口
int expireIfNeeded(redisDb *db, robj *key) {
/* 1. 检查是否设置了过期时间 */
long long when = getExpire(db, key);
if (when < 0) return 0; /* 没有过期时间 */
/* 2. 检查是否正在加载 RDB 或 AOF */
if (server.loading) return 0;
/* 3. 当前时间与过期时间比较 */
long long now = commandTimeSnapshot();
if (now <= when) return 0; /* 未过期 */
/* 4. 删除过期键 */
server.stat_expiredkeys++;
propagateExpire(key, when);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", key, db->id);
return dbDelete(db, key); /* 从键空间和过期字典中删除 */
}
// 在所有读写命令中调用
robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
robj *val;
/* 惰性删除检查 */
if (expireIfNeeded(db, key)) {
/* key 已被删除 */
return NULL;
}
val = lookupKey(db, key, flags);
return val;
}}
调用时机:
GET、SET、DEL等所有访问 key 的命令KEYS、SCAN等遍历命令RANDOMKEY随机获取 key
三、定期删除实现
3.1 源码分析
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}// expire.c (Redis 7.2.0) - 定期删除主函数
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}void activeExpireCycle(int type) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 静态变量,记录上次处理的数据库索引 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} static unsigned int current_db = 0;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 1. 每次处理的数量限制 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} timelimit = 10000; /* 最多 10ms */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 2. 遍历数据库 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} for (int j = 0; j < dbs_per_call; j++) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} redisDb *db = &server.db[current_db % server.dbnum];
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} current_db++;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 3. 跳过没有过期键的数据库 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} if (dictSize(db->expires) == 0) continue;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 4. 随机抽查过期键 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} long long start = ustime();
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} int deleted = 0;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} while (num--) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} dictEntry *de;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 随机获取一个带过期时间的 key */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} if ((de = dictGetRandomKey(db->expires)) == NULL) break;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 检查并删除 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} if (activeExpireCycleTryExpire(db, de, start)) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} deleted++;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} }
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} }
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 5. 如果删除的 key 比例超过 25%,继续处理 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} continue;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} }
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 6. 超时则退出 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} if (ustime() - start > timelimit) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} break;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} }
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} }
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}// 尝试删除单个过期键
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} long long expire = dictGetSignedIntegerVal(de);
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} if (now > expire) {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} /* 已过期,删除 */
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} robj *key = dictGetKey(de);
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} dbDelete(db, key);
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} return 1;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} } else {
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} return 0;
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
} }
#// expire.c (Redis 7.2.0) - 定期删除主函数
void activeExpireCycle(int type) {
/* 静态变量,记录上次处理的数据库索引 */
static unsigned int current_db = 0;
/* 1. 每次处理的数量限制 */
long long timelimit = 1000000 / ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC;
timelimit = 10000; /* 最多 10ms */
/* 2. 遍历数据库 */
int dbs_per_call = (server.dbnum < 16) ? server.dbnum : 16;
for (int j = 0; j < dbs_per_call; j++) {
redisDb *db = &server.db[current_db % server.dbnum];
current_db++;
/* 3. 跳过没有过期键的数据库 */
if (dictSize(db->expires) == 0) continue;
/* 4. 随机抽查过期键 */
long long start = ustime();
int num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP; /* 20 */
int deleted = 0;
while (num--) {
dictEntry *de;
/* 随机获取一个带过期时间的 key */
if ((de = dictGetRandomKey(db->expires)) == NULL) break;
/* 检查并删除 */
if (activeExpireCycleTryExpire(db, de, start)) {
deleted++;
}
}
/* 5. 如果删除的 key 比例超过 25%,继续处理 */
if (deleted > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP / 4) {
continue;
}
/* 6. 超时则退出 */
if (ustime() - start > timelimit) {
break;
}
}
}
// 尝试删除单个过期键
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now) {
long long expire = dictGetSignedIntegerVal(de);
if (now > expire) {
/* 已过期,删除 */
robj *key = dictGetKey(de);
dbDelete(db, key);
return 1;
} else {
return 0;
}
}}
3.2 定期删除的参数调优
| 参数 | 默认值 | 说明 | 调优建议 |
|---|---|---|---|
hz |
10 | 每秒执行定期删除的次数(10 = 100ms一次) | 内存压力大时调高(如 20),但会增加 CPU 使用 |
active-expire-cycle-lookups-per-loop |
20 | 每次循环抽查的 key 数量 | 内存压力大时调高(如 50) |
active-expire-cycle-slow-time-perc |
1 | 定期删除占用的 CPU 时间比例(1%) | CPU 敏感场景调低 |
active-expire-cycle-fast-time-perc |
5 | 快速模式占用的 CPU 时间比例(5%) | - |
配置建议:
# 生产环境推荐配置
hz 10 # 默认值即可
active-expire-cycle-lookups-per-loop 20 # 默认值
active-expire-cycle-slow-time-perc 1 # 默认值# 生产环境推荐配置
# 生产环境推荐配置
hz 10 # 默认值即可
active-expire-cycle-lookups-per-loop 20 # 默认值
active-expire-cycle-slow-time-perc 1 # 默认值hz 10 # 默认值即可
# 生产环境推荐配置
hz 10 # 默认值即可
active-expire-cycle-lookups-per-loop 20 # 默认值
active-expire-cycle-slow-time-perc 1 # 默认值active-expire-cycle-lookups-per-loop 20 # 默认值
# 生产环境推荐配置
hz 10 # 默认值即可
active-expire-cycle-lookups-per-loop 20 # 默认值
active-expire-cycle-slow-time-perc 1 # 默认值active-expire-cycle-slow-time-perc 1 # 默认值
四、内存淘汰算法
4.1 淘汰算法概述
当内存达到上限时,Redis 会根据配置的淘汰策略删除部分数据。Redis 7.2.0 支持 9 种淘汰策略:
| 策略 | 说明 | 使用场景 |
|---|---|---|
| noeviction | 不淘汰,写入时返回错误 | 缓存场景,不允许丢数据 |
| allkeys-lru | 从所有 key 中淘汰 LRU | 通用缓存 |
| allkeys-lfu | 从所有 key 中淘汰 LFU | 适合热点数据 |
| volatile-lru | 从设置了过期时间的 key 中淘汰 LRU | 只淘汰有过期时间的缓存 |
| volatile-lfu | 从设置了过期时间的 key 中淘汰 LFU | 热点数据有过期时间 |
| allkeys-random | 从所有 key 中随机淘汰 | 简单场景 |
| volatile-random | 从设置了过期时间的 key 中随机淘汰 | - |
| volatile-ttl | 优先淘汰 TTL 小的 key | 适合会话数据 |
| allkeys-lfu | 从所有 key 中淘汰 LFU | 新增策略(Redis 4.0+) |
4.2 LRU 算法实现
Redis 使用的是 近似 LRU 算法,而非经典的 LRU:
为什么不使用精确 LRU?
- 经典 LRU 需要维护链表,每次访问都要更新链表,开销大
- Redis 需要高性能,不能在每次访问时都更新数据结构
Redis 的近似 LRU:
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj;// server.h (Redis 7.2.0) - redisObject 结构
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj;typedef struct redisObject {
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj; unsigned type:4; /* 类型 */
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj; unsigned encoding:4; /* 编码 */
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj; unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj; int refcount; /* 引用计数 */
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj; void *ptr; /* 指向实际数据的指针 */
#// server.h (Redis 7.2.0) - redisObject 结构
typedef struct redisObject {
unsigned type:4; /* 类型 */
unsigned encoding:4; /* 编码 */
unsigned lru:24; /* LRU 时间戳(24位,存储约 194 天) */
int refcount; /* 引用计数 */
void *ptr; /* 指向实际数据的指针 */
} robj;} robj;
LRU 淘汰流程:
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
}// evict.c (Redis 7.2.0) - LRU 淘汰
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
}int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} int j, k;
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} dictEntry *samples[server.maxmemory_samples];
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} /* 1. 随机采样 N 个 key(默认 5) */
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} for (j = 0; j < server.maxmemory_samples; j++) {
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} de = dictGetRandomKey(keydict);
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} samples[j] = de;
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} }
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} /* 2. 找出最老的 key(LRU 值最小) */
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} for (k = 0; k < server.maxmemory_samples; k++) {
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} unsigned long long lru = objectLRUClock(samples[k]);
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} /* 3. 插入淘汰池(按 LRU 排序) */
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} evictionPoolInsert(lru, samples[k]);
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} }
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
} return C_OK;
#// evict.c (Redis 7.2.0) - LRU 淘汰
int evictionPoolPopulate(dict *sample_dict, dict *keydict, dict *eviction_pool) {
int j, k;
dictEntry *samples[server.maxmemory_samples];
/* 1. 随机采样 N 个 key(默认 5) */
for (j = 0; j < server.maxmemory_samples; j++) {
de = dictGetRandomKey(keydict);
samples[j] = de;
}
/* 2. 找出最老的 key(LRU 值最小) */
for (k = 0; k < server.maxmemory_samples; k++) {
unsigned long long lru = objectLRUClock(samples[k]);
/* 3. 插入淘汰池(按 LRU 排序) */
evictionPoolInsert(lru, samples[k]);
}
return C_OK;
}}
maxmemory_samples 参数影响:
| maxmemory_samples | 采样数量 | 准确度 | 性能 |
|---|---|---|---|
| 3 | 3 | 较低 | 最高 |
| 5 | 5 | 中等 | 高 |
| 10 | 10 | 较高 | 中等 |
# 推荐配置
maxmemory 2gb
maxmemory-policy allkeys-lru
maxmemory-samples 5# 推荐配置
# 推荐配置
maxmemory 2gb
maxmemory-policy allkeys-lru
maxmemory-samples 5maxmemory 2gb
# 推荐配置
maxmemory 2gb
maxmemory-policy allkeys-lru
maxmemory-samples 5maxmemory-policy allkeys-lru
# 推荐配置
maxmemory 2gb
maxmemory-policy allkeys-lru
maxmemory-samples 5maxmemory-samples 5
4.3 LFU 算法实现
Redis 4.0 引入了 LFU(Least Frequently Used)算法,基于访问频率淘汰数据:
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj;// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj;typedef struct redisObject {
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj; unsigned type:4;
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj; unsigned encoding:4;
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj; unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj; int refcount;
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj; void *ptr;
#// server.h (Redis 7.2.0) - redisObject 中的 lru 字段复用
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:24; /* LRU: 24位时间戳<br/>LFU: 高16位=访问时间,低8位=访问计数 */
int refcount;
void *ptr;
} robj;} robj;
LFU 的实现机制:
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}// object.c (Redis 7.2.0) - LFU 计数更新
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}void objectLFUStep(robj *obj) {
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} /* 1. 获取当前计数 */
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} unsigned long counter = LFUDecrAndReturn(obj);
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} /* 2. 概率性增加计数(防止热点数据垄断) */
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} if (counter < 255) {
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} double r = (double)rand() / RAND_MAX;
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} double factor = 1.0 / (counter + 1);
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} if (r < factor) {
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} counter++;
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} }
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} }
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} /* 3. 更新 lru 字段 */
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}}
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}// LFU 计数衰减
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}unsigned long LFUDecrAndReturn(robj *obj) {
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} unsigned long lru = obj->lru;
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} unsigned long counter = lru & 255; /* 低 8 位 */
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} /* 计数衰减:每隔一分钟,计数减半 */
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} unsigned long period = LFUTimeElapsed(lru) / 60;
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} if (period) {
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} if (period > 100) period = 100; /* 最多衰减到 0 */
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} counter = counter >> period;
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} }
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
} return counter;
#// object.c (Redis 7.2.0) - LFU 计数更新
void objectLFUStep(robj *obj) {
/* 1. 获取当前计数 */
unsigned long counter = LFUDecrAndReturn(obj);
/* 2. 概率性增加计数(防止热点数据垄断) */
if (counter < 255) {
double r = (double)rand() / RAND_MAX;
double factor = 1.0 / (counter + 1);
if (r < factor) {
counter++;
}
}
/* 3. 更新 lru 字段 */
obj->lru = (LFUGetTimeInMinutes() << 8) | counter;
}
// LFU 计数衰减
unsigned long LFUDecrAndReturn(robj *obj) {
unsigned long lru = obj->lru;
unsigned long counter = lru & 255; /* 低 8 位 */
/* 计数衰减:每隔一分钟,计数减半 */
unsigned long period = LFUTimeElapsed(lru) / 60;
if (period) {
if (period > 100) period = 100; /* 最多衰减到 0 */
counter = counter >> period;
}
return counter;
}}
LFU vs LRU 对比:
| 特性 | LRU | LFU |
|---|---|---|
| 淘汰依据 | 最近访问时间 | 访问频率 |
| 适用场景 | 临时数据 | 热点数据 |
| 优点 | 实现简单,性能好 | 更精准地保留热点 |
| 缺点 | 偶发访问可能误判 | 需要预热期 |
| Redis 版本 | 所有版本 | 4.0+ |
4.4 淘汰算法选择建议
| 场景 | 推荐策略 | 原因 |
|---|---|---|
| 通用缓存 | allkeys-lru |
兼顾性能和效果 |
| 热点数据 | allkeys-lfu |
保留高频访问数据 |
| 会话数据 | volatile-ttl |
优先淘汰即将过期的 |
| 禁止淘汰 | noeviction |
缓存预热完成后使用 |
| 只淘汰缓存 | volatile-lru |
持久化数据不淘汰 |
五、内存淘汰流程
5.1 完整流程图
sequenceDiagram
participant Client as 客户端
participant Redis as Redis 服务器
Client->>Redis: SET key value
Redis->>Redis: 检查内存使用
alt 内存充足
Redis-->>Client: OK
else 内存不足
Redis->>Redis: 触发内存淘汰
Redis->>Redis: 根据 policy 选择淘汰算法
alt LRU
Redis->>Redis: 采样 N 个 key<br/>找出 LRU 最小的
else LFU
Redis->>Redis: 采样 N 个 key<br/>找出 LFU 最低的
else TTL
Redis->>Redis: 找出 TTL 最小的
else Random
Redis->>Redis: 随机选择 key
end
Redis->>Redis: 删除选中的 key
Redis->>Redis: 释放内存
alt 仍需淘汰
Redis->>Redis: 继续淘汰
else 内存足够
Redis->>Redis: 执行写入
Redis-->>Client: OK
end
end
5.2 源码实现
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}// evict.c (Redis 7.2.0) - 内存淘汰入口
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}int freeMemoryIfNeeded(void) {
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 1. 检查是否启用淘汰 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} return C_ERR; /* 不淘汰,返回错误 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} }
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 2. 计算需要释放的内存 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} size_t mem_used = zmalloc_used_memory();
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} size_t mem_tofree = mem_used - server.maxmemory;
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 3. 循环淘汰直到内存足够 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} while (mem_used > server.maxmemory) {
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 根据策略选择淘汰算法 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} int keys_freed = 0;
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 从所有 key 中淘汰 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} keys_freed = evictionPoolPopulate(
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} server.db[0].dict,
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} server.db[0].dict,
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} evictionPool
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} );
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} } else {
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 从设置了过期时间的 key 中淘汰 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} keys_freed = evictionPoolPopulate(
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} server.db[0].expires,
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} server.db[0].dict,
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} evictionPool
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} );
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} }
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 删除 key 并释放内存 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} if (keys_freed > 0) {
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} mem_used = zmalloc_used_memory();
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} } else {
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} /* 没有 key 可淘汰 */
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} break;
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} }
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} }
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
} return C_OK;
#// evict.c (Redis 7.2.0) - 内存淘汰入口
int freeMemoryIfNeeded(void) {
/* 1. 检查是否启用淘汰 */
if (server.maxmemory_policy == MAXMEMORY_NO_EVICTION) {
return C_ERR; /* 不淘汰,返回错误 */
}
/* 2. 计算需要释放的内存 */
size_t mem_used = zmalloc_used_memory();
size_t mem_tofree = mem_used - server.maxmemory;
/* 3. 循环淘汰直到内存足够 */
while (mem_used > server.maxmemory) {
/* 根据策略选择淘汰算法 */
int keys_freed = 0;
if (server.maxmemory_policy & MAXMEMORY_FLAG_ALLKEYS) {
/* 从所有 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].dict,
server.db[0].dict,
evictionPool
);
} else {
/* 从设置了过期时间的 key 中淘汰 */
keys_freed = evictionPoolPopulate(
server.db[0].expires,
server.db[0].dict,
evictionPool
);
}
/* 删除 key 并释放内存 */
if (keys_freed > 0) {
mem_used = zmalloc_used_memory();
} else {
/* 没有 key 可淘汰 */
break;
}
}
return C_OK;
}}
六、实战与调优
6.1 监控指标
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000# 1. 查看内存使用情况
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000redis-cli INFO memory | grep used_memory_human
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000used_memory_human: 2.5G
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000# 2. 查看淘汰统计
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000redis-cli INFO stats | grep evicted_keys
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000evicted_keys: 12345
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000# 3. 查看过期删除统计
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000redis-cli INFO stats | grep expired_keys
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000expired_keys: 67890
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000# 4. 查看 key 数量
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000redis-cli DBSIZE
# 1. 查看内存使用情况
redis-cli INFO memory | grep used_memory_human
used_memory_human: 2.5G
# 2. 查看淘汰统计
redis-cli INFO stats | grep evicted_keys
evicted_keys: 12345
# 3. 查看过期删除统计
redis-cli INFO stats | grep expired_keys
expired_keys: 67890
# 4. 查看 key 数量
redis-cli DBSIZE
(integer) 500000(integer) 500000
6.2 性能测试
python
# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()import redis`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()import time`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()import random`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()import string`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()r = redis.Redis(host='localhost', port=6379, db=0)`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()def generate_random_key(length=10):`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() return ''.join(random.choices(string.ascii_letters + string.digits, k=length))`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()# 测试 LRU 淘汰`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()def test_lru_eviction():`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print("=== LRU 淘汰测试 ===")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 1. 设置内存上限和淘汰策略`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.config_set('maxmemory', '100mb')`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.config_set('maxmemory-policy', 'allkeys-lru')`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.config_set('maxmemory-samples', '5')`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 2. 写入数据(超过内存限制)`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() for i in range(200000):`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() key = f"lru_key_{i}"`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() value = "x" * 1024 # 1KB`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.setex(key, 3600, value) # 设置 1 小时过期`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() if i % 10000 == 0:`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() evicted = r.info('stats')['evicted_keys']`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print(f"已写入 {i} 个 key,淘汰 {evicted} 个")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print("LRU 淘汰测试完成")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()# 测试 LFU 淘汰`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()def test_lfu_eviction():`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print("\n=== LFU 淘汰测试 ===")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 1. 设置淘汰策略为 LFU`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.config_set('maxmemory-policy', 'allkeys-lfu')`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 2. 写入数据并制造热点`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() hot_keys = [f"lfu_hot_{i}" for i in range(100)]`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() cold_keys = [f"lfu_cold_{i}" for i in range(10000)]`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 写入冷数据`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() for key in cold_keys:`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.setex(key, 3600, "x" * 1024)`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 频繁访问热数据(增加 LFU 计数)`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() for _ in range(100):`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() for key in hot_keys:`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.get(key)`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 写入更多数据触发淘汰`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() for i in range(10000, 20000):`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() key = f"lfu_cold_{i}"`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.setex(key, 3600, "x" * 1024)`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 检查热数据是否保留`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() hot_survived = sum(1 for key in hot_keys if r.exists(key))`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print(f"热数据保留率: {hot_survived}%")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print("LFU 淘汰测试完成")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()# 测试过期策略`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()def test_expire_strategy():`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print("\n=== 过期策略测试 ===")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 1. 设置过期时间`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.setex("expire_test_1", 10, "value1")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.setex("expire_test_2", 20, "value2")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 2. 检查 TTL`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 3. 等待过期`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() time.sleep(11)`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() # 4. 移除过期时间`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() r.persist("expire_test_2")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() `
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() print("过期策略测试完成")`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy()if __name__ == "__main__":`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() test_lru_eviction()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() test_lfu_eviction()`
`# 测试 LRU 淘汰
def test_lru_eviction():
print("=== LRU 淘汰测试 ===")
# 1. 设置内存上限和淘汰策略
r.config_set('maxmemory', '100mb')
r.config_set('maxmemory-policy', 'allkeys-lru')
r.config_set('maxmemory-samples', '5')
# 2. 写入数据(超过内存限制)
for i in range(200000):
key = f"lru_key_{i}"
value = "x" * 1024 # 1KB
r.setex(key, 3600, value) # 设置 1 小时过期
if i % 10000 == 0:
evicted = r.info('stats')['evicted_keys']
print(f"已写入 {i} 个 key,淘汰 {evicted} 个")
print("LRU 淘汰测试完成")
# 测试 LFU 淘汰
def test_lfu_eviction():
print("\n=== LFU 淘汰测试 ===")
# 1. 设置淘汰策略为 LFU
r.config_set('maxmemory-policy', 'allkeys-lfu')
# 2. 写入数据并制造热点
hot_keys = [f"lfu_hot_{i}" for i in range(100)]
cold_keys = [f"lfu_cold_{i}" for i in range(10000)]
# 写入冷数据
for key in cold_keys:
r.setex(key, 3600, "x" * 1024)
# 频繁访问热数据(增加 LFU 计数)
for _ in range(100):
for key in hot_keys:
r.get(key)
# 写入更多数据触发淘汰
for i in range(10000, 20000):
key = f"lfu_cold_{i}"
r.setex(key, 3600, "x" * 1024)
# 检查热数据是否保留
hot_survived = sum(1 for key in hot_keys if r.exists(key))
print(f"热数据保留率: {hot_survived}%")
print("LFU 淘汰测试完成")
# 测试过期策略
def test_expire_strategy():
print("\n=== 过期策略测试 ===")
# 1. 设置过期时间
r.setex("expire_test_1", 10, "value1")
r.setex("expire_test_2", 20, "value2")
# 2. 检查 TTL
print(f"expire_test_1 TTL: {r.ttl('expire_test_1')}s")
print(f"expire_test_2 TTL: {r.ttl('expire_test_2')}s")
# 3. 等待过期
time.sleep(11)
print(f"expire_test_1 是否存在: {r.exists('expire_test_1')}")
print(f"expire_test_2 是否存在: {r.exists('expire_test_2')}")
# 4. 移除过期时间
r.persist("expire_test_2")
print(f"移除过期后 TTL: {r.ttl('expire_test_2')}")
print("过期策略测试完成")
if __name__ == "__main__":
test_lru_eviction()
test_lfu_eviction()
test_expire_strategy() test_expire_strategy()
6.3 生产环境配置
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化# redis.conf 生产环境配置
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化# === 内存配置 ===
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化maxmemory-policy allkeys-lru # 通用缓存场景
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化maxmemory-samples 5 # LRU 采样数量
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化# === 过期策略配置 ===
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化hz 10 # 定期删除频率(10 = 100ms 一次)
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化# === 监控配置 ===
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化slowlog-max-len 128 # 慢查询日志长度
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化# === 持久化配置 ===
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化save 900 1 # 900 秒内至少 1 个 key 变化
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化save 300 10 # 300 秒内至少 10 个 key 变化
# redis.conf 生产环境配置
# === 内存配置 ===
maxmemory 4gb # 根据实际情况设置(建议为物理内存的 50-70%)
maxmemory-policy allkeys-lru # 通用缓存场景
maxmemory-samples 5 # LRU 采样数量
# === 过期策略配置 ===
hz 10 # 定期删除频率(10 = 100ms 一次)
active-expire-cycle-lookups-per-loop 20 # 每次循环抽查数量
# === 监控配置 ===
latency-monitor-threshold 100 # 延迟监控阈值(毫秒)
slowlog-log-slower-than 10000 # 慢查询阈值(微秒)
slowlog-max-len 128 # 慢查询日志长度
# === 持久化配置 ===
save 900 1 # 900 秒内至少 1 个 key 变化
save 300 10 # 300 秒内至少 10 个 key 变化
save 60 10000 # 60 秒内至少 10000 个 key 变化save 60 10000 # 60 秒内至少 10000 个 key 变化
七、常见问题与排查
7.1 过期键未及时删除
问题: 设置了过期时间,但内存未释放。
原因: 1. 定期删除未抽查到该 key 2. 惰性删除未被访问
解决:
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DEL# 1. 手动触发删除
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DELredis-cli DEL key
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DEL
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DEL# 2. 调整定期删除参数
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DELredis-cli CONFIG SET hz 20
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DEL
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DEL# 3. 使用 SCAN 扫描并删除
# 1. 手动触发删除
redis-cli DEL key
# 2. 调整定期删除参数
redis-cli CONFIG SET hz 20
# 3. 使用 SCAN 扫描并删除
redis-cli --scan --pattern "prefix:*" | xargs redis-cli DELredis-cli --scan --pattern "prefix:*" | xargs redis-cli DEL
7.2 淘汰策略导致数据丢失
问题: 重要数据被淘汰。
解决:
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noeviction# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noevictionredis-cli CONFIG SET maxmemory-policy volatile-lru
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noeviction
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noeviction# 2. 重要数据不设置过期时间
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noevictionredis-cli SET important_data "value"
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noeviction
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noeviction# 3. 使用 noeviction 策略(配合错误处理)
# 1. 使用 volatile-* 策略,只淘汰有过期时间的 key
redis-cli CONFIG SET maxmemory-policy volatile-lru
# 2. 重要数据不设置过期时间
redis-cli SET important_data "value"
# 3. 使用 noeviction 策略(配合错误处理)
redis-cli CONFIG SET maxmemory-policy noevictionredis-cli CONFIG SET maxmemory-policy noeviction
7.3 内存碎片率高
问题: mem_fragmentation_ratio > 1.5
解决:
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yes# 1. 执行内存碎片整理(Redis 4.0+)
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yesredis-cli MEMORY PURGE
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yes
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yes# 2. 重启 Redis(释放内存碎片)
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yesredis-cli SHUTDOWN NOSAVE
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yesredis-server /etc/redis/redis.conf
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yes
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yes# 3. 调整内存分配器
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yes# 在 redis.conf 中设置:
# 1. 执行内存碎片整理(Redis 4.0+)
redis-cli MEMORY PURGE
# 2. 重启 Redis(释放内存碎片)
redis-cli SHUTDOWN NOSAVE
redis-server /etc/redis/redis.conf
# 3. 调整内存分配器
# 在 redis.conf 中设置:
# jemalloc-bg-thread yes# jemalloc-bg-thread yes
八、总结
Redis 的过期策略和内存淘汰机制是其高性能和高可用的重要保障:
核心要点:
- 过期策略:惰性删除 + 定期删除,平衡 CPU 和内存
- 过期字典:独立维护过期时间,O(1) 时间复杂度查询
- LRU 算法:近似 LRU,随机采样 + 时间戳比较
- LFU 算法:基于访问频率,计数衰减 + 概率增长
- 淘汰策略:9 种策略,根据场景选择
选择建议:
| 场景 | 过期策略 | 淘汰策略 |
|---|---|---|
| 通用缓存 | 设置 TTL | allkeys-lru |
| 热点数据 | 设置 TTL | allkeys-lfu |
| 会话数据 | 设置 TTL | volatile-ttl |
| 持久化数据 | 不设置 TTL | noeviction |
调优原则:
- 内存压力大:增大
hz和maxmemory-samples - CPU 敏感:降低
hz,使用noeviction - 热点数据:使用
lfu策略 - 避免数据丢失:使用
volatile-*策略
参考资料
版权声明: 本文为原创技术文章,转载请注明出处。
作者: [你的昵称] 发布时间: 2026-04-01 Redis 版本: 7.2.0