Redis中过期策略是怎么样的

63次阅读
没有评论

共计 3214 个字符,预计需要花费 9 分钟才能阅读完成。

这篇文章将为大家详细讲解有关 Redis 中过期策略是怎么样的,丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

保存过期时间

Redis 可以为每个 key 设置过期时间,会将每个设置了过期时间的 key 放入一个独立的字典中。【相关推荐:Redis 视频教程】

typedef struct redisDb { 
int id; //id 是数据库序号,为 0 -15(默认 Redis 有 16 个数据库) 
long avg_ttl; // 存储的数据库对象的平均 ttl(time to live),用于统计  
dict *dict; // 存储数据库所有的 key-value 
dict *expires; // 存储 key 的过期时间  
dict *blocking_keys;//blpop  存储阻塞 key 和客户端对象  
dict *ready_keys;// 阻塞后 push  响应阻塞客户端   存储阻塞后 push 的 key 和客户端对象  dict *watched_keys;// 存储 watch 监控的的 key 和客户端对象  
} redisDb;

dict 用来维护一个 Redis 数据库中包含的所有 Key-Value 键值对,expires 则用于维护一个 Redis 数据库中设置了失效时间的键 (即 key 与失效时间的映射)。注意这里的失效时间是用毫秒的时间戳表示的,比如 2022-01-02 22:45:02 过期则 value 为 1641134702000

当我们使用 expire 命令设置一个 key 的失效时间时,Redis 首先到 dict 这个字典表中查找要设置的 key 是否存在,如果存在就将这个 key 和失效时间添加到 expires 这个字典表。

当我们使用 setex 命令向系统插入数据时,Redis 首先将 Key 和 Value 添加到 dict 这个字典表中,然后将 Key 和失效时间添加到 expires 这个字典表中。注意 setex 只能用于字符串。

简单地总结来说就是,设置了失效时间的 key 和具体的失效时间全部都维护在 expires 这个字典表中。

设置过期时间

expire 的使用

expire 命令的使用方法如下: expire key ttl(单位秒)

127.0.0.1:6379  expire name 2 #2 秒失效  
(integer) 1 
127.0.0.1:6379  get name 
(nil) 
127.0.0.1:6379  set name zhangfei 
OK 
127.0.0.1:6379  ttl name # 永久有效  
(integer) -1 
127.0.0.1:6379  expire name 30 #30 秒失效  
(integer) 1 
127.0.0.1:6379  ttl name # 还有 24 秒失效  
(integer) 24 
127.0.0.1:6379  ttl name # 失效  
(integer) -2

Redis 有四个不同的命令可以用于设置键的生存时间(键可以生存多久)或过期时间(键什么时候会被删除):

expire 命令用于将键 key 的生存时间设置为 ttl 秒

pexpire 命令用于将键 key 的生存时间设置为 ttl 毫秒

expireat 命令用于将键 key 的过期时间设置为 timestamp 所指定的秒数时间戳

pexpireat 命令用于将键 key 的过期时间设置为 timestamp 所指定的毫秒数时间戳

注意 expire、pexpire、expireat 最终实现都是通过 pexpireat 实现的,也就是说无论客户端执行哪个命令,都会 Redis 都会转换成 pexpireat 命令执行。所以 expires 字典中存的时间是用毫秒时间戳表示的键的过期时间。

过期策略

如果一个键过期了,那什么时候被删除呢?

有三种过期策略

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

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

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

定时删除

优点

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

缺点

1、对 cpu 最不友好:在过期键比较多的情况下,删除过期键这一行为可能会占用相当一部分 cpu 的时间,对服务器的响应时间和吞吐量造成影响。

惰性删除

优点

1、对 cpu 最友好:只有在取出键的时候才会对过期键进行检查,即不需要 cpu 定期扫描,也不需要创建大量的定时器。

缺点

1、对内存最不友好:如果一个键已经过期,但是后面不会被访问到的话,那么就一直保留在数据库中。如果这样的键过多,无疑会占用很大的内存。

定期删除

定期删除是上面的定时删除和惰性删除的一中折中方案。

优点

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

2、通过删除过期键,能有效的减少因为过期键而带来的内存浪费

缺点 难以确定删除操作执行的时长和频率

1、如果删除操作执行得太频繁,或者执行的时间太长,定期删除策略就会退化成定时删除,以至于占用太多 cpu 的执行时间。

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

Redis 的过期策略

Redis 使用是惰性删除和定期删除两种策略:通过配好使用这两种策略,服务器可以很好地在合理使用 cpu 时间和避免浪费内存空间之间取得平衡。

惰性删除策略的实现

过期键的惰性删除删除策略由 db.c/expireIfNeeded 函数实现,所有读写数据库的 Redis 命令在执行之前都会调用 expireIfNeed 函数对输入键进行检查:

如果键已经过期,那么 expireIfNeeded 函数将键删除

如果键未过期,那么 expireIfNeeded 函数不做操作

命令调用 expireIfNeeded 函数过程如下图

另外因为每个被访问的键都可能被删除,所以每个命令都必须能同时处理键存在以及不存在的情况。
下图表示 get 命令的执行过程

定期删除策略的实现

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

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

(1) 从过期字典中随机选出 20 个 key。

(2) 删除这 20 个 key 中已经过期的 key。

(3) 如果过期的 key 的比例超过 1/4,那就重复步骤 (1)。同时,为了保证过期扫描不会出现循环过度,导致结程卡死的现象,算法还增加了扫描时间的上限,默认不会超过 25ms。

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

消耗 cpu

Redis 会持续扫描过期字典 (循环多次),直到过期字典中过期的 key 变得稀疏,才会停止 (循环次数明显下降)。

导致请求卡顿或超时

当客户端请求到来时,服务器如果正好进入过期扫描状态,客户端的请求将会等待至少 25ms 后才会进行处理,如果客户端将超时时间设置得比较短,比如 10ms,那么就会出现大量的连接因为超时而关闭,业务端就会出现很多异常

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

关于“Redis 中过期策略是怎么样的”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-15发表,共计3214字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)