Hash 对象建模

Redis Hash 对象存储

使用 Redis Hash 为复杂业务对象建模。学习用户资料、产品目录和配置管理的高效数据建模。

真实业务场景

某社交平台存储包含 15+ 字段(姓名、简介、头像、设置、统计数据)的用户资料。使用单个 JSON 字符串意味着每次读写都要反序列化整个对象。使用 Redis Hash,每个字段都可以独立访问——更新用户的在线状态而无需触及其资料数据。这减少了带宽,简化了部分更新,并通过 Redis 的 ziplist 编码(针对小 Hash)提高了内存效率。

架构图

应用层
↓ HSET / HGET / HINCRBY
┌──────────────────────────────────────┐
│ Redis Hash: user:{id} │
│ ┌──────────────────────────────────┐ │
│ │ name → "Alice" │ │
│ │ email → "alice@example.com" │ │
│ │ avatar → "https://cdn/a.jpg" │ │
│ │ bio → "Software Engineer" │ │
│ │ followers → 1024 │ │
│ │ following → 256 │ │
│ │ status → "online" │ │
│ │ lastLogin → 1737000000 │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────┘
↓ 定期同步
PostgreSQL (持久化存储)

关键命令解析

性能分析

HSET/HGET: 每个字段 O(1)。无论 Hash 大小如何,时间恒定。
Ziplist 编码: 字段数 ≤128 且值 ≤64 字节的 Hash 使用 ziplist——比单独的 key 节省 10 倍内存。
内存对比: 100万用户 × 8 字段作为 Hash ≈ 1.2GB vs 100万用户 × 8 个单独 STRING key ≈ 4.8GB。节省 4 倍空间。
HINCRBY: 原子 O(1) 递增。无需读-改-写循环。每秒处理 10万+ 并发计数器更新。

常见陷阱

超出 ziplist 阈值: 字段数 >128 或值 >64 字节的 Hash 会切换到 hashtable 编码,使用更多内存。保持字段紧凑。
对大 Hash 使用 HGETALL: 如果 Hash 有 1000+ 字段,HGETALL 会在序列化时阻塞 Redis。对大 Hash 改用 HSCAN。
嵌套对象: Redis Hash 是扁平的(string → string)。不要尝试嵌套 Hash。将嵌套数据序列化为单字段中的 JSON,或使用单独的 key。
无单独字段 TTL: Redis TTL 适用于整个 key,而非单个字段。如果需要字段级过期,请使用单独的 key 或在应用代码中管理清理。

最佳实践

保持 Hash 字段在 128 个以内且值在 64 字节以内,以利用 ziplist 编码。
使用 HINCRBY 进行计数,而不是 GET → increment → SET,以避免竞态条件。
优先使用 HMGET 而非多次 HGET 调用,以减少网络往返。
使用一致的命名:user:{id}, product:{sku}, config:{service}。
如果访问模式差异显著,将热字段(status, lastSeen)与冷字段(bio, settings)分离到不同的 Hash 中。
对于可能增长超过 100 个字段的 Hash,使用 HSCAN 代替 HGETALL。

可运行演示

Redis Demo
Click "Step" or "Run All" to execute commands...

在我们的 Redis 在线编辑器中尝试这些命令