少女祈祷中...
NEKO
知识库

redis 数据结构面试要点

一、基础概念类

Q1:Redis 是什么?有什么特点?

  • 基于内存的键值数据库,也支持持久化。

  • 特点:纯内存、单线程命令执行、IO 多路复用、丰富数据结构、支持主从/哨兵/Cluster。

  • 常用于缓存、计数器、排行榜、分布式锁、消息队列。

Q2:Redis 为什么快?

  1. 纯内存操作,避免磁盘 I/O。

  2. 单线程命令执行,免锁竞争、无上下文切换。

  3. IO 多路复用(epoll),高并发连接。

  4. 高效数据结构:SDS、跳表、listpack 等。

  5. 协议简单:RESP,解析快。

Q3:Redis 是单线程还是多线程?

  • 命令执行是单线程,保证原子性、免锁。

  • 网络 IO 在 Redis 6 后可多线程,提升吞吐。

  • 持久化、异步删除、集群同步另有后台线程。

  • 所以“Redis 单线程”指的是命令处理主线程。

Q4:Redis 和 Memcached 的区别?

维度

Redis

Memcached

数据结构

丰富

只有 KV

持久化

支持

不支持

高可用

主从/哨兵/Cluster

无

线程

命令单线程

多线程

内存管理

多种策略

LRU

二、5 种基本类型类

Q5:Redis 有哪些基本数据类型?

类型

说明

典型场景

String

字符串/数字/二进制

缓存、计数器、分布式锁

List

双向链表

消息队列、最新列表

Hash

字段-值映射

对象存储、购物车

Set

无序不重复集合

去重、共同好友、抽奖

ZSet

有序集合,带 score

排行榜、延时队列

Q6:String 的底层实现?

  • SDS(Simple Dynamic String),不是 C 字符串。

  • SDS 结构:len、alloc、buf[]。

  • 优点:

    • O(1) 获取长度。

    • 二进制安全。

    • 预分配,减少内存重分配。

    • 兼容 C 字符串函数。

Q7:String 的编码有哪些?

  • int:值为整数且范围合适。

  • embstr:短字符串(≤44 字节),一次分配。

  • raw:长字符串(>44 字节),两次分配。

  • OBJECT ENCODING key 可查看。

Q8:List 的底层实现?

  • 早期:ziplist(小)+ linkedlist(大)。

  • 3.2+:quicklist,由多个 ziplist/listpack 组成的双向链表。

  • 7.0+:listpack 替代 ziplist。

  • 特点:两端操作 O(1),中间 O(n)。

Q9:Hash 的底层实现?

  • listpack(小数据)或 hashtable(大数据)。

  • 转换条件:字段数 > 512 或某字段值 > 64 字节。

  • hashtable 用渐进式 rehash,避免一次性阻塞。

Q10:Set 的底层实现?

  • intset:全整数且元素少。

  • listpack:元素少且非整数(7.0+)。

  • hashtable:元素多。

  • 转换条件:元素数 > 512 或含非整数。

Q11:ZSet 的底层实现?

  • listpack(小数据)或 skiplist + hashtable(大数据)。

  • skiplist 负责按 score 排序和范围查询。

  • hashtable 负责 O(1) 按 member 查 score。

  • 转换条件:元素数 > 128 或 member 长度 > 64。

Q12:跳表(skiplist)的原理?

  • 多层链表,上层是下层的索引。

  • 查找从最高层开始,逐层下降,平均 O(log n)。

  • 相比平衡树:实现简单、范围查询友好、并发好。

  • Redis 跳表层高最大 32,用随机法决定层数。

三、底层编码与转换类

Q13:什么是 ziplist?为什么被 listpack 替代?

  • ziplist:紧凑的连续内存结构,存小数据省内存。

  • 缺点:连锁更新——某节点扩容可能引发后续节点连锁扩容。

  • listpack:每个节点记录自身长度,不记录前驱长度,避免连锁更新。

  • Redis 7.0 用 listpack 替代 ziplist。

Q14:什么是渐进式 rehash?

  • hashtable 扩容时,不一次性迁移所有键。

  • 维护两个哈希表,逐步把旧表键迁到新表。

  • 期间查找同时查两个表,新增只写新表。

  • 避免一次性 rehash 阻塞主线程。

