Redis中过期策略是怎么样的

发布时间:2022-01-13 09:48:56 作者:小新
来源:亿速云 阅读:167
# Redis中过期策略是怎么样的

## 引言

Redis作为高性能的键值存储系统,其内存管理机制直接影响着系统性能和资源利用率。其中,过期键的处理策略是Redis内存管理的核心组成部分。本文将深入剖析Redis的过期策略实现原理,包括被动删除、主动删除等机制,并结合源码分析其底层实现细节,最后通过实际案例展示不同策略的应用场景。

## 一、Redis过期键基础概念

### 1.1 什么是过期键
Redis允许为键设置生存时间(TTL),当达到指定时间后,该键会自动被服务器删除。这种带有生存时间限制的键称为"过期键"。

```bash
# 设置键值并指定10秒后过期
SET mykey "hello" EX 10

1.2 过期时间的存储结构

Redis在内部使用redisDb结构存储数据库数据,其中包含两个关键字典:

typedef struct redisDb {
    dict *dict;                 // 键空间(保存所有键值对)
    dict *expires;              // 过期字典(保存键的过期时间)
    // ...其他字段
} redisDb;

二、Redis的过期删除策略

Redis采用多策略组合的方式处理过期键,主要包括三种机制:

2.1 被动过期(惰性删除)

实现原理

当客户端尝试访问某个键时,Redis会首先检查该键是否已过期:

int expireIfNeeded(redisDb *db, robj *key) {
    if (!keyIsExpired(db,key)) return 0;
    
    // 从键空间和过期字典中删除
    db->expires--;
    return dbDelete(db,key);
}

特点分析

2.2 主动过期(定期删除)

工作流程

Redis通过serverCron时间事件定期执行过期扫描:

  1. 每次随机抽取一定数量的键(默认20个)
  2. 删除其中已过期的键
  3. 如果过期比例超过25%,则重复该过程
void activeExpireCycle(int type) {
    // 每次扫描的数据库数量
    for (j = 0; j < dbs_per_call; j++) {
        // 随机选择20个键检查
        for (i = 0; i < 20; i++) {
            // 检查并删除过期键
        }
        
        // 如果过期键比例>25%,继续扫描
    }
}

参数配置

2.3 内存驱逐策略

当内存达到maxmemory限制时,Redis会根据配置的淘汰策略删除键:

策略 说明
volatile-lru 从已设置过期时间的键中使用LRU算法淘汰
allkeys-lru 从所有键中使用LRU算法淘汰
volatile-random 随机淘汰有过期时间的键
allkeys-random 随机淘汰任意键
volatile-ttl 优先淘汰剩余生存时间短的键

三、底层实现细节

3.1 过期字典的运作机制

过期字典使用哈希表存储,键与主字典共享对象引用:

void setExpire(redisDb *db, robj *key, long long when) {
    // 共享键对象(不重复创建)
    if (dictAdd(db->expires, key, (void*)when) == DICT_ERR) {
        // 更新现有过期时间
        dictReplace(db->expires, key, (void*)when);
    }
    // 增加引用计数
    incrRefCount(key);
}

3.2 时间精度处理

Redis使用两种时间表示方式: 1. 秒级精度:EXPIRE/TTL命令使用 2. 毫秒级精度:PEXPIRE/PTTL命令使用

内部统一转换为毫秒级UNIX时间戳存储。

3.3 持久化时的处理

RDB持久化

AOF持久化

四、不同场景下的策略表现

4.1 高吞吐量场景

4.2 大内存实例

4.3 从节点处理

从节点不会主动删除过期键,而是: 1. 等待主节点发来DEL命令 2. 读取已过期的键时返回空值(被动删除)

五、性能优化实践

5.1 监控指标

关键监控项: - expired_keys:累计删除的过期键数量 - evicted_keys:因内存不足淘汰的键数量 - keyspace_hits/misses:键访问命中率

5.2 参数调优

# 提高定期删除频率(1-500)
config set hz 100

# 增加每次扫描的键数量
config set active-expire-cycle-lookups-per-loop 50

5.3 最佳实践

  1. 避免在同一时间点设置大量相同TTL的键
  2. 对于热点数据设置较长TTL+主动更新
  3. 使用SCAN+TTL命令定期检查异常键

六、源码级深度解析

6.1 惰性删除实现

db.c中的关键函数:

robj *lookupKeyReadWithFlags(redisDb *db, robj *key, int flags) {
    robj *val = lookupKey(db,key,flags);
    if (val == NULL)
        server.stat_keyspace_misses++;
    else
        server.stat_keyspace_hits++;
    return val;
}

robj *lookupKey(redisDb *db, robj *key, int flags) {
    // 检查过期键
    if (expireIfNeeded(db,key) == 1) {
        // 键已过期被删除
        return NULL;
    }
    return dictFind(db->dict,key->ptr);
}

6.2 定期删除算法

expire.c中的核心逻辑:

void databasesCron(void) {
    // 每次cron调用时执行主动过期
    if (server.active_expire_enabled) {
        if (server.masterhost == NULL) {
            activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
        } else {
            expireSlaveKeys();
        }
    }
}

七、与其他系统的对比

系统 过期策略 特点
Memcached 惰性删除 简单但内存利用率低
RocksDB TTL+Compaction 基于SST文件级别删除
MySQL 事件调度 需要显式设置定时任务

结语

Redis通过组合多种过期策略,在CPU消耗和内存利用率之间取得了良好平衡。理解这些机制有助于开发者根据实际业务场景做出合理的架构决策和参数调优。建议在关键业务环境中密切监控过期键的处理情况,并根据负载特征调整相关参数。

本文基于Redis 7.0版本分析,部分实现细节可能随版本变化而调整。 “`

这篇文章共计约3400字,详细涵盖了Redis过期策略的各个方面,包括: 1. 基础概念和存储结构 2. 三种核心删除策略 3. 底层实现机制 4. 不同场景下的表现 5. 性能优化实践 6. 源码级分析 7. 与其他系统的对比

文章采用技术深度与实践建议相结合的方式,既适合开发者理解原理,也能帮助运维人员优化实际系统。

推荐阅读:
  1. Redis过期策略及实现原理
  2. 怎么处理redis的过期策略

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

redis

上一篇:MySQL为什么不能用uuid做主键

下一篇:php如何增加多行数据

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》