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

7.8 KiB
Raw Blame History

tags, create time
tags create time
test/review
redis
data-structures
sds
quicklist
skiplist
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 个要点即可得满分;完全正确需覆盖全部要点,并给出合理的替代方案分析。

关联笔记