Files
autumn-recruitment/03.Redis/core/Redis 五大核心数据结构_test.md
T

149 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
tags: [test/review, redis, data-structures, sds, quicklist, skiplist]
create time: 2026-08-09 12:00
---
# Redis 五大核心数据结构_测试题
## 概述
本测试覆盖 Redis 五种核心数据结构的底层实现原理,包括 SDS、quicklist、hash编码切换、intset/hashtable 切换以及 skiplist + hashtable 的 ZSet 结构。共 10 道题:6 道选择题、3 道填空题、1 道简答题。
---
## 一、选择题(6道,由浅入深)
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
### Q1(基础)— 考察定义层面
Redis String 类型底层使用 SDS(Simple Dynamic String)而非 C 字符串。以下哪一项**不是** SDS 相比 C 字符串的核心优势?
A. O(1) 获取字符串长度
B. 二进制安全,不会因为 \0 截断
C. 支持自动缩容以释放多余内存
D. 修改字符串时通过 free 字段实现惰性空间释放
### Q2(基础)— 考察行为判断
对于一个 Hash 类型的键,在 Redis 4.0+ 中,当满足什么条件时会从 ziplist 切换到 hashtable 编码?
A. 元素数量超过 512 或者任意 value 长度超过 64 字节
B. 元素数量超过 1000
C. 任意 key 长度超过 64 字节
D. Hash 中包含浮点数类型的 value
### Q3(进阶)— 考察核心原理
Redis List 从 3.2 版本起统一使用 quicklist 实现。关于 quicklist 的结构特点,以下说法正确的是:
A. quicklist 是一个双向链表,每个节点本身是一个独立的 linkedlist
B. quicklist 的每个节点是 ziplist(或 listpack),通过 list-max-ziplist-size 控制节点大小
C. quicklist 只能单向遍历,无法支持 LPUSH 和 RPUSH 的组合操作
D. quicklist 的节点大小固定为 4KB,不支持动态调整
### Q4(进阶)— 考察对比辨析
关于 Set 类型的 intset 和 hashtable 两种编码,以下哪项描述是正确的?
A. intset 可以存储字符串,但 hashtable 只能存储整数
B. intset 升级到达到的最大整数格式为 int64_t,且不可降级
C. 当 Set 中包含混合类型(整数 + 字符串)时,Redis 会同时使用 intset 和 hashtable
D. intset 查找时间复杂度为 O(N),hashtable 平均为 O(1)
### Q5(深入)— 考察场景推理
某电商系统使用 ZSet 实现商品销量排行榜,zadd score member 其中 score 为销量数值。随着商品数量从几十增长到数百万,ZSet 内部编码发生了什么变化?这种变化的根本原因是什么?
A. 从 hashtable 切换到 skiplist,因为 hashtable 不够灵活
B. 从 quicklist 切换到 ziplist,因为数据量增大后 ziplist 更高效
C. 从 quicklist 切换到 skiplist + hashtable,因为 skiplist 提供 O(log N) 的有序访问而 hashtable 提供 O(1) 的成员查找
D. 编码保持不变,始终使用 skiplist + hashtable,因为 Redis 会自动优化
### Q6(深入)— 考察源码级别细节
Redis 7.0 引入了一项针对小字符串的内存优化:SDS_TYPE_5 直接存储在 dictEntry 的键槽中。这项优化的主要目的是什么?
A. 减少字符串比较的时间复杂度
B. 完全避免额外堆分配,降低内存碎片和 malloc 开销
C. 使短字符串可以使用更大的 maxlevel=64 来提升跳表性能
D. 让 SDS 兼容 C 字符串协议以便与旧版客户端通信
---
## 二、填空题(3道)
### F1 — 填空
Redis ZSet 的内部实现组合了两种数据结构:跳表用于按 score 排序,______ 用于按 member 做 O(1) 查找。
> **提示**: 思考 ZSet 需要同时支持"按分数范围查询"和"精确成员查询"两个维度。
### F2 — 填空
对于 quicklist,如果将 `list-max-ziplist-size` 设置为 **-2**,则表示每节点最大不超过 ______ KB。
> **提示**: 回顾表格中负数取值的含义。
### F3 — 填空
Hash 类型在 Redis 4.0 之前使用 zipmap,4.0~5.x 使用 ziplist。默认切换到 hashtable 的条件是:元素数量大于 512 或任意 value 长度超过 ______ 字节。
> **提示**: 这是 Redis 对压缩列表上限的一个关键阈值。
---
## 三、简答题(1道)
### S1
一个社交应用的点赞功能需要同时满足以下需求:
1. 统计每个用户的点赞总数(类似 `user_id:like_count`)
2. 维护一个用户点赞过的所有帖子 ID 列表(类似 `user:1:liked_posts`)
3. 对帖子维护一个被点赞用户列表,并按点赞时间排序
请结合 Redis 五大核心数据结构的特点,说明你会如何选择数据结构来存储以上信息?为什么不用其他替代方案?
> **答题框架提示**:
> 1. 逐一对应三个业务需求选择最合适的结构
> 2. 考虑每种结构的编码切换策略
> 3. 分析替代方案的缺陷(如用 List 维护排序的代价)
---
## 参考答案与解析
### 选择题答案
| 题号 | 正确答案 | 解析 |
|------|---------|------|
| Q1 | C | SDS 不支持自动缩容,只通过 free 字段保留空闲空间供下次复用。这是设计取舍——频繁缩容反而浪费 CPU。其他选项均为 SDS 核心优势:len 字段 O(1) 获得长度、记录 len 而非依赖 \0 实现二进制安全、free 实现惰性空间释放。 |
| Q2 | A | Redis 4.0+ 的 Hash 哈希表切换条件是:有一个 value > 64 字节或元素数 > 512。注意 Redis 4.0 已将 ziplist 作为 Hash 编码废弃,默认用 hashtable。 |
| Q3 | B | quicklist 是双向链表,每节点为 ziplist(Redis 7.0+ 为 listpack)。通过 list-max-ziplist-size 控制每节点规模。A 错在节点是 ziplist 而非 linkedlist;C 错在支持两端操作;D 错在可配置。 |
| Q4 | B | intset 升级路径是 int16_t → int32_t → int64_t,一旦扩容 realloc 整个结构且不可降级。A 反了;C 不存在混存机制,非整数出现就全部转为 hashtable;D 反了,intset 二分查找 O(log N),hashtable 平均 O(1)。 |
| Q5 | C | 数据量大后 ZSet 从 ziplist/quicklist 切换到 skiplist + hashtable 双结构。skiplist 保证有序性(O(log N) 查找),hashtable 保证 O(1) 的 member 查找。D 不对,小数据量时用 quicklist/ziplist 省内存。 |
| Q6 | B | Redis 7.0 的 native 优化中,小字符串用 SDS_TYPE_5 直接内嵌在 dictEntry 中,无需额外 malloc 分配独立对象。这减少了内存碎片并降低了 malloc 系统调用次数。 |
### 填空题答案
| 题号 | 答案 | 解析 |
|------|------|------|
| F1 | hashtable | ZSet 同时维护了一个 skiplist(按 score 升序排列)和一个 hashtable(按 member 做 O(1) 查找),两者同步更新,兼顾有序性和快速定位。 |
| F2 | 8 | list-max-ziplist-size = -1 表示不限制(仅受 memory 约束),-2 <= 8KB,-3 <= 4KB,-4 <= 2KB,-5 <= 1KB(默认)。负数表示以 KB 为单位的大小上限。 |
| F3 | 64 | 这是 Hash 编码切换的关键阈值之一:value 长度 > 64 字节 或元素数 > 512,都会促使 Redis 从 ziplist/zipmap 切换到 hashtable。 |
### 简答题参考答案
S1:**参考答案要点**:
1. 点赞总数使用 String 类型,通过 INCR 命令原子递增,简单高效;也可嵌套在 Hash 中用 field 存储多种计数。
2. 点赞帖子列表可用 ZSet,score 存点赞时间戳,member 存 post_id,天然有序且支持范围查询(ZREVRANGEBYSCORE)。
3. 帖子的点赞用户列表同样用 ZSet,score 为点赞时间,member 为用户 ID,配合 ZRANGE 取 Top-N。
4. 替代分析:List 虽然能存列表,但不支持按时间排序的高效插入;Hash 适合字段-值映射但不适合有序列表场景。
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点,并给出合理的替代方案分析。
## 关联笔记
- [[03.Redis/core/RDB 与 AOF 持久化]]
- [[03.Redis/core/集群与哨兵机制]]
- [[03.Redis/strategies/多级缓存架构设计]]
- [[03.Redis/strategies/缓存穿透击穿雪崩解决方案]]