有没有处理过Redis大Key
到底多大,才算大Key?
这里有一个常见的误区,就是认为大Key就是指String类型的Value很大。这个理解不完全对。大Key的“大”,有两个维度的衡量标准:

对于String类型,我们看的是它的Value体积。一般来说,超过 10MB 的String,我们就要高度警惕了。比如你把一整篇长文,或者一个巨大的JSON对象直接塞进去,就很容易产生这种大Key。它的问题在于,一次网络请求就可能把服务器的网卡带宽给打满。

对于集合类型,也就是 Hash, List, Set, ZSet,我们更关注的是它的内部元素数量。一个经验法则是,当成员数超过 5000个 时,它就是一个潜在的大Key。比如一个拥有几百万粉丝的用户的粉丝列表,或者一个热门商品的评论集合。你对它做一次全量操作,比如 HGETALL,就可能让Redis卡住很久。
所以,请大家记住我们这页PPT的核心思想:大Key的本质,是一次命令操作的资源开销过大,这包括CPU、内存和网络。一个体积只有1KB的Hash,但如果它里面有一百万个field,那它绝对是一个“超级大Key”!
大Key的危害
了解了什么是大Key,我们再来看看它到底有多可怕。我们把它总结为“三宗罪”,每一条都可能引发线上的生产事故。

第一罪:网络阻塞。想象一下,你的Redis服务器和客户端之间的网络带宽就像一根水管。当你请求一个几十MB的大Key时,就相当于把一块巨石塞进了水管,瞬间把它堵死了。在这期间,其他所有正常的、微小的请求,比如点赞、获取用户信息等,全都被堵在后面,导致整个服务响应极其缓慢。
第二罪:命令阻塞。这是最致命的一点。Redis处理所有命令是单线程的。当你删除一个大Key时,Redis需要释放它占用的庞大内存,这个过程非常耗时,而且无法中断。在这几秒甚至更长的时间里,Redis就像被点了“葵花点穴手”,无法响应任何其他命令。你的业务看起来就像“卡死”了一样。

第三罪:集群迁移困难。在Redis Cluster集群模式下,数据是分布在不同slot(槽)里的。一个Key只能属于一个slot。如果你的一个Key巨大无比,当你想对集群进行扩容或缩容,需要迁移slot时,这个“巨无霸”Key就会成为迁移的拦路虎,导致迁移过程极其缓慢,甚至失败。
如何发现大Key
既然大Key危害这么大,我们怎么在它“引爆”之前找到它呢?这里有三种常用的侦察手段:
redis-cli --bigkeys:这是Redis自带的一个工具,简单好用。它会对整个实例进行扫描,并告诉你每种数据类型里“最大”的那个Key是什么。它的优点是方便,对性能影响小;缺点是信息不够全面,它只告诉你“山顶”在哪,但山腰上其他的大石头它就不管了。适合做初步排查。
MEMORY USAGE 命令:这是一个非常精准的命令,可以告诉你一个Key到底占用了多少字节的内存。但请大家看屏幕上的警告,这个命令本身在计算大Key时,也可能导致阻塞!所以,千万不要在生产环境对未知的Key随意使用,否则你可能亲手制造一次阻塞。
最佳实践:监控与巡检。这是最靠谱、最安全的方式。我们可以写一个脚本,定期地、分批地用 SCAN 命令遍历所有的Key,然后结合 STRLEN、HLEN 这些命令去检查每个Key的大小和元素数量。一旦超过我们设定的阈值,就立刻报警。这样就能做到防患于未然。
如何安全删除
好,现在我们发现了大Key,要怎么删掉它呢?直接一个 DEL 命令?千万不要!那相当于引爆炸弹。我们要用“温柔删除法”。

对于String类型:如果它本身就不该存在Redis里,比如是静态文件,最好的办法是把它迁移到对象存储(如OSS或S3),Redis里只存它的URL。

对于Hash或Set:核心思想是分批次删除。我们用 HSCAN 或 SSCAN 命令,每次只获取100个元素,然后用 HDEL 或 SREM 把这100个删掉,然后根据返回的游标继续下一轮,直到整个Key被删完。

对于List:我们可以用 LTRIM 命令,它像一个裁纸刀。比如一个List有10万个元素,我们执行 LTRIM mylist 100 -1,就相当于把前100个元素裁掉,只保留后面的。我们循环执行这个操作,每次都能“温柔”地砍掉一小部分,直到列表为空。
这些“温柔删除法”的精髓,就是把一次大的、耗时的删除操作,分解成无数次微小的、快速的删除,避免长时间阻塞Redis。
如何预防
处理大Key只是亡羊补牢,最高级的策略是从设计上就杜绝它。

分片 (Sharding):比如一个用户有50万粉丝,不要把这50万ID全放在一个Set里。我们可以根据用户ID取模,把粉丝分散到10个或100个小的Set里。followers:12345 变成 followers:12345:0、followers:12345:1 ... 这样每个Key都不大。
拆分 (Splitting):对于超大的String,比如一篇20MB的文章,我们可以把它切成4个5MB的块,分别存为 article:1001:part1, article:1001:part2... 读取的时候再拼起来。
设置合理的过期时间:这是最简单,也最容易被忽略的一点。对于那些可能会无限增长的数据,比如日志、用户行为记录等,一定要给它们设置一个合理的过期时间(EXPIRE),让Redis自动帮你清理,防止数据无限堆积。
为什么删除大Key会阻塞?

现在,我们来到了今天最核心的一张幻灯片。 为什么删除大Key会阻塞?前面我们提到了——因为Redis是单线程的。
大家请看屏幕上的这个动画。
[指着动画讲解]
左边这个红色的、巨大的 DEL big_key 任务,代表着删除大Key的操作。它一旦开始执行,就占用了Redis唯一的工作线程。
而它后面,排着一长串绿色的、微小的任务,比如 GET、SET、INCR。它们本身执行起来非常快,可能只需要几微秒。但是,因为前面的“大块头”挡住了路,它们只能在后面焦急地排队、等待。
这就是阻塞的本质! 在删除大Key的那几秒钟里,后续所有命令都得干等着,整个服务对外看起来就是“卡死了”。
而我们前面讲的 HSCAN 这类“温柔删除法”,它的聪明之处就在于,它把一个大的删除任务,拆解成了N个微小的删除任务。每次执行完一个小删除,就会把线程让出来,让队列后面的其他命令有机会执行。这样,虽然总的删除时间可能更长,但服务在宏观上是持续可用的,不会出现长时间的“假死”现象。
总结
好了,我们来总结一下今天的内容,并聊聊面试官问你大Key问题时,他到底想考察什么。
核心知识点回顾:
定义:不仅看体积,更看元素数量。
危害:网络阻塞、命令阻塞、集群迁移困难。
发现:--bigkeys做初筛,SCAN+监控做巡检。
处理:核心是渐进式删除,比如用SCAN或LTRIM。
预防:从设计入手,做好分片、拆分,并一定记得设置过期时间。
原理:关键在于理解Redis的单线程模型。
当你能在面试中,把这些点清晰、有条理地讲出来时,面试官想考察的其实是:
你是否真正理解Redis的底层工作原理(单线程)。
你是否具备线上问题的排查和解决能力。
你是否具备良好的系统设计能力,懂得预防问题而不是等问题发生。
最后,你对Redis的掌握,是停留在API调用层面,还是已经深入到了原理和最佳实践的层面。
掌握了这些,你不仅能解决实际工作中的棘手问题,更能向面试官充分展示你作为一名优秀工程师的技术深度。