一、基础概念类
Q1:Redis 是什么?有什么特点?
基于内存的键值数据库,也支持持久化。
特点:纯内存、单线程命令执行、IO 多路复用、丰富数据结构、支持主从/哨兵/Cluster。
常用于缓存、计数器、排行榜、分布式锁、消息队列。
Q2:Redis 为什么快?
纯内存操作,避免磁盘 I/O。
单线程命令执行,免锁竞争、无上下文切换。
IO 多路复用(epoll),高并发连接。
高效数据结构:SDS、跳表、listpack 等。
协议简单:RESP,解析快。
Q3:Redis 是单线程还是多线程?
命令执行是单线程,保证原子性、免锁。
网络 IO 在 Redis 6 后可多线程,提升吞吐。
持久化、异步删除、集群同步另有后台线程。
所以“Redis 单线程”指的是命令处理主线程。
Q4:Redis 和 Memcached 的区别?
二、5 种基本类型类
Q5:Redis 有哪些基本数据类型?
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 等)。
评论