Redis del bigkey即使开启了lazyfree,为什么还是阻塞的,但是别人又不阻塞?why

数据库之Redis运维手册(私人整理) 1、redis配置文件 #cat 8000.conf daemonize no #[yes/no]默认值no,该参数用于定制redis服务是否以守护模式运行。 pidfile /var/run/redis.pid #默认值/var/run/redis.pid,指定redis服务的进程号文件路径,以守护模式运行时需要配置本参数; port 8000 #默认值6379,指定redis服务... 阅读详情

图片

Redis del bigkey之后为啥还是阻塞的呢?明明开启了lazyfree,为啥别人立马可以删除?


干货:[公粽号:堆栈future]

lazyfree redis 4.0引入

lazyfree-lazy-user-del 6.0引入


为什么del删除bigkey是阻塞的

lazy-free是4.0新增的功能,但是默认是关闭的,需要手动开启。你开启之后,然后用del删除一个几万的key,发现命令阻塞在那里了,你很郁闷,我都开启了,为撒还阻塞呢?莫非在逗我?

先说答案:你用错了命令,在你开启lazyfree之后,你得用redis提供的命令:unlink,用这个命令去删除就是异步了。

redis> UNLINK key1 key2 key3
(integer) 2

源码角度解释下为什么

手动开启lazy-free时,有4个选项可以控制,分别对应不同场景下,要不要开启异步释放内存机制:

  1. lazyfree-lazy-expire:key在过期删除时尝试异步释放内存

  2. lazyfree-lazy-eviction:内存达到maxmemory并设置了淘汰策略时尝试异步释放内存

  3. lazyfree-lazy-server-del:执行RENAME/MOVE等命令或需要覆盖一个key时,删除旧key尝试异步释放内存

  4. replica-lazy-flush:主从全量同步,从库清空数据库时异步释放内存

除了replica-lazy-flush之外,其他情况都只是可能去异步释放key的内存,并不是每次必定异步释放内存的。

开启lazy-free后,Redis在释放一个key的内存时,首先会评估代价,如果释放内存的代价很小,那么就直接在主线程中操作了,没必要放到异步线程中执行(不同线程传递数据也会有性能消耗)。

什么情况才会真正异步释放内存?这和key的类型、编码方式、元素数量都有关系(详细可参考源码中的lazyfreeGetFreeEffort函数):

  • 当Hash/Set底层采用哈希表存储(非ziplist/int编码存储)时,并且元素数量超过64个

  • 当ZSet底层采用跳表存储(非ziplist编码存储)时,并且元素数量超过64个

  • 当List链表节点数量超过64个(注意,不是元素数量,而是链表节点的数量,List的实现是在每个节点包含了若干个元素的数据,这些元素采用ziplist存储)

  • 再加一个条件就是refcount=1 就是没有人在引用这个key的时候

只有以上这些情况,在删除key释放内存时,才会真正放到异步线程中执行,其他情况一律还是在主线程操作。

也就是说String(不管内存占用多大)、List(少量元素)、Set(int编码存储)、Hash/ZSet(ziplist编码存储)这些情况下的key在释放内存时,依旧在主线程中操作。

直接看源码:

size_t lazyfreeGetFreeEffort(robj *key, robj *obj, int dbid) {
    if (obj->type == OBJ_LIST) {
        quicklist *ql = obj->ptr;
        return ql->len;
    } else if (obj->type == OBJ_SET && obj->encoding == OBJ_ENCODING_HT) {
        dict *ht = obj->ptr;
        return dictSize(ht);
    } else if (obj->type == OBJ_ZSET && obj->encoding == OBJ_ENCODING_SKIPLIST){
        zset *zs = obj->ptr;
        return zs->zsl->length;
    } else if (obj->type == OBJ_HASH && obj->encoding == OBJ_ENCODING_HT) {
        dict *ht = obj->ptr;
        return dictSize(ht);
    } else if (obj->type == OBJ_STREAM) {
        size_t effort = 0;
        stream *s = obj->ptr;
    }
}

lazyfreeGetFreeEffort函数判断下删除一个key的付出有多大,然后

#define LAZYFREE_THRESHOLD 64

/* Free an object, if the object is huge enough, free it in async way. */
void freeObjAsync(robj *key, robj *obj, int dbid) {
    size_t free_effort = lazyfreeGetFreeEffort(key,obj,dbid);
    if (free_effort > LAZYFREE_THRESHOLD && obj->refcount == 1) {
        atomicIncr(lazyfree_objects,1);
        bioCreateLazyFreeJob(lazyfreeFreeObject,1,obj);
    } else {
        decrRefCount(obj);
    }
}

