数据结构与内部编码
用途:选型“这个数据该用什么结构存”、解释内存占用异常
对外类型与内部编码
「对外类型与内部编码」小节链接| 类型 | 常用内部编码 | 说明 |
|---|---|---|
| String | int / embstr(≤44B)/ raw |
短字符串共享对象头,省内存 |
| Hash | listpack(小)/ hashtable |
元素少且短用紧凑编码,超过阈值转换 |
| List | listpack / quicklist(双向链表 + listpack 节点) |
兼顾插入与内存 |
| Set | intset / hashtable |
整数集合紧凑存储 |
| ZSet | listpack / skiplist + hashtable |
跳表支持范围查询,哈希支持按成员取分值 |
| Stream | radix tree(listpack 节点) | 追加型日志结构,支持消费者组 |
| 特殊 | HyperLogLog、Bitmap、GeoSet、Module 类型 | HLL 是概率结构,有误差率 |
阈值参数:hash-max-listpack-entries/value、zset-max-listpack-* 等。编码转换单向(转成大结构后不会自动转回),因此设计 key 时要控制单 key 元素数量。
选型速查
「选型速查」小节链接| 需求 | 结构 | 要点 |
|---|---|---|
| 对象缓存 | String(序列化 JSON) | 注意大 value 与序列化开销 |
| 部分字段更新 | Hash | 可 HINCRBY、HGET 单字段,避免整体读写 |
| 排行榜 / 延时队列 | ZSet | 分值排序,ZRANGEBYSCORE 取区间 |
| 去重集合 / 标签 | Set | SINTER/SDIFF 做交并差 |
| 计数 / 唯一性判断 | String + INCR / Set |
注意过期与分片计数 |
| 概率去重统计 | HyperLogLog | 12KB 级别估算基数,误差约 0.81% |
| 布尔状态位图 | Bitmap | 签到、活跃标记,BITCOUNT 聚合 |
| 消息流与消费位点 | Stream | 有 ID、可回溯、支持消费者组与 ACK |
| 分布式限流 | ZSet(滑动窗口)或 String + Lua | 原子性用 Lua 保证 |
内存去哪了
「内存去哪了」小节链接INFO memory 与 MEMORY USAGE key、MEMORY DOCTOR、--bigkeys / --hotkeys 是排查入口。常见放大来源:
- key 本身占内存:冗长前缀、把业务字段拼进 key。
- 编码转换:Hash 元素超过阈值转 hashtable,指针开销显著。
- 过期数据未回收:惰性删除 + 定期采样删除,大量 key 同时过期会造成内存不降与延迟毛刺(需要
active-expire-effort或分批过期)。 - 客户端输出缓冲区:大 key 批量读取会撑高
mem_clients_normal。 - 碎片率:
mem_fragmentation_ratio高(>1.5)时考虑重启整理或activedefrag。
设计原则
「设计原则」小节链接- 单 key 元素数上限(经验:集合类 < 5000,value < 10KB),大 key 会放大网络、序列化与迁移代价。
- key 命名分层:
业务:域:标识,便于扫描、统计与 TTL 治理。 - 必须设 TTL:无过期时间的 key 是内存泄漏的主要来源;缓存类尤其如此。
- 热点结构分片:单个高并发计数 key 拆成 N 个(
counter:{shard})读时求和。
常见误区
「常见误区」小节链接| 误区 | 修正 |
|---|---|
用 KEYS * 找 key |
阻塞主线程,用 SCAN 游标 |
| 把 Redis 当持久化数据库 | 语义与可靠性模型不匹配,需 DB 兜底 |
| 大 Hash 当“表”存百万字段 | 单 key 巨大,迁移与删除代价高,应拆分 |
| 只监控命中率不监控大 key/碎片 | 故障常来自内存与延迟,不是命中率 |
以为 DEL 立即释放内存 |
大 key 删除阻塞,用 UNLINK 异步释放 |
延伸阅读
「延伸阅读」小节链接- Redis 官方文档:Data types、Internal encoding、Memory optimization
- 《Redis 设计与实现》(黄健宏)数据结构章节