# Redis 的 hash 是什么?
6 min read
Table of Contents
Redis 的 hash 是什么?
Redis Hash 面试标准答案
【核心定义】
Redis Hash 是一个基于哈希表实现的、用于存储字段-值对(field-value pairs)的复合数据结构,它提供了高效的字段级操作能力。
【关键要点】
- 数据结构本质:Redis Hash 底层采用两种编码方式——
ziplist(压缩列表)和hashtable(哈希表),根据数据量和元素大小自动切换。 - 核心特性:支持对单个字段的独立读写,而不需要操作整个对象,特别适合存储对象属性。
- 操作效率:大多数操作(如 HGET、HSET)的时间复杂度为 O(1),与字段数量无关。
- 内存优化:小哈希对象使用 ziplist 编码,通过紧凑存储减少内存碎片和开销。
- 线程安全:Redis 单线程模型保证了所有操作的原子性,无需额外同步机制。
【深度推导/细节】
编码转换机制(核心优化逻辑)
Step 1 - 初始创建:新创建的 Hash 对象默认使用 ziplist 编码。
- ziplist 结构:连续内存块,按顺序存储 field-value 对
- 优势:内存紧凑,无指针开销,适合小数据量
Step 2 - 转换触发条件(Redis 配置项):
hash-max-ziplist-entries(默认 512):当字段数量超过此值时转换hash-max-ziplist-value(默认 64 字节):当任意字段或值的长度超过此值时转换
Step 3 - 转换过程:
- 创建新的哈希表(dict 结构)
- 遍历 ziplist 中的所有 field-value 对
- 将每对数据插入哈希表
- 释放原 ziplist 内存,更新对象编码为
hashtable
哈希表扩容机制
冲突解决:采用链地址法(separate chaining) 扩容触发:当负载因子(元素数/桶数)达到 1 时,且当前没有进行 BGSAVE/BGREWRITEAOF 扩容大小:扩容为当前已使用桶数的 2 倍(最接近的 2^n)
【关联/对比】
Redis Hash vs. Java HashMap
| 维度 | Redis Hash | Java HashMap |
|---|---|---|
| 线程安全 | 单线程天然安全 | 非线程安全,ConcurrentHashMap 安全 |
| 扩容时机 | 负载因子=1(更保守) | 负载因子=0.75(更激进) |
| 冲突解决 | 链地址法 | 链表+红黑树(JDK8+) |
| 内存管理 | 自动编码转换 | 固定数组+链表/树结构 |
Redis Hash vs. String 存储对象
- Hash 优势:字段级更新节省网络传输,内存更高效(共享 field 名)
- String 优势:序列化整个对象,读取时一次获取全部属性
『面试官追问』
-
为什么小哈希要用 ziplist?大哈希要用 hashtable?
- ziplist:内存连续,CPU缓存友好,但插入/查找 O(n)
- hashtable:O(1) 操作,但指针开销大(每个 entry 3个指针)
- 权衡点:512个字段和64字节长度是经验值,平衡内存与CPU
-
Hash 的渐进式rehash过程是怎样的?
- 维护两个哈希表(ht[0], ht[1])
- 每次操作迁移一个桶(渐进式)
- 查找时先查ht[0],再查ht[1]
- 新增直接写入ht[1]
-
HSET 和 HMSET 的区别?HMSET 在 Redis 4.0+ 的变化?
- HSET:单字段设置,返回 1(新增)或 0(更新)
- HMSET:多字段设置,始终返回 OK
- Redis 4.0+:HSET 支持多字段,HMSET 被标记为弃用
-
Hash 适合存储什么类型的数据?
- 用户会话(session)
- 对象属性(用户信息、商品属性)
- 计数器组(多个相关计数器)
- 不适合:需要整体序列化的场景
-
Hash 的最大长度限制?
- 理论最大字段数:2^32 - 1 个(约42.9亿)
- 实际限制:可用内存大小
- 单个 value 最大 512MB(Redis 字符串限制)
【版本差异】
- Redis 2.6-:HSET 只支持单字段,HMSET 必须使用
- Redis 4.0+:HSET 支持多字段,HMSET 标记为弃用
- Redis 6.0+:优化内存分配,更好的碎片整理
- Redis 7.0+:listpack 逐步替代 ziplist(更安全的内存布局)
【最佳实践建议】
- 控制单个 Hash 的字段数,避免超大 Hash 影响迁移效率
- 字段名尽量简短(ziplist 编码时更省内存)
- 批量操作使用 pipeline 减少网络往返
- 监控 bigkey,避免单个 Hash 过大影响集群迁移