redis的过期策略

本文介绍了Redis过期key的处理策略。Redis会将设置过期时间的key放入独立字典,采用定时遍历和惰性删除策略。定时扫描每秒十次,用贪心策略,有扫描时间上限。业务开发要避免大量key同时过期,否则会导致读写卡顿。从库过期处理被动,依赖主库同步del指令,可能出现主从数据不一致。

Redis 所有的数据结构都可以设置过期时间,时间一到,就会自动删除。你可以想象 Redis 内部有一个死神,时刻盯着所有设置了过期时间的 key,寿命一到就会立即收割。

你还可以进一步站在死神的角度思考,会不会因为同一时间太多的 key 过期,以至于忙不过来。同时因为 Redis 是单线程的,收割的时间也会占用线程的处理时间,如果收割的太过于繁忙,会不会导致线上读写指令出现卡顿。

过期的 key 集合

redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定时遍历这个字典来删除到期的 key。除了定时遍历之外,它还会使用惰性策略来删除过期的 key,所谓惰性策略就是在客户端访问这个 key 的时候,redis 对 key 的过期时间进行检查,如果过期了就立即删除。定时删除是集中处理,惰性删除是零散处理。

定时扫描策略

Redis 默认会每秒进行十次过期扫描,过期扫描不会遍历过期字典中所有的 key,而是 采用了一种简单的贪心策略。

1、从过期字典中随机 20 个 key;

2、删除这 20 个 key 中已经过期的 key;

3、如果过期的 key 比率超过 1/4,那就重复步骤 1;

同时,为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过 25ms。

设想一个大型的 Redis 实例中所有的 key 在同一时间过期了,会出现怎样的结果?

毫无疑问,Redis 会持续扫描过期字典 (循环多次),直到过期字典中过期的 key 变得稀疏,才会停止 (循环次数明显下降)。这就会导致线上读写请求出现明显的卡顿现象。导致这 种卡顿的另外一种原因是内存管理器需要频繁回收内存页,这也会产生一定的 CPU 消耗。

也许你会争辩说“扫描不是有 25ms 的时间上限了么,怎么会导致卡顿呢”?这里打个 比方,假如有 101 个客户端同时将请求发过来了,然后前 100 个请求的执行时间都是 25ms,那么第 101 个指令需要等待多久才能执行?2500ms,这个就是客户端的卡顿时间, 是由服务器不间断的小卡顿积少成多导致的。

所以业务开发人员一定要注意过期时间,如果有大批量的 key 过期,要给过期时间设置 一个随机范围,而不能全部在同一时间过期。

# 在目标过期时间上增加一天的随机时间
redis.expire_at(key, random.randint(86400) + expire_ts)

在一些活动系统中,因为活动是一期一会,下一期活动举办时,前面几期的很多数据都可以丢弃了,所以需要给相关的活动数据设置一个过期时间,以减少不必要的 Redis 内存占用。如果不加注意,你可能会将过期时间设置为活动结束时间再增加一个常量的冗余时间, 如果参与活动的人数太多,就会导致大量的 key 同时过期。

从库的过期策略

从库不会进行过期扫描,从库对过期的处理是被动的。主库在 key 到期时,会在 AOF 文件里增加一条 del 指令,同步到所有的从库,从库通过执行这条 del 指令来删除过期的 key。

因为指令同步是异步进行的,所以主库过期的 key 的 del 指令没有及时同步到从库的话,会出现主从数据的不一致,主库没有的数据在从库里还存在。

Redis 提供了丰富的键过期策略和机制,以支持灵活的数据生命周期管理。在 Redis 中,可以通过设置键的生存时间(TTL, Time To Live)来控制键的自动删除行为。一旦键的 TTL 过期,它将被自动从数据库中移除。 ### 键的过期设置 Redis 支持多种方式为键设置过期时间: - **EXPIRE**:以秒为单位设置键的生存时间。 - **PEXPIRE**:以毫秒为单位设置键的生存时间。 - **EXPIREAT**:指定一个绝对时间点(Unix 时间戳,以秒为单位),当到达该时间点时,键将失效。 - **PEXPIREAT**:与 `EXPIREAT` 类似,但以毫秒为单位指定绝对时间点。 例如: ```bash SET mykey "Hello" EXPIRE mykey 60 # 设置键 mykey 的生存时间为 60 秒 ``` ### 键的过期策略 Redis 实现了以下几种主要的过期策略来平衡性能和内存使用: 1. **惰性删除(Lazy Expiration)** Redis 不会主动检查并删除已过期的键,而是等到客户端尝试访问某个键时才检查其是否过期。如果键已经过期,则将其删除并返回空值给客户端。这种策略的优点是节省 CPU 资源,但可能导致过期键长时间驻留在内存中,直到被访问为止。 2. **定期删除(Active Expiration)** Redis 每隔一段时间(默认每 100 毫秒)会随机检查一部分设置了过期时间的键,并删除其中已经过期的键。这一过程是渐进式的,不会一次性扫描所有键,从而避免对性能造成显著影响。这种方式可以在一定程度上减少内存浪费,同时保持系统的响应速度。 3. **混合模式** Redis 实际采用的是惰性删除和定期删除相结合的方式。这样既保证了大部分情况下不会因为检查过期键而消耗过多资源,又能及时清理掉一些长期未被访问但仍过期的键。 ### 过期键的存储结构 为了高效地处理设置了过期时间的键,Redis 使用了一个专门的字典(称为 `expires` 字典)来保存这些键及其对应的过期时间。每个设置了过期时间的键都会在这个字典中有一个条目,键本身仍然存在于主字典中,但其过期时间则记录在 `expires` 字典中。 ### 查看过期时间 用户可以使用以下命令来查询键的过期时间: - **TTL**:返回键的剩余生存时间(以秒为单位)。如果键没有设置过期时间,则返回 `-1`;如果键不存在或已过期,则返回 `-2`。 - **PTTL**:与 `TTL` 类似,但返回值是以毫秒为单位的剩余生存时间。 例如: ```bash TTL mykey ``` ### 复杂度与性能考虑 对于大多数实际应用场景来说,Redis 的键过期机制是非常高效的。然而,在某些极端情况下,比如大量键在同一时间点过期,可能会导致短暂的性能波动。为了避免这种情况,建议合理分布键的过期时间,或者通过程序逻辑引入一定的随机性来分散过期时间。 此外,需要注意的是,当数据量较大且频繁设置过期时间时,定期删除操作可能无法完全覆盖所有过期键,因此系统内存占用可能会有所增加。在这种情况下,可以适当调整 Redis 的配置参数(如 `maxmemory` 和 `maxmemory-policy`)来优化内存使用。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值