极高 进阶
Redis数据结构与底层实现#
一句话答案#
五种基本类型:String(SDS)、List(quicklist)、Hash(listpack/hashtable)、Set(intset/listpack/hashtable)、ZSet(listpack/skiplist+hashtable)。Redis 7.0 起 Hash/ZSet/List 内部用 listpack 替代 ziplist,7.2 起 Set 新增 listpack 编码。
核心要点
| 类型 | 底层编码 | 典型场景 |
|---|---|---|
| String | SDS(简单动态字符串) | 缓存对象、计数器、分布式锁、Session 存储 |
| Hash | listpack(小量)/ hashtable(大量) | 对象属性存储(用户信息)、购物车 |
| List | listpack(小量)/ quicklist(大量) | 消息队列、最新动态列表、任务队列 |
| Set | intset(小量且全整数)/ listpack(小量混合类型,7.2+)/ hashtable(大量) | 去重(用户抽奖、UV 统计)、共同好友、标签 |
| ZSet(SortedSet) | listpack(小量)/ skiplist+hashtable(大量) | 实时排行榜、延迟队列、带权重的优先级队列 |
各类型典型命令与场景:
String:
SET key value EX 60 # 缓存,60s 过期
INCR page_views # 原子计数器
SETNX lock_key uuid # 分布式锁(原子性加锁)bashHash:
HSET user:1001 name "Alice" age 25 city "Beijing"
HGET user:1001 name
# 优势:比 String 存 JSON 更节省内存,支持单字段更新bashList:
LPUSH queue task1 # 生产者左推
BRPOP queue 0 # 消费者右取(阻塞等待)
LRANGE feed:1001 0 9 # 最新 10 条 Feed 流bashSet:
SADD lottery:users user1 user2 # 参与抽奖
SRANDMEMBER lottery:users 1 # 随机抽取1人
SINTER follows:A follows:B # A 和 B 的共同关注bashZSet:
ZADD leaderboard 1000 user1 900 user2 # 排行榜写入
ZREVRANGE leaderboard 0 9 WITHSCORES # 取 top10
ZADD delay_queue <timestamp> task_id # 延迟队列(score=执行时间戳)bash面试回答(2分钟版)
Redis有五种基本数据类型,每种底层都有不同的编码实现。String底层用SDS而非C字符串,SDS有len字段实现O(1)取长度,还能二进制安全和预分配空间减少内存重分配。List在3.2之后用quicklist实现,本质是ziplist组成的双向链表。Hash在元素少于128个且单个元素小于64字节时用listpack紧凑编码,超过阈值自动转为hashtable。Set在元素全为整数且数量小时用intset紧凑编码,Redis 7.2起小集合还支持listpack编码,超过阈值转为hashtable。ZSet最特殊,同时使用skiplist和hashtable两种结构,skiplist支持有序范围查询,hashtable支持O(1)按成员查分数。这种设计的核心思路是”小数据用紧凑编码省内存,大数据转高效结构保性能”,编码转换对使用者透明,Redis会根据数据量自动选择最优编码。
追问与易错
追问方向:
- “ZSet 为什么用跳表不用红黑树?”→ 跳表实现简单(插入删除只需调整指针+随机层数),范围查询天然友好(找到起点后沿链表顺序遍历),内存分配更灵活;红黑树需要复杂的旋转操作,范围查询要中序遍历效率低
- “String 能存多大?”→ 最大 512MB,但生产环境建议单个 value 不超过 10KB;过大的 String 会阻塞单线程、增加网络传输耗时、触发大 Key 问题
- “Hash 什么时候从 listpack 转为 hashtable?”→ 元素数量超过 128(hash-max-listpack-entries)或单个元素超过 64 字节(hash-max-listpack-value)时自动转换;Redis 7.0 前用 ziplist,7.0+ 改为 listpack
- “Set 有几种编码?”→ 三种:intset 用于全整数小集合(紧凑有序数组);Redis 7.2+ 新增 listpack 编码用于小集合混合类型;超过阈值转为 hashtable
易错点:
- ❌ “Redis 的 List 就是链表”——3.2+ 是 quicklist(ziplist/listpack 组成的双向链表)
- ❌ 忽略底层编码的自动转换——小数据量用紧凑编码,超过阈值自动转