--- 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/缓存穿透击穿雪崩解决方案]]