它被freeObjAsync这个函数调用,用来和64去判断并且同时判断引用是否为1.只有满足了大于64并且refcount==1,那么就会异步删除,异步删除就是把这个删除任务交由(bio系统)去处理,否则调用decrRefCount在主线称中同步删除,如果是用zmalloc申请的内存最后都是调用zfree删除。

可见,即使开启了lazy-free,String类型的bigkey,在删除时依旧有阻塞主线程的风险。所以,即便Redis提供了lazy-free,我建议还是尽量不要在Redis中存储bigkey。

那为什么有人能del bigkey成功呢?

能del一个bigkey成功的,一定是因为他所用的redis版本是6.0及以上的。redis增加了一个配置项:lazyfree-lazy-user-del,只要开启了,del直接可以异步删除key了,这就和unlink没啥区别了。

堆栈future

使很多处于迷茫阶段的coder能从这里找到光明,堆栈创世,功在当代,利在千秋

121篇原创内容

图片

Redis:从“单线程神话“到“多线程真香“——一条走了十几年的演绎之路 文章摘要: Redis网络模型从单线程到多线程的演变,展现了高性能设计的智慧与妥协。最初采用单线程事件循环(Reactor模式),通过全内存操作、无锁竞争和极致优化的数据结构实现超高吞吐。但随着网络IO成为瓶颈,Redis 6.0引入多线程网络IO处理(主线程仍串行执行命令),QPS提升50%-170%,核心源码通过分桶分配socket避免锁竞争。未来或将探索命令执行多线程化、智能调度等方向。这一演变揭示了技术选型中平衡简单性与性能的永恒课题,也为高并发场景提供了经典优化范式。(149字) 阅读详情

相关推荐

自然语言处理:稀疏向量表示

稀疏向量表示是指运用特定的方法和技术,将数据(如文本、图像、信号等)转化为向量形式,且该向量具有大部分元素值为零,仅少数元素值非零的特征,以此来实现对数据的高效存储、处理和分析。

老赵爱学习的博客 1443

Redis7_11 高阶篇 第二章 Redis的BigKey

阿里广告平台,海量数据里查询某一固定前缀的key? 小红书,你如何生产上限制keys */flushdb/flushall等危险命令以防止误删误用? 美团,MEMORY USAGE 命令你用过吗? BigKey问题,多大算big? 你如何发现? 如何删除? 如何处理? BigKey你做过调优吗? 惰性释放lazyfree了解过吗? Morekey问题,生产上redis数据库有1000W记录,你如何遍历? key *可以吗?

qq_33168558的博客 1665

Spring Boot整合Apache Hop 2.3.0实战:从零搭建数据管道(附完整代码)

本文详细介绍了如何在Spring Boot项目中整合Apache Hop 2.3.0,从零开始构建可嵌入的数据管道。内容涵盖环境初始化、依赖配置、管道设计,并通过完整代码示例演示了如何通过REST API触发执行,实现数据同步与ETL流程的自动化管理,为微服务架构提供灵活的数据集成方案。

web99的专栏 632

redis惰性删除 lazy free 源码剖析,干货满满

redis 是用 c 语言实现的,而我们知道 c 语言是没有垃圾回收的,也就说对于程序申请的内存是需要程序来释放的,因此,在 redis 中删除数据包含两个步骤: 步骤一:将待删除数据对从字典表中删除; 步骤二:释放待删除数据所占用的内存空间。 如果这两个步骤同步执行,就叫同步删除;而如果只执行步骤一,将来通过后台线程来执行步骤二,就叫异步删除。而惰性删除里的惰性其实指的就是删除时只执行步骤一,而将步骤二 "延迟" 到后台线程执行。

Chlapis的博客 4123

避坑指南:企业微信IP白名单设置失败的5种常见原因及解决方案

本文深入解析企业微信API调用中IP白名单设置失败的5种常见原因,包括动态公网IP变更、代理服务器导致的IP失真等,并提供针对性的解决方案。特别针对可信IP配置问题,详细介绍了诊断方法和Java代码示例,帮助企业开发者快速解决访问限制问题,确保API调用安全稳定。

weixin_29280657的博客 619

