问题: Redis 支持哪些核心数据类型?请分别说明 String、List、Hash、Set、ZSet 的底层实现(如 SDS、quicklist、ziplist、跳表等),并各举一个典型应用场景。

👇 点击展开/折叠 面试背诵模板(建议先背这个) Redis 支持 String、List、Hash、Set、ZSet 五种核心数据类型。String 底层为 SDS(简单动态字符串),支持预分配内存,用于缓存对象和计数器;List 底层为 quicklist(双向链表 + ziplist 组合),用于消息队列和最新消息列表;Hash 底层为 ziplist(小数据量)或 hashtable(大数据量),用于存储对象属性;Set 底层为 intset(整数集合)或 hashtable,用于去重、共同好友和标签系统;ZSet 底层为 ziplist(小数据量)或 skiplist + dict(大数据量),跳表保证有序查找 O(log N),用于排行榜和延迟队列。不同编码根据数据规模动态切换,兼顾内存效率与性能。
---

各数据类型底层实现详解

① String(字符串)—— SDS

  • 不再使用 C 字符串,而是自定义 SDS(Simple Dynamic String),包含长度字段和预分配空间,获取长度 O(1),杜绝缓冲区溢出
  • 典型应用:缓存 HTML 片段、分布式锁、计数器(INCR 命令)

② List(列表)—— quicklist(3.2 版本后)

  • 由双向链表和 ziplist 组合而成,每个节点是一个 ziplist,既解决了链表内存碎片问题,又解决了普通 ziplist 更新时大规模搬迁的性能问题
  • 典型应用:用户最新消息列表(LPUSH + LRANGE)、阻塞队列(BRPOP)

③ Hash(哈希)—— ziplist / hashtable

  • 字段少且值短时使用 ziplist(连续内存,节省空间),字段多或值大时转为哈希表(O(1) 读写)
  • 典型应用:存储用户基本信息(如 hset user:1001 name "tom" age 25)、购物车

④ Set(集合)—— intset / hashtable

  • 全是整数且数量少时用 intset(有序整数数组,二分查找),否则用哈希表
  • 典型应用:抽奖去重、共同好友(SINTER 交集)、用户标签

⑤ ZSet(有序集合)—— ziplist / skiplist + dict

  • 数据少时用 ziplist 节省内存,数据多时用跳跃表 + 字典组合:字典提供 O(1) 按值查分值的功能,跳表提供按分值排序和范围查询 O(log N) 功能
  • 典型应用:排行榜(按分数排序)、延迟队列(按时间戳排序)

编码转换触发阈值(面试高频补充)

数据类型 编码转换条件 说明
Hash hash-max-ziplist-entries(默认 512)或 hash-max-ziplist-value(默认 64 字节) 任一超过阈值则从 ziplist 转 hashtable
ZSet zset-max-ziplist-entries(默认 128)或 zset-max-ziplist-value(默认 64 字节) 任一超过阈值则从 ziplist 转 skiplist + dict
Set set-max-intset-entries(默认 512) 元素超过 512 个或包含非整数则转 hashtable
List list-max-ziplist-size 相关配置 quicklist 中每个 ziplist 节点大小由配置控制,不涉及整体类型转换

时间复杂度速查表(面试加分)

数据类型 核心操作 时间复杂度 底层依赖
String GET/SET O(1) SDS 直接寻址
List LPUSH/RPOP O(1) quicklist 头尾操作
Hash HGET/HSET O(1) hashtable(或 ziplist 的 O(N) 但 N 很小)
Set SADD/SISMEMBER O(1) hashtable
ZSet ZADD/ZRANK O(log N) 跳表查找

场景选择建议

  • 需要计数器、分布式锁 → String
  • 需要按顺序消费、最新列表 → List
  • 需要存储对象属性且需单独修改某字段 → Hash
  • 需要去重、交并补集运算 → Set
  • 需要排序、范围查找、按分数聚合 → ZSet