当前位置: 首页 > news >正文

Redis过期数据的删除策略

1 介绍

Redis 是一个kv型数据库,我们所有的数据都是存放在内存中的,但是内存是有大小限制的,不可能无限制的增量。
想要把不需要的数据清理掉,一种办法是直接删除,这个咱们前面章节有详细说过;另外一种就是设置过期时间,缓存过期后,由Redis系统自行删除。
这边需要注意的是,缓存过期之后,并不是马上删除的,那Redis是怎么删除过期数据的呢?主要通过两个方式

  • 惰性删除
  • 通过定时任务,定期选取部分数据删除

2 Redis缓存过期命令

我们通过以下指令给指定key的缓存设置过期时间,如果都没设置过期时间, key 将一直存在,直到我们使用 Del 的命令明确删除掉。

# 缓存时间过期命令,参考如下
EXPIRE key seconds [ NX | XX | GT | LT] 

Redis 7.0 开始,EXPIRE 添加了 NX、XX和GT、LT 选项,分别代表如下:

  • NX:仅当Key没有过期时设置过期时间
  • XX:仅当Key已过期时设置过期时间
  • GT:仅当新到期时间大于当前到期时间时设置到期时间
  • LT:仅当新到期时间小于当前到期时间时设置到期时间

其中,GT、LT和NX选项是互斥的,下面是官方的测试用例:

redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> SET mykey "Hello World"
"OK"
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 XX
(integer) 0
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 NX
(integer) 1
redis> TTL mykey
(integer) 10

3 两种过期数据的删除方式

我们前面说过,Redis删除过期数据主要通过以下两个方式,我们一个个来看:

  • 惰性删除
  • 通过定时任务,定期选取部分数据删除

3.1 惰性删除

惰性删除比较简单,当客户端请求过来查询我们的key的时候,先对key做一下检查,如果没过期则返回缓存数据,如果过期,则删除缓存,重新从数据库中获取数据。
这样,我们就把删除过期数据的主动权交给了访问请求的客户端,如果客户端一直没请求,那这个过期缓存可能就长时间得不到释放。

Redis的源码 src/db.c 中的 expireIfNeeded 方法 就是实现以上惰性删除逻辑的,我们来看看:

int expireIfNeeded(redisDb *db, robj *key, int force_delete_expired) {// 对于未过期的key,直接 return 0if (!keyIsExpired(db,key)) return 0;	/* If we are running in the context of a slave, instead of* evicting the expired key from the database, we return ASAP:* the slave key expiration is controlled by the master that will* send us synthesized DEL operations for expired keys.** Still we try to return the right information to the caller,* that is, 0 if we think the key should be still valid, 1 if* we think the key is expired at this time. */if (server.masterhost != NULL) {if (server.current_client == server.master) return 0;if (!force_delete_expired) return 1;}/* If clients are paused, we keep the current dataset constant,* but return to the client what we believe is the right state. Typically,* at the end of the pause we will properly expire the key OR we will* have failed over and the new primary will send us the expire. */if (checkClientPauseTimeoutAndReturnIfPaused()) return 1;/* Delete the key */deleteExpiredKeyAndPropagate(db,key);return 1;
}

3.2 定期删除

刚才前面说过了,仅靠客户端访问来对过期缓存执行删除远远不够,因为有的 key 过期了,但客户端一直没请求,那这个过期缓存可能就长时间甚至永远得不到释放。
所以除了惰性删除,Redis 还可以通过定时任务的方式来删除过期的数据。定时任务的发起的频率由redis.conf配置文件中的hz来进行配置

# 代表每1s 运行 10次
hz 10

Redis 默认每 1 秒运行 10 次,也就是每 100 ms 执行一次,每次随机抽取一些设置了过期时间的 key(这边注意不是检查所有设置过期时间的key,而是随机抽取部分),检查是否过期,如果发现过期了就直接删除。
该定时任务的具体流程如下:

  1. 定时serverCron方法去执行清理,执行频率根据redis.conf中的hz配置的值
  2. 执行清理的时候,不是去扫描所有的key,而是去扫描所有设置了过期时间的key(redisDb.expires)
  3. 如果每次去把所有过期的key都拿过来,那么假如过期的key很多,就会很慢,所以也不是一次性拿取所有的key
  4. 根据hash桶的维度去扫描key,扫到20(可配)个key为止。假如第一个桶是15个key ,没有满足20,继续扫描第二个桶,第二个桶20个key,由于是以hash桶的维度扫描的,所以第二个扫到了就会全扫,总共扫描35个key
  5. 找到扫描的key里面过期的key,并进行删除
  6. 删除完检查过期的 key 超过 25%,继续执行4、5步

image

其他注意点:

  • 为何不扫描所有key进行过期缓存元素删除:Redis本身就是高速缓存,如果每次检查大量的key,无论在CPU和内存的的使用率上都会特别高,Redis集群越大,风险越大。
  • 分片模式下的删除同步:无论定时删除还是惰性删除。master 会生成删除的指令记录到 AOF 和 slave 节点。

http://www.lryc.cn/news/137476.html

相关文章:

  • 如何使用CSS实现一个拖拽排序效果?
  • leetcode 118.杨辉三角
  • 微服务框架之SpringBoot面试题汇总
  • Promise详解
  • Oracle 查询(当天,月,年)的数据
  • 什么是梯度下降
  • 开黑啦kook 机器人开发 PHP swoole Liunx 服务器(宝塔)
  • Vue 中hash 模式与 history 模式的区别
  • Dockerfile推送私有仓库的两个案例
  • 【指标】指标公式大全,款款经典(建议珍藏)!-神奇指标网
  • 面试题目收集
  • 创建R包-2.1:在RStudio中使用Rcpp制作R-Package(更新于2023.8.23)
  • chatGPT如何解释泽众PerformanceRunner性能测试工具?
  • LA@向量组线性相关性
  • [k8s] 基于ubuntu22部署k8s1.28记录
  • React 事件代理 和原生事件绑定混用:你的选择会导致什么问题?
  • 使用阿里云国外和国内云服务器有什么注意事项?
  • 【计算机网络】【常考问题总结】
  • 前端基础(props emit slot 父子组件间通信)
  • 即时通讯:短轮询、长轮询、SSE 和 WebSocket 间的区别
  • 高忆管理:药店零售概念回落,开开实业走低,此前7日大涨超80%
  • Go1.19 排序算法设计实践 经典排序算法对比
  • 3:Ubuntu上配置QT交叉编译环境并编译QT程序到Jetson Orin Nano(ARM)
  • CentOS下MySQL的彻底卸载的几种方法
  • Spring 的异常处理机制
  • java八股文面试[JVM]——JVM参数
  • 面试热题(复原ip地址)
  • 【JavaSE】Java方法的使用
  • Node.js 安装和配置(完整详细版)
  • 剪枝基础与实战(4):稀疏训练及剪枝效果展示