手把手教你用DaVinci Configurator配置AUTOSAR SWC接口(含RTE避坑指南)

本文提供了一份基于DaVinci Configurator工具的AUTOSAR软件组件(SWC)接口配置实战指南。文章详细拆解了SR(发送者-接收者)和CS(客户端-服务器)接口的配置流程,并重点分享了运行时环境(RTE)生成阶段在多核部署、数据类型匹配等常见陷阱中的避坑方案与调试技巧,旨在帮助汽车电子工程师高效完成配置并规避错误。

uuu88的博客 547

2021-09-17

作者:Java斗帝之路 Redis作为一个基于内存的缓存系统,一直以高性能著称,因没有上下文切换以及无锁操作,即使在单线程处理情况下,读速度仍可达到11万次/s,写速度达到8.1万次/s。但是,单线程的设计也给Redis带来一些问题: 只能使用CPU一个核; 如果删除的键过大(比如Set类型中有上百万个对象),会导致服务端阻塞好几秒; QPS难再提高。 针对上面问题,Redis在4.0版本以及6.0版本分别引入了Lazy Free以及多线程IO,逐步向多线程过渡,下面将会做详细介绍。 单线程原.

chinaherolts2008的博客 217

unity | 动画模块之滚动选项框

动画模块之滚动选项框

菌菌兹的博客 2074

Redis 异步删除各个参数的具体作用

综合上面的分析,异步删除各参数的作用如下,注意,这几个参数的默认值都是 no。另外,在通过POPTRIM之类的命令从列表(List),集合(Set),有序集合(Sorted Set)中弹出或者移除元素时,对于这些元素的删除都是同步的,并不会异步删除。如果元素的值过大(最大值由 proto-max-bulk-len 决定,默认是 512MB),依然会阻塞主线程。

王二的博客 922

程序员必备75道逻辑思维题(附答案)之二

逻辑训练 身为一个大数据工程师,平时的算法训练还是不能少的,今天给大家看几道我曾经看到的逻辑思维题觉得很好,想分享一下。 【6】一个球、一把长度大约是球的直径2/3长度的直尺.你怎样测出球的半径?方法很多,看看谁的比较巧妙 【7】五个大小相同的一元人民币硬币。要求两两相接触,应该怎么摆? 【8】猜牌问题 S先生、P先生、Q先生他们知道桌子的抽屉里有16张扑克牌:红桃A、Q、4 黑桃J、8、4、2、...

蛋蛋淡淡定的庄园 3547

RT-DETR算法优化改进:Backbone改进 | HGBlock完美结合PPHGNetV2 GhostConv

GhostConv助力RT-DETR ,HGBlock与PPHGNetV2 GhostConv完美结合

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 2909

redis提升知识点

转发自:https://www.toutiao.com/i6932075775340675597/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1614216920&app=news_article&utm_source=weixin&utm_medium=toutiao_android&use_new_style=1&req_id=20210225093

jackey_sdc的博客 269

docker-compose Install OrangeHRM

OrangeHRM是一个全面的人力资源管理HRM) 系统,它包含任何企业所需的所有基本功能。OrangeHRM旨在支持任何规模的团队,包括初创企业、中小企业以及大型跨国组织。

极致,细节 1004

谈谈BigKey的理解

我们都知道Redis是一种kv键值对存储数据的非关系型数据库,当一个key的value值过大时,就会出现BigKey的问题,最直接的影响就是会影响我们redis的性能和稳定,所以我们需要清除和排查BigKey。

qq_62592925的博客 226

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Redis 大键值对 Big Key 懒惰删除机制

一、懒惰删除介绍 在删除元素数量很多的集合(set/hash/list/sortedSet)时,无论是使用DEL命令删除还是redis为了释放内存空间而进行的删除,在删除这些big key的时候,会导致redis主线程阻塞。 在redis 4.0版本中,提供了lazy free(懒惰删除)的特性解决 big key 删除导致的主线程阻塞的问题。 使用lazy free删除big key时,和一个O(1)指令的耗时一样,亚毫秒级返回(返回结果不会产生等待阻塞),真正删除key的耗时动作交由后台子线程执行

潘广宇的博客 1582

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Redis4.0新特性(二)-Lazy Free

Redis4.0新增了非常实用的lazy free特性,从根本上解决Big Key(主要指定元素较多集合类型Key)删除的风险。笔者在redis运维中也遇过几次Big Key删除带来可用性和性能故障。 本文分为以下几节说明redis lazy free: lazy free的定义 ...

