Redis里头key是咋找的,底层原理和机制大概聊聊
- 问答
- 2026-01-08 22:19:21
- 5
聊Redis怎么找key,说白了就是聊你给Redis一个键的名字,user:1001:profile”,它是怎么在它那庞大的内存数据库里,咻的一下把对应的值给找出来的,这个过程的快慢直接决定了Redis为什么能那么“飞起”,核心秘密就在于它用了两种主要的数据结构来组织这些键:哈希表 和 字典,咱们一步一步拆开看。
最基础、最核心的玩意儿叫哈希表,你可以把它想象成一个有很多个抽屉的柜子,Redis在启动的时候,就会初始化一个这样的“大柜子”,当你设置一个键值对时,SET user:1001:profile "{...}",Redis并不是随便找个空地方就塞进去的,它会对键的名字“user:1001:profile”进行一个运算,这个运算叫哈希函数(来源:Redis设计与实现),这个哈希函数的作用很神奇,不管你输入多长的字符串,它都会算出一个固定长度的、看起来像乱码的数字,这个数字,就代表了它应该放在哪个“抽屉”里,这个“抽屉”在技术上的名字叫哈希桶。
查找的过程就反过来了:你要找“user:1001:profile”这个键,Redis同样用这个哈希函数算一下,得到一个数字,然后直接“导航”到对应的那个抽屉里去找,理想情况下,这个抽屉里只有它一个,一下子就找到了,这就像你知道图书馆某本书的精确编号,直接去那个书架拿,而不是从第一排书架开始一本一本翻,这就是哈希表为什么查找速度极快,理论上接近O(1)的原因(来源:通用数据结构知识)。

问题来了,万一两个不同的键,user:1001:profile”和“article:2024:title”,经过哈希函数计算后,很不巧地得到了同一个数字(也就是指向了同一个抽屉),这该怎么办?这种情况就叫哈希冲突,Redis解决哈希冲突的方法很经典,叫链地址法,就是说,那个“抽屉”不是一个只能放一个东西的格子,而是一个链表的头,如果两个键撞到同一个桶里,Redis就把它们用一根“链子”串起来,都挂在这个抽屉下面,查找的时候,先找到正确的抽屉,然后顺着这条小小的链子一个一个对比键的名字,直到找到完全匹配的那个为止。
查找性能的关键就变成了:这个哈希表“柜子”的抽屉够不够多?以及每个抽屉下面的链子平均来说长不长?如果键的数量越来越多,链子就会越来越长,查找就要在链子上遍历更多次,速度就会慢下来。

这就引出了第二个重要机制:渐进式Rehash,当Redis发现哈希表已经太拥挤了(比如链子的平均长度太长了),它就需要扩容,也就是换一个抽屉更多、更大的新柜子,但Redis是单线程的,它不可能停下来服务,把几百万个键一次性全部从旧柜子搬到新柜子,那会卡住很久,所以它用了一个非常巧妙的“渐进式”方法(来源:Redis官方文档)。
具体是这么干的:Redis会同时准备两个哈希表,一个旧的,一个新的(更大),在需要扩容的时候,它并不急着立刻搬家,而是开始一个“慢慢搬”的过程,每当有新的查找、更新、删除请求来时,Redis除了处理这个请求本身,还会“顺便”从旧表里把一到两个键值对搬移到新表里,你来查找“user:1001:profile”,Redis会先在旧表里找到它,返回给你值,然后悄悄把这个键值对复制到新表里,并在旧表里做个标记,如果有新的写入请求,Redis会直接写到新表里,保证旧表的数据只减不增,这样,经过一段时间,所有活跃的、被访问到的键都会被逐渐迁移过去,当旧表完全清空时,Redis就把旧表扔掉,把新表设为当前使用的表,这个过程是平缓的,对用户来说几乎无感。
除了这个全局的键空间字典,Redis的某些特定功能也利用了类似的思想,比如当你使用 HSET 命令操作一个哈希键(Hash)时,这个哈希键本身 field 和 value 的映射,在数据量小的时候用一种更紧凑的结构(ziplist)存储,但当数据量变大后,其内部也会转换成一个小的哈希表结构来保证 field 的快速查找。
Redis找key的核心就是哈希表这把“万能钥匙”,它通过哈希函数实现快速定位,用链地址法解决冲突,再用渐进式Rehash在后台悄无声息地完成扩容,从而在绝大多数情况下,都能以近乎瞬时的速度找到你想要的那个key,这一切设计,都是为了实现其作为内存数据库最根本的目标:快。
本文由革姣丽于2026-01-08发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/77067.html