Q15:OBJECT ENCODING 有什么用?

  • 查看 key 的实际编码。

  • 例:OBJECT ENCODING mykey 返回 embstr、hashtable 等。

  • 用于验证编码转换和内存优化。

Q16:编码转换是单向的吗?

  • 大部分是单向的,如 listpack → hashtable。

  • 但某些操作后可能回退,如删除元素后 Set 的 intset 不会自动回退。

  • 具体看类型和版本。

四、高级数据结构类

Q17:Bitmap 是什么?有什么场景?

  • 基于 String 的位操作,每个 bit 存 0/1。

  • 命令:SETBIT、GETBIT、BITCOUNT、BITOP。

  • 场景:签到、活跃用户统计、布隆过滤器。

  • 优点:极省内存;缺点:只能存布尔值。

Q18:HyperLogLog 是什么?

  • 基数统计(去重计数)的概率算法。

  • 命令:PFADD、PFCOUNT、PFMERGE。

  • 优点:固定 12KB 内存,误差约 0.81%。

  • 缺点:不精确,不能取元素。

  • 场景:UV 统计。

Q19:GEO 是什么?

  • 基于 ZSet 实现地理位置存储。

  • 命令:GEOADD、GEODIST、GEORADIUS、GEOSEARCH。

  • 场景:附近的人、打车。

  • 底层:经纬度编码成 score。

Q20:Stream 是什么?

  • Redis 5.0 引入的消息队列结构。

  • 支持消费组、ACK、持久化。

  • 命令:XADD、XREAD、XACK、XGROUP。

  • 相比 List:支持多消费者、消息确认。

Q21:布隆过滤器是什么?

  • 用多个哈希函数和位数组判断元素是否存在。

  • 特点:不存在一定准,存在可能误判。

  • 不支持删除(可用 Counting Bloom)。

  • Redis 通过 RedisBloom 模块支持。

五、应用场景类

Q22:Redis 怎么做计数器?

  • INCR、DECR、INCRBY。

  • 原子操作,适合点赞、库存、限流。

  • 注意:值必须是整数,否则报错。

Q23:Redis 怎么做排行榜?

  • ZSet:ZADD 加分数,ZREVRANGE 取排名。

  • 支持按 score 排序、范围查询、排名查询。

  • 场景:游戏积分、热搜。

Q24:Redis 怎么做分布式锁?

  • SET key value NX EX seconds。

  • value 存唯一标识,删除时用 Lua 校验。

  • 详见分布式锁模块。

Q25:Redis 怎么做消息队列?

  • List:LPUSH + BRPOP,简单但无 ACK。

  • Pub/Sub:不持久化,易丢消息。

  • Stream:支持消费组和 ACK,推荐。

Q26:Redis 怎么做去重?

  • Set:SADD 自动去重。

  • Bitmap:适合大量整数 ID。

  • HyperLogLog:只需基数时用。

Q27:Redis 怎么做会话共享?

  • String 或 Hash 存 session。

  • 设置 TTL 自动过期。

  • 多台应用服务器共享同一 Redis。

六、高频陷阱题

Q28:Redis 的 String 和 C 字符串有什么区别?

  • SDS 有长度字段,O(1) 取长度。

  • 二进制安全,可存 \0。

  • 预分配减少重分配。

  • C 字符串以 \0 结尾,不能存二进制。

Q29:ZSet 为什么用跳表不用红黑树?

  • 跳表实现简单,范围查询方便。

  • 并发控制更容易。

  • 内存和性能与红黑树相当。

Q30:Hash 的 rehash 会阻塞吗?

  • 不会。渐进式 rehash 分多次完成。

  • 期间查找查两个表,新增写新表。

Q31:List 是链表还是数组?

  • quicklist:多个 listpack 组成的双向链表。

  • 两端操作 O(1),中间 O(n)。

Q32:SETBIT 的 offset 很大会怎样?

  • 会按 offset 分配内存,可能撑爆内存。

  • 用之前要评估最大 offset。

Q33:HyperLogLog 能精确统计吗?

  • 不能。标准误差约 0.81%。

  • 需要精确用 Set 或 Bitmap。

Q34:Redis 的 key 有长度限制吗?

  • 最大 512MB。

  • 但 key 不宜过长,影响内存和比较效率。

Q35:TYPE 和 OBJECT ENCODING 区别?

  • TYPE 返回逻辑类型(string、list 等)。

  • OBJECT ENCODING 返回底层编码(embstr、quicklist 等)。

评论