Redis 过期策略与内存淘汰算法全解析

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;
}}

调用时机:

  • GETSETDEL 等所有访问 key 的命令
  • KEYSSCAN 等遍历命令
  • 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 的过期策略和内存淘汰机制是其高性能和高可用的重要保障:

核心要点:

  1. 过期策略:惰性删除 + 定期删除,平衡 CPU 和内存
  2. 过期字典:独立维护过期时间,O(1) 时间复杂度查询
  3. LRU 算法:近似 LRU,随机采样 + 时间戳比较
  4. LFU 算法:基于访问频率,计数衰减 + 概率增长
  5. 淘汰策略:9 种策略,根据场景选择

选择建议:

场景 过期策略 淘汰策略
通用缓存 设置 TTL allkeys-lru
热点数据 设置 TTL allkeys-lfu
会话数据 设置 TTL volatile-ttl
持久化数据 不设置 TTL noeviction

调优原则:

  • 内存压力大:增大 hzmaxmemory-samples
  • CPU 敏感:降低 hz,使用 noeviction
  • 热点数据:使用 lfu 策略
  • 避免数据丢失:使用 volatile-* 策略

参考资料


版权声明: 本文为原创技术文章,转载请注明出处。

作者: [你的昵称] 发布时间: 2026-04-01 Redis 版本: 7.2.0

相关推荐
s1mple“”2 小时前
大厂Java面试实录:从Spring Boot到AI技术的在线教育场景深度解析
spring boot·redis·微服务·kafka·向量数据库·java面试·ai技术
IT 行者2 小时前
CentOS 下源码编译安装完整版 Redis 8.0 指南(附 Rust 工具链详解)
redis·rust·centos
2601_949814692 小时前
ubuntu 安装 Redis
linux·redis·ubuntu
流星雨在线3 小时前
Node.js + Express 项目完整搭建手册(Redis + MySQL + 常用中间件)
redis·node.js·express
一直都在57217 小时前
Redis (一)
数据库·redis·缓存
秦jh_18 小时前
【Redis】客户端使用
数据库·redis·缓存
我真会写代码18 小时前
Redis核心特性详解:事务、发布订阅与数据删除淘汰策略
java·数据库·redis
IT 行者18 小时前
LangChain4j 集成 Redis 向量存储:我踩过的坑和选型建议
java·人工智能·redis·后端
wenlonglanying19 小时前
nginx 代理 redis
运维·redis·nginx