646 字
3 分钟
Redis 数据类型和底层编码有什么区别?
  1. 1Redis 系列导读:知识地图、必会主线与复习顺序
  2. 2Redis 中常见的数据类型有哪些?
  3. 3Redis 通常应用于哪些场景?
  4. 4Redis为什么这么快?
  5. 5Redis 常用的过期时间、删除 Key 命令有哪些?
  6. 6Redis 的过期 Key 是如何被删除的?
  7. 7Redis 内存满了怎么办?有哪些淘汰策略?
  8. 8缓存穿透、击穿、雪崩的区别与解决方案
  9. 9Redis 如何保证缓存与数据库的数据一致性?
  10. 10Redis 的持久化机制有哪些?
  11. 11Redis 主从复制的完整流程是什么?
  12. 12Redis 的哨兵机制是什么?
  13. 13Redis Cluster 模式与 Sentinel 模式的区别是什么?
  14. 14Redis 支持事务吗?如何实现?
  15. 15Redis 中如何实现分布式锁?
  16. 16Redis 的 Lua 脚本功能是什么?如何使用?
  17. 17如何解决 Redis 中的热点 Key 问题?
  18. 18Redis BigKey 有什么危害?如何发现和治理?
  19. 19为什么 Redis 设计为单线程?6.0 版本为何引入多线程?
  20. 20Redis 的 LRU 和 LFU 有什么区别?
  21. 21Redis 数据类型和底层编码有什么区别?本文
  22. 22Redis 中跳表的实现原理是什么?
  23. 23Redis 的 ZSet 为什么使用跳表,而不是平衡树?
  24. 24Redis 的 RDB 快照如何生成?为什么会有写时复制?
  25. 25Redis 的 AOF 刷盘和重写有什么区别?
  26. 26Redis 断线后如何通过 PSYNC 部分重同步?
  27. 27Redis 主从切换为什么会丢数据?WAIT 能解决吗?
  28. 28Redis 集群会出现脑裂问题吗?
  29. 29Redisson 看门狗(watch dog)机制了解吗?
  30. 30Redis Cluster:哈希槽、Gossip 与故障转移
  31. 31Redis Pipeline 为什么能提高吞吐?能保证原子性吗?
  32. 32Redis 的 SCAN 和 KEYS 有什么区别?
  33. 33Redis 变慢时如何排查?SLOWLOG 能看到所有耗时吗?
  34. 34Redis 和 MySQL 有什么区别?
  35. 35Redis 为什么使用 SDS,而不是 C 字符串?
  36. 36Redis 的哈希表如何处理冲突和渐进式 rehash?
  37. 37Redis Cluster 的 MOVED 和 ASK 重定向有什么区别?
  38. 38Redis Cluster 为什么会报 CROSSSLOT?Hash Tag 怎么用?
  39. 39Redis 如何实现限流?固定窗口和滑动窗口怎么选?
  40. 40Redis Stream 如何保证消息消费?ACK 和 PEL 是什么?
  41. 41Redis 删除数据后为什么内存不下降?如何理解内存碎片?

String、Hash、List、Set、ZSet 是面向命令使用者的逻辑类型;int、raw、listpack、hashtable 等是内部存储编码。同一种类型可以根据元素数量和长度选择不同编码,以减少小对象内存成本或提高大对象操作效率。 具体实现会随版本变化,本文以 Redis 7.2 的常见路径为例。

常见类型如何存储?#

类型常见内部形式
String可用整数编码;短字符串可用 embstr;其他字符串常用 raw/SDS
Hash较小对象可用 listpack,超过配置条件转为哈希表
List以 quicklist 组织节点,节点常使用 listpack 存放元素
Set可用 intset、listpack 或哈希表,取决于版本和内容
ZSet小对象可用 listpack,大对象常用字典与跳表配合

早期资料常把 Hash/ZSet 小对象说成 ziplist。Redis 7.x 的主流实现已经使用 listpack,不能跨版本背诵固定结论。Redis 7.2 也有小 Set 的 listpack 路径,因此“Set 永远只有 intset 与哈希表”不是所有版本都准确。

为什么不一直用紧凑编码?#

listpack 把多个元素紧凑地放在连续内存中,减少指针和分配开销,也改善局部性。但查找或插入可能需要扫描、移动数据。元素少时节省内存更划算,元素多时则需要可扩展的数据结构。

可以用 TYPE key 查看逻辑类型,用 OBJECT ENCODING key 观察当前编码,用 MEMORY USAGE key 估算单 Key 的内存。转换阈值由类型相关配置控制;编码转换会改变成本,不应随意把阈值调得很大来追求内存数字好看。

常见追问#

Hash 转成哈希表后,删小了会自动变回吗?#

不能普遍假设自动回退。不同类型和版本转换策略不同,常见 Hash 增长转换不自动反向压缩;应观察实际编码。

embstr 和 raw 是两种不同业务类型吗?#

不是,它们都属于 String,只是对象头与字符串存储的内存组织方式不同,命令语义仍由 String 类型定义。

ZSet 为什么同时需要字典和跳表?#

字典方便按成员查分数,跳表方便按分数排序、排名与范围遍历。两种结构服务于不同访问路径。

知道编码对项目有什么帮助?#

可以解释大量小对象的内存开销、编码转换后的延迟变化,以及为什么一个巨大 Hash 并不总比拆分后的 Key 更合适。

Redis 数据类型和底层编码有什么区别?
https://blog.xqcherry.top/posts/interview/redis/redis-internal-encodings/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0