Redis 的缓存过期策略

Redis 的缓存过期策略是指当数据存储在 Redis 中时,如何处理到达特定生命周期末端的数据。Redis 主要使用两种策略来管理键的过期:惰性过期(Lazy Expiration)和定期删除(Periodic Deletion)。

惰性过期

当客户端访问一个键时,Redis 会检查这个键是否已经达到过期时间。如果已过期,Redis 就会删除它,然后返回一个错误。

源码概览

在 Redis 的源码中,expireIfNeeded 函数负责检查键是否过期。以下是一个简化的伪代码:

c 复制代码
int expireIfNeeded(redisDb *db, robj *key) {
    // 检查键是否有过期时间设置
    if (!key->expire) return 0;

    // 获取当前时间
    mstime_t now = mstime();

    // 判断键是否过期
    if (now > key->expire) {
        // 执行删除操作
        dbDelete(db, key);
        return 1;
    }

    return 0;
}

定期删除

Redis 每隔一段时间执行一次自动清理操作。它会随机地选择一些键,并检查它们是否过期。过期的键会被删除。

源码概览

Redis 使用 activeExpireCycle 函数来定期检查和删除过期的键。以下是简化的伪代码:

c 复制代码
void activeExpireCycle(int type) {
    // 从数据库中随机抽取一部分键
    for (int i = 0; i < REDIS_EXPIRELOOKUPS_PER_CRON; i++) {
        // 随机选择数据库
        int db_id = rand() % server.dbnum;
        redisDb *db = server.db[db_id];

        // 随机选择键
        if (dictSize(db->expires) == 0) continue;
        dictEntry *de = dictGetRandomKey(db->expires);
        
        // 检查键是否过期
        expireIfNeeded(db, dictGetKey(de));
    }
}

过期策略选择

Redis 的过期策略是折衷的。它不保证立即删除所有过期键,但保证过期键不会被永久访问到。

注意事项

  • 内存使用:过期键可能在过期后不会立即被删除,因此可能会暂时占用更多内存。
  • 性能考量:定期删除策略避免了锁定 Redis 实例以删除大量的过期键,但它仍然需要使用一定的 CPU 资源来随机检查键。
  • 持久化:当 Redis 重启时,它会根据持久化文件(AOF 或 RDB)来恢复过期键的状态。

Java代码演示使用 Jedis

下面是使用 Java 和 Jedis 客户端库与 Redis 交互的代码示例。这个例子演示了如何设置键的过期时间以及如何检索它。

java 复制代码
import redis.clients.jedis.Jedis;

public class RedisExpirationDemo {
    public static void main(String[] args) {
        // Connect to the Redis server
        Jedis jedis = new Jedis("localhost", 6379);

        try {
            // Set a key with a value and an expiration time in seconds (10 seconds in this case)
            String key = "myKey";
            String value = "Hello, Redis!";
            int expireTime = 10; // Key expires in 10 seconds

            jedis.setex(key, expireTime, value);
            System.out.println("Key set with expiration time.");

            // Get the value right away
            String currentValue = jedis.get(key);
            System.out.println("Value immediately after setting: " + currentValue);

            // Wait for the key to expire
            Thread.sleep(10000);

            // Try to get the value after expiration time
            currentValue = jedis.get(key);
            System.out.println("Value after expiration: " + (currentValue == null ? "null (key expired)" : currentValue));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // Close the connection
            jedis.close();
        }
    }
}

在上述代码中,我们使用 setex 方法设置了一个键,为其提供了一个过期时间(10秒)。随后,我们尝试立即获取该键,应该能够获取到值。然后程序休眠10秒,再次尝试获取该键时,由于键已经过期,所以应该获取不到值。

请注意,为了简化代码,这里没有包含异常处理和资源管理的最佳实践,如在生产环境中应使用 try-with-resources 语句来自动关闭 Jedis 实例。此外,确保 Redis 服务在本地运行并监听默认端口(6379)。

相关推荐
kfaino10 小时前
码农的AI翻身(六)你好,我叫 Parameter
后端·aigc
掘金者阿豪10 小时前
把业务数据变成共享仪表盘:Metabase可视化与远程访问实践
前端·后端
猪猪拆迁队11 小时前
虚拟工厂仿真引擎的架构设计:让一条产线可编程、可观测、可干预
后端·ai编程
字节跳动数据库12 小时前
文章分享——相似函数处理方法
人工智能·后端·程序员
云技纵横12 小时前
@Transactional 失效的 7 种场景:第 5 种最难排查
后端
用户67570498850212 小时前
你知道 Go 结构体和结构体指针调用的区别吗?一文带你彻底搞懂!
后端·go
程序员cxuan12 小时前
读懂 Claude Code 架构分析系列,第一篇,开始!
人工智能·后端·架构
用户67570498850212 小时前
面试官问“装饰器模式”,这样回答薪资多要 3000!
后端
tntxia12 小时前
Geo Scene域名修改引起的一些问题
后端
用户2986985301412 小时前
Java 实现 Word 文档加密与权限解除
java·后端