Redis里Hash到底是咋实现的,底层原理那些事儿浅谈一下
- 问答
- 2025-12-23 21:31:19
- 1
关于Redis里Hash到底是咋实现的,咱们得先明白一个核心点:它并不是一成不变的,Redis的作者们为了在内存使用和性能之间找到最佳平衡,给Hash类型设计了两种底层的编码格式,你可以理解为两种不同的“内部储物方式”,它会根据你存入的数据情况,智能地选择用哪一种,这两种格式分别叫ziplist(压缩列表) 和 hashtable(哈希表)。(来源:Redis官方文档关于内存优化的章节)
第一种情况:当Hash还很小的时候,用ziplist(压缩列表)
你可以把ziplist想象成一个非常节俭的、把所有东西都紧紧打包在一起的“行李箱”,这个行李箱不是像普通列表那样一个个格子分开的,而是一大块连续的内存空间,当你往一个小的Hash里设置字段和值,比如执行 HSET myhash name "张三" age 25,Redis就会把“name”、“张三”、“age”、“25”这四个元素,按照顺序一个挨一个地塞进这个连续的内存块里。
这么做最大的好处就是省内存,因为如果是用真正的哈希表,它需要维护很多额外的结构信息,比如指针之类的,这些本身就要占地方,而ziplist几乎去掉了所有“装饰性”的东西,只保留最核心的数据,所以非常紧凑,但它的缺点也很明显:因为数据是紧挨着的,如果要查找中间某个字段,或者修改一个长度变化的值,可能就需要重新分配内存和移动数据,性能会比较差,这只在东西少的时候划算。
那什么时候算“小”呢?Redis给了两个配置参数让你自己定(来源:redis.conf配置文件中的默认值):

hash-max-ziplist-entries:默认是512,意思是,如果Hash中的字段数量不超过512个,就考虑用ziplist。hash-max-ziplist-value:默认是64字节,意思是,如果每个字段的值(比如上面的“张三”这个字符串)的长度都不超过64字节,就考虑用ziplist。
只有同时满足这两个条件,Redis才会使用ziplist来存储这个Hash。
第二种情况:当Hash变大时,自动切换成hashtable(哈希表)
一旦你不停地往Hash里塞数据,字段数超过了512,或者你存了一个超长的字符串(比如一篇长文),上面说的那两个条件任何一个被打破,Redis就会触发一个“变身”过程,它会把这个Hash的底层结构从ziplist转换成真正的hashtable。

这个hashtable就是咱们平时说的“字典”或者“映射”这种数据结构,它就像是带索引的文件柜,这个文件柜有很多个小格子(术语叫“桶”或“槽”),当你存一个字段值对时,Redis会用一个函数(哈希函数)算一下字段名(key)的哈希值,然后根据这个值决定把它放到哪个格子里,这样当你要查找的时候,HGET myhash name,Redis再用同样的函数算一下“name”的哈希值,就能直接定位到那个格子,查询速度非常快,基本上是瞬间完成(O(1)时间复杂度)。
这种方式的优点是增删改查的效率极高,非常适用于字段数量多或者值很大的场景,但缺点就是比ziplist更占内存,因为它需要维护这个“文件柜”的索引结构本身。
总结一下底层原理那些事儿:
- 动态切换:Redis的Hash不是死板的,它像个智能管家,在你数据量小的时候,为了帮你省内存,它用紧凑的ziplist打包,一旦数据量上来了,为了追求极致的速度,它就自动升级成高效的hashtable。
- 权衡之道:这个设计的精髓就是在时间和空间之间做权衡,用小内存成本(ziplist)换慢操作,还是用大内存成本(hashtable)换快操作?Redis根据你的实际数据帮你做决定。
- 可配置性:你可以通过修改前面提到的那两个配置参数(hash-max-ziplist-entries和hash-max-ziplist-value),来调整“大小”的判定标准,比如你的机器内存特别紧张,但可以接受一点性能损失,你就可以把这两个值调大,让更多的Hash使用ziplist格式,反之,如果你追求极致性能,就可以把它们调小,让Hash更早地切换成hashtable。
下次你用Redis的Hash时,心里就可以有个数了:你眼前这个简单的Hash命令背后,Redis其实在默默地、智能地为你选择最优的存储方案。
本文由度秀梅于2025-12-23发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://www.haoid.cn/wenda/67150.html