chuangpangzhou2446的博客 165

redis过期key的删除策略

前言 在使用redis的过程中,不免会产生过期的key,而这些key过期后并不会实时地马上被删除,当这些key数量累积越来越多,就会占用很多内存,因此在redis底层同时使用了三种策略来删除这些key。 第一种策略:被动删除 当读/写一个key时,redis首先会检查这个key是否存在,如果存在且已过期,则直接删除这个key并返回nil给客户端。 第二种策略:定期删除 redis中有一系列的定期任务(serverCron),这些任务每隔一段时间就会运行一次,其中就包含清理过期key的任务,运行频率由配置文件

IT部落格 8132

Redis:性能风险之内部阻塞风险

可见,即使开启了lazy-free,String类型的bigkey,在删除时依旧有阻塞主线程的风险。开启lazy-free后,Redis在释放一个key的内存时,首先会评估代价,如果释放内存的代价很小,那么就直接在主线程中操作了,没必要放到异步线程中执行(不同线程传递数据也会有性能消耗)。删除操作需要释放键值对所占用的内存空间,而操作系统在释放空间之后会插入一个空的内存块的链表,便于后续的管理和再分配,因此再,这个过程会阻塞应用程序,特别是对于释放大量的数据的时候。什么情况才会真正异步释放内存?

张豫湘的博客 209

redis 怎么关闭写盘_redis为什么响应变慢了

redis是一个内存的数据库,最大的特点就是访问性能快,但是也有很多时候,我们会遇到响应变慢的情况,今天我们就来聊一聊。redis是一个单线程的模型,如果主线程阻塞了,肯定会造成响应变慢。下面我们先来看一看阻塞主线程的操作。AOF重写和RDB快照前面已经讲过了,redis在AOF重写时,主线程会fork出一个bgrewriteaof子进程,而主线程会fork出一个bgsave子进程。这2个操作表面...

weixin_33367083的博客 123

redis灵魂拷问:为什么响应变慢了

redis响应变慢的原因有哪些呢?

zjj2006的专栏 786

做对这 10 点,让你的 Redis 性能更上一层楼

Redis 作为内存数据库,虽说已经足够快了。但是,做对这 10 点,可以让你的 Redis 性能更上一层楼!

IT小小鸟~~ 1660

Redis

│ └── skiplist [底层:dict(解决key到value的快速查询)+ skiplist(解决Zset排序、范围查询、排名问题)]比如爆款商品、热门微博、秒杀库存。│ └── quicklist:适合大数据量,把数据拆成多个listpack,避免单个listpck过大,较好的增删性能。某一个redis key对应的数据量特别大,对这个key的操作、网络传输、内存占用和迁移成本明显高于普通key。volatile-ttl:从设置ttl的key中淘汰剩余ttl最短的key。

qq_39356542的博客 177

redis的关键路径和lazy-free

Redis的写操作(例如SET,HSET,SADD等)是在关键路径上吗? 我觉得这需要客户端根据业务需要来区分: 1、如果客户端依赖操作返回值的不同,进而需要处理不同的业务逻辑,那么HSET和SADD操作算关键路径,而SET操作不算关键路径。因为HSET和SADD操作,如果field或member不存在时,Redis结果会返回1,否则返回0。而SET操作返回的结果都是OK,客户端不需要关心结果有什么不同。 2、如果客户端不关心返回值,只关心数据是否写入成功,那么SET/HSET/SADD不算关键路径,多次执

yizhiniu_xuyw的专栏 482

知识体系之Redis

redis

JaweG 2792

Redis 超时排查

突然收到告警,提示redis挂了,同时大群也在说某某redis连接超时了,过了一会儿就恢复了。这时登上服务器,查看监控。首先看看qps: 可以看到qps并不高,但是中间有段时间没取到数据是怎么回事?那么继续看看redis的cpu使用率: 可以看到cpu已经饱和,这也就能解释为何断图了,因为redis是单线程,在使用cpu 100%以后,就无法处理其他的命令了,zabbix也就无法执行i...

weixin_34348174的博客 290
上一篇: Redis Cluster通过hash slot映射数据,但是如何把两个key映射到同一个slot中呢?
下一篇: Redis实例发生故障,而Redis使用RDB机制,事务的原子性能否得到保证?
stackfuture
博客等级 码龄5年 23粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值