redis的超时删除策略

 

这个问题有三种可能的答案,它们分别代表了三种不同的删除策略:

·定时删除:在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作。

·惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。

·定期删除:每隔一段时间,程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。

在这三种策略中,第一种和第三种为主动删除策略,而第二种则为被动删除策略。

 定时删除

定时删除策略对内存是最友好的:通过使用定时器,定时删除策略可以保证过期键会尽可能快地被删除,并释放过期键所占用的内存。

另一方面,定时删除策略的缺点是,它对CPU时间是最不友好的:在过期键比较多的情况下,删除过期键这一行为可能会占用相当一部分CPU时间,在内存不紧张但是CPU时间非常紧张的情况下,将CPU时间用在删除和当前任务无关的过期键上,无疑会对服务器的响应时间和吞吐量造成影响。

例如,如果正有大量的命令请求在等待服务器处理,并且服务器当前不缺少内存,那么服务器应该优先将CPU时间用在处理客户端的命令请求上面,而不是用在删除过期键上面。

除此之外,创建一个定时器需要用到Redis服务器中的时间事件,而当前时间事件的实现方式——无序链表,查找一个事件的时间复杂度为O(N)——并不能高效地处理大量时间事件。

因此,要让服务器创建大量的定时器,从而实现定时删除策略,在现阶段来说并不现实。

 惰性删除

惰性删除策略对CPU时间来说是最友好的:程序只会在取出键时才对键进行过期检查,这可以保证删除过期键的操作只会在非做不可的情况下进行,并且删除的目标仅限于当前处理的键,这个策略不会在删除其他无关的过期键上花费任何CPU时间。

惰性删除策略的缺点是,它对内存是最不友好的:如果一个键已经过期,而这个键又仍然保留在数据库中,那么只要这个过期键不被删除,它所占用的内存就不会释放。

在使用惰性删除策略时,如果数据库中有非常多的过期键,而这些过期键又恰好没有被访问到的话,那么它们也许永远也不会被删除(除非用户手动执行FLUSHDB),我们甚至可以将这种情况看作是一种内存泄漏——无用的垃圾数据占用了大量的内存,而服务器却不会自己去释放它们,这对于运行状态非常依赖于内存的Redis服务器来说,肯定不是一个好消息。

举个例子,对于一些和时间有关的数据,比如日志(log),在某个时间点之后,对它们的访问就会大大减少,甚至不再访问,如果这类过期数据大量地积压在数据库中,用户以为服务器已经自动将它们删除了,但实际上这些键仍然存在,而且键所占用的内存也没有释放,那么造成的后果肯定是非常严重的。

定期删除

从上面对定时删除和惰性删除的讨论来看,这两种删除方式在单一使用时都有明显的缺陷:

·定时删除占用太多CPU时间,影响服务器的响应时间和吞吐量。

·惰性删除浪费太多内存,有内存泄漏的危险。

定期删除策略是前两种策略的一种整合和折中:

·定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。

·除此之外,通过定期删除过期键,定期删除策略有效地减少了因为过期键而带来的内存浪费。

定期删除策略的难点是确定删除操作执行的时长和频率:

·如果删除操作执行得太频繁,或者执行的时间太长,定期删除策略就会退化成定时删除策略,以至于将CPU时间过多地消耗在删除过期键上面。

·如果删除操作执行得太少,或者执行的时间太短,定期删除策略又会和惰性删除策略一样,出现浪费内存的情况。

因此,如果采用定期删除策略的话,服务器必须根据情况,合理地设置删除操作的执行时长和执行频率。

 

 

 

过期键的定期删除策略由redis.c/activeExpireCycle函数实现,每当Redis的服务器周期性操作redis.c/serverCron函数执行时,activeExpireCycle函数就会被调用,它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。

整个过程可以用伪代码描述如下:


# 
默认每次检查的数据库数量
DEFAULT_DB_NUMBERS = 16
# 
默认每个数据库检查的键数量
DEFAULT_KEY_NUMBERS = 20
# 
全局变量,记录检查进度
current_db = 0
def activeExpireCycle():
    # 
初始化要检查的数据库数量
    # 
如果服务器的数据库数量比 DEFAULT_DB_NUMBERS 
要小
    # 
那么以服务器的数据库数量为准
    if server.dbnum < DEFAULT_DB_NUMBERS:
        db_numbers = server.dbnum
    else:
        db_numbers = DEFAULT_DB_NUMBERS
    # 
遍历各个数据库
    for i in range(db_numbers):
        # 
如果current_db
的值等于服务器的数据库数量
        # 
这表示检查程序已经遍历了服务器的所有数据库一次
        # 
current_db
重置为0
,开始新的一轮遍历
        if current_db == server.dbnum:
            current_db = 0
        # 
获取当前要处理的数据库
        redisDb = server.db[current_db]
        # 
将数据库索引增1
,指向下一个要处理的数据库
        current_db += 1
        # 
检查数据库键
        for j in range(DEFAULT_KEY_NUMBERS):
            # 
如果数据库中没有一个键带有过期时间,那么跳过这个数据库
            if redisDb.expires.size() == 0: break
            # 
随机获取一个带有过期时间的键
            key_with_ttl = redisDb.expires.get_random_key()
            # 
检查键是否过期,如果过期就删除它
            if is_expired(key_with_ttl):
                delete_key(key_with_ttl)
            # 
已达到时间上限,停止处理
            if reach_time_limit(): return

activeExpireCycle函数的工作模式可以总结如下:

·函数每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中的过期键。

·全局变量current_db会记录当前activeExpireCycle函数检查的进度,并在下一次activeExpireCycle函数调用时,接着上一次的进度进行处理。比如说,如果当前activeExpireCycle函数在遍历10号数据库时返回了,那么下次activeExpireCycle函数执行时,将从11号数据库开始查找并删除过期键。

·随着activeExpireCycle函数的不断执行,服务器中的所有数据库都会被检查一遍,这时函数将current_db变量重置为0,然后再次开始新一轮的检查工作。

转载于:https://www.cnblogs.com/hexie/p/5011299.html

<think>我们参考了上述引用的相关内容,特别是关于Redis过期键删除策略的描述。Redis使用两种策略:惰性删除和定期删除。惰性删除:当客户端访问某个键时,Redis会检查该键是否过期,如果过期则删除。定期删除Redis会周期性地随机测试一些设置了过期时间的键,并删除其中过期的键。关于配置,Redis并没有提供直接配置这两种策略的参数。但是,我们可以通过配置定期删除的执行频率和每次执行的时间限制来调整。具体来说,在redis.conf配置文件中,有两个参数与定期删除相关:1.`hz`:这个参数定义了Redis后台任务(包括定期删除)的执行频率,默认为10,即每秒执行10次。可以调整,但通常不建议设置太高。2.定期删除的具体执行方式由Redis内部算法控制,它会根据服务器繁忙程度调整每次扫描的时长和范围,并尽量不影响正常请求的处理。另外,需要注意的是,定期删除有两种模式:快速模式(fast)和慢速模式(slow)。快速模式执行时间较短,但扫描的键较少;慢速模式执行时间较长,扫描的键较多。Redis会根据服务器状态自动切换。由于惰性删除是每次访问时触发的,所以没有相关配置参数。因此,配置的主要关注点在定期删除的`hz`参数。在redis.conf中,可以这样配置:```hz10#默认值,可以调整,范围在1到500之间```但是,调整这个参数需要谨慎,因为除了过期键的删除,它还会影响其他后台任务(如rehash、关闭超时的连接等)。增加`hz`值会让Redis更频繁地执行后台任务,从而可能更快地删除过期键,但也会增加CPU的使用。总结配置方法:1.打开redis.conf文件2.找到`hz`参数,根据需求调整(一般保持默认即可)3.重启Redis服务使配置生效(或者使用`CONFIGSET`命令动态设置,但要注意这种方式重启后失效)注意:Redis的过期键删除策略结合了惰性和定期删除,所以即使定期删除不够及时,还有惰性删除作为保障。另外,引用[4]中提到定期删除会控制每次执行的时长、遍历的db数量、采样键数量等,这些是Redis内部算法控制的,用户无法直接配置。因此,用户可配置的只有`hz`参数,它间接影响了定期删除的频率。最后提醒:在实际使用中,如果发现大量过期键堆积,可以适当调高`hz`值,但要注意监控CPU使用情况。§§相关问题§§1.Redis的惰性删除策略在什么情况下会失效?2.如何监控Redis中过期键的删除情况?3.除了调整`hz`参数,还有哪些方法可以优化Redis过期键的删除?</think> ### Redis 过期键删除策略及配置方法 #### 一、Redis 过期键删除策略 Redis 采用 **惰性删除** 和 **定期删除** 相结合的混合策略(引用[1][3][4]): 1. **惰性删除 (Lazy Expiration)** - 触发时机:当客户端访问键时触发检测 - 执行逻辑:若发现键已过期则立即删除 - 优点:对 CPU 友好 - 缺点:可能导致过期键长期占用内存 2. **定期删除 (Periodic Expiration)** - 触发机制:Redis 周期性随机采样键进行检测(引用[4]) - 执行逻辑: - **Fast 模式**:短时间扫描部分键(默认每 100ms 执行 1 次) - **Slow 模式**:全量扫描所有键(当内存不足时自动触发) - 关键控制参数: - 每次扫描的键数量 - 扫描的 DB 数量 - 最大执行时长 > ⚠️ **策略优先级**:惰性删除优先执行,定期删除作为补充(引用[1]) > 📌 **数据一致性保障**:通过混合策略平衡内存占用和 CPU 负载(引用[2][4]) --- #### 二、配置方法(基于 redis.conf) 定期删除策略通过以下参数精细化控制(引用[4]): ```conf # 基础扫描频率 (默认值) hz 10 # 每秒执行10次后台任务(包括定期删除) # 慢速模式配置 slowlog-log-slower-than 10000 # 慢查询阈值(微秒) slowlog-max-len 128 # 慢查询日志长度 # 内存不足时行为 maxmemory-policy volatile-lru # 内存淘汰策略 ``` | 配置项 | 默认值 | 说明 | |--------|--------|------| | **hz** | 10 | 值越高删除越频繁(范围 1-500),过高会导致CPU占用增加 | | **maxmemory-samples** | 5 | 每次随机采样键的数量 | | **active-expire-effort** | 1 | 删除强度(1-10),值越大删除越激进 | > 🔧 **动态配置命令**: > ```bash > CONFIG SET hz 20 # 运行时调整扫描频率 > CONFIG REWRITE # 持久化配置到文件 > ``` --- #### 三、配置建议 1. **高频访问场景** - 提高 `hz` 值(建议 15-25)加速过期键回收 - 避免值超过 50,防止 CPU 过载 2. **大内存实例** - 增加 `maxmemory-samples`(建议 10-20)提升扫描覆盖率 - 启用 `volatile-ttl` 淘汰策略优先删除即将过期键 3. **关键数据场景** - 启用 **AOF 持久化** + `appendfsync always` 保证删除操作的持久性 - 监控慢查询日志:`slowlog get` --- #### ⚠️ 注意事项 - 不推荐依赖 **定时删除**(单独为每个键设置定时器),会导致 CPU 资源耗尽(引用[3]) - 当删除速度赶不上键过期速度时,需优化配置或升级硬件 - 集群环境中需确保所有节点时间同步(避免过期判断不一致) > 通过合理配置惰性与定期删除的协作机制,Redis 可在保证性能的同时实现内存高效回收[^1][^2][^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值