redis大key删除时要小心(redis删除大key为啥会阻塞)
mhr18 2024-10-24 11:10 40 浏览 0 评论
问题
redis大key是让人比较头疼的问题,如果线上redis出现大key,断然不可立即执行del,因为大key的删除会造成阻塞。阻塞期间,所有请求都可能造成超时,当超时越来越多,新的请求不断进来,这样会造成redis连接池耗尽,尽而引发线上各种依赖redis的业务出现异常。
做个简单测试
通过脚本先向redis写入大量的数据:
127.0.0.1:6379> hlen hset_test
(integer) 3784945
这里看到大概有300多万的数据,我们执行个del看看:
127.0.0.1:6379> del hset_test
(integer) 1
(3.90s)
可以发现耗时将近4s。
我们知道redis核心是单线程在跑的,那么这个阻塞期间,redis是无法处理其他请求的。
低峰期删除
最简单的方式就是在业务低峰期进行删除,比如大部分场景在凌晨4点左右比较低峰,这时候执行删除,造成的影响比较小。当然这种方式也是无法避免阻塞期间的请求,一般适用执行期间qps非常小的业务。
scan分批
既然大key不能一下删除,那么我们就分批删除。
hset
对于hset,我们hsan分批删除。
# 伪代码
HSCAN key 0 COUNT 100
HDEL key fields
每次取个100条,然后删除
set
对于set,我们可以每次随机取一批数据,然后删除
# 伪代码
SRANDMEMBER key 10
SREM key fields
zset
对于zset,每次可以直接删除一批数据
伪代码
ZREMRANGEBYRANK key 0 10
list
对于list,直接pop
伪代码
i:=0
for {
lpop key
i++
if i%100 == 0 {
sleep(1ms)
}
}
异步删除
过期key删除策略
有人说既然在线删除大key会造成阻塞,那么就对这个key设置一个TTL,交给redis自己去删。我先看看redis的过期key删除策略:
定期删除:
我们知道redis的key分为带过期的和永久的,对于有过期时间的key,redis会单独放在一个字典表里,单独的好处就是redis知道这个字典里的key随时可能过期,那么我就定期过来处理下,定期的任务就交给了serveCron,默认每100ms执行一次。每当serveCron执行的时候,就会去带ttl的key里面随机抽取一部分key来检查,如果这批key真的过期了,那么就执行同步删除。随机抽查的原因:
- 不可能全部检验的,阻塞线程
- 随机的话体现一定的公平性
惰性删除
通过定期删除,我们可以每次删除一批已经过期的key,但是如果一个key已经过期了,定期删除也没清理到,这时用户来读取这个key的话,肯定不能直接返回,这时也会检查这个key是否过期,如果过期直接删除,返回空。
淘汰策略
- noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键
- allkeys-lru:通过LRU算法驱逐最久没有使用的键
- volatile-lru:通过LRU算法从设置了过期时间的键集合中驱逐最久没有使用的键
- allkeys-random:从所有key中随机删除
- volatile-random:从过期键的集合中随机驱逐
- volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键
- volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
- allkeys-lfu:从所有键中驱逐使用频率最少的键
淘汰策略是一个灵活的选项,一般根据业务来选择合适的淘汰策略,那么自定义的淘汰策略是何时触发的?当然是我们进行加key或者更新一个更大的key的时候。所以他的删除也是同步的,如果正好淘汰一个大key的时候,很不幸当前也会发生阻塞。
总结:不管以上三种哪个触发的删除,它都是同步的。所以就算加个TTL,redis也是同步删除的,大key还是会造成阻塞。
异步删除
在redis4.0的时候,作者对于大key删除造成阻塞的问题也做了考虑,于是出现了异步删除,异步删除也分为用户主动和程序被动。
主动删除
unlink
对于主动删除,redis提供了del的替代方法unlink,当我们在unlink的时候,redis会先检查要删除元素的个数(比如集合),如果集合的元素的小于等于64个的时候,就会直接执行同步删除,因为这不算一个大key,不会浪费很多的开销,但是当超过64个的时候,redis会认为是大key的概率比较大,这时候redis会在字典里,先把key删除,真正的value会交给异步线程来操作,这样的话就不会对主线程造成任何影响。
flushall、flushdb
在执行flushall或者flushdb的时候,增加了ASYNC选项 FLUSHALL [ASYNC] ,当用户没设置ASYNC的时候,此时的flush操作是阻塞的,当设置了ASYNC的时候,会建立一个新的空字典,然后指向它,老字典交给异步线程来慢慢删。
被动删除
redis配置策略
- lazyfree-lazy-eviction:针对redis有设置内存达到maxmemory的淘汰策略时,这时候会启动异步删除,此场景异步删除的缺点就是如果删除不及时,内存不能得到及时释放。
- lazyfree-lazy-expire:对于有ttl的key,在被redis清理的时候,不执行同步删除,加入异步线程来删除。
- replica-lazy-flush:在slave节点加入进来的时候,会执行flush清空自己的数据,如果flush耗时较久,那么复制缓冲区堆积的数据就越多,后面slave同步数据较相对慢,开启replica-lazy-flush后,slave的flush可以交由异步现成来处理,从而提高同步的速度。
- lazyfree-lazy-server-del:这个选项是针对一些指令,比如rename一个字段的时候 RENAME key newkey, 如果这时newkey是存在的,对于rename来说它就要删除这个newkey的value,如果这个newkey是一个大key,那么就会造成阻塞,当开启了这个选项时也会交给异步线程来操作,这样就不会阻塞主线程了。
题外话:rename
先来做个测试:
127.0.0.1:6379> set A 1
OK
127.0.0.1:6379> eval "for i=1,10000000,1 do redis.call('hset','B', i,1) end" 0
(15.89s)
- 设置A为1
- 向B里面添加1000w的数据
B肯定是大key了,这时想把A重新命名成B执行rename A B
127.0.0.1:6379> rename A B
OK
(11.07s)
发现阻塞了,这是因为redis删除B造成的,如果有rename的场景一定要注意newkey是否已经存在,newkey是否是大key。
欢迎大家关注公众号《假装懂编程》,我将持续输出网络、数据库、go、缓存、架构、面试、程序人生相关文章。
相关推荐
- 使用 Docker 部署 Java 项目(通俗易懂)
-
前言:搜索镜像的网站(推荐):DockerDocs1、下载与配置Docker1.1docker下载(这里使用的是Ubuntu,Centos命令可能有不同)以下命令,默认不是root用户操作,...
- Spring Boot 3.3.5 + CRaC:从冷启动到秒级响应的架构实践与踩坑实录
-
去年,我们团队负责的电商订单系统因扩容需求需在10分钟内启动200个Pod实例。当运维组按下扩容按钮时,传统SpringBoot应用的冷启动耗时(平均8.7秒)直接导致流量洪峰期出现30%的请求超时...
- 《github精选系列》——SpringBoot 全家桶
-
1简单总结1SpringBoot全家桶简介2项目简介3子项目列表4环境5运行6后续计划7问题反馈gitee地址:https://gitee.com/yidao620/springbo...
- Nacos简介—1.Nacos使用简介
-
大纲1.Nacos的在服务注册中心+配置中心中的应用2.Nacos2.x最新版本下载与目录结构3.Nacos2.x的数据库存储与日志存储4.Nacos2.x服务端的startup.sh启动脚...
- spring-ai ollama小试牛刀
-
序本文主要展示下spring-aiollama的使用示例pom.xml<dependency><groupId>org.springframework.ai<...
- SpringCloud系列——10Spring Cloud Gateway网关
-
学习目标Gateway是什么?它有什么作用?Gateway中的断言使用Gateway中的过滤器使用Gateway中的路由使用第1章网关1.1网关的概念简单来说,网关就是一个网络连接到另外一个网络的...
- Spring Boot 自动装配原理剖析
-
前言在这瞬息万变的技术领域,比了解技术的使用方法更重要的是了解其原理及应用背景。以往我们使用SpringMVC来构建一个项目需要很多基础操作:添加很多jar,配置web.xml,配置Spr...
- 疯了!Spring 再官宣惊天大漏洞
-
Spring官宣高危漏洞大家好,我是栈长。前几天爆出来的Spring漏洞,刚修复完又来?今天愚人节来了,这是和大家开玩笑吗?不是的,我也是猝不及防!这个玩笑也开的太大了!!你之前看到的这个漏洞已...
- 「架构师必备」基于SpringCloud的SaaS型微服务脚手架
-
简介基于SpringCloud(Hoxton.SR1)+SpringBoot(2.2.4.RELEASE)的SaaS型微服务脚手架,具备用户管理、资源权限管理、网关统一鉴权、Xss防跨站攻击、...
- SpringCloud分布式框架&分布式事务&分布式锁
-
总结本文承接上一篇SpringCloud分布式框架实践之后,进一步实践分布式事务与分布式锁,其中分布式事务主要是基于Seata的AT模式进行强一致性,基于RocketMQ事务消息进行最终一致性,分布式...
- SpringBoot全家桶:23篇博客加23个可运行项目让你对它了如指掌
-
SpringBoot现在已经成为Java开发领域的一颗璀璨明珠,它本身是包容万象的,可以跟各种技术集成。本项目对目前Web开发中常用的各个技术,通过和SpringBoot的集成,并且对各种技术通...
- 开发好物推荐12之分布式锁redisson-sb
-
前言springboot开发现在基本都是分布式环境,分布式环境下分布式锁的使用必不可少,主流分布式锁主要包括数据库锁,redis锁,还有zookepper实现的分布式锁,其中最实用的还是Redis分...
- 拥抱Kubernetes,再见了Spring Cloud
-
相信很多开发者在熟悉微服务工作后,才发现:以为用SpringCloud已经成功打造了微服务架构帝国,殊不知引入了k8s后,却和CloudNative的生态发展脱轨。从2013年的...
- Zabbix/J监控框架和Spring框架的整合方法
-
Zabbix/J是一个Java版本的系统监控框架,它可以完美地兼容于Zabbix监控系统,使得开发、运维等技术人员能够对整个业务系统的基础设施、应用软件/中间件和业务逻辑进行全方位的分层监控。Spri...
- SpringBoot+JWT+Shiro+Mybatis实现Restful快速开发后端脚手架
-
作者:lywJee来源:cnblogs.com/lywJ/p/11252064.html一、背景前后端分离已经成为互联网项目开发标准,它会为以后的大型分布式架构打下基础。SpringBoot使编码配置...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (63)
- oracle批量插入数据 (62)
- oracle事务隔离级别 (53)
- oracle 空为0 (50)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)