Redis 面试题汇总
恭喜你学完了 Redis 核心知识点!
这一节,我们来汇总面试中常考的 Redis 面试题,并给出回答思路。
基础篇
Q1: Redis 为什么这么快?
标准答案:
- 纯内存操作:内存访问速度是纳秒级,比磁盘快 10 万倍
- 单线程模型:避免了锁竞争和上下文切换
- I/O 多路复用:单线程同时处理成千上万的连接
- 高效数据结构:SDS、跳表、压缩列表等为 Redis 量身定制
- C 语言实现:编译型语言,执行效率高
追问:单线程如何处理并发?
通过 I/O 多路复用,监听多个 socket 的事件,在一个线程中处理所有客户端请求。
Q2: Redis 有哪几种数据类型?
标准答案:
| 类型 | 底层实现 | 特点 |
|---|---|---|
| String | SDS | 二进制安全 |
| List | QuickList | 双向链表 |
| Hash | HT / ZipList | 对象存储 |
| Set | HT / IntSet | 无序去重 |
| ZSet | SkipList + HT | 有序去重 |
| Bitmap | String | 位图 |
| HyperLogLog | String | 概率统计 |
| Geo | ZSet | 地理位置 |
| Stream | RadixTree | 日流 |
Q3: Redis 和 Memcached 的区别?
标准答案:
| 特性 | Redis | Memcached |
|---|---|---|
| 数据类型 | 丰富 | 只支持字符串 |
| 持久化 | 支持 RDB/AOF | 不支持 |
| 集群 | 原生 Cluster | 需要客户端实现 |
| 内存管理 | 多种淘汰策略 | LRU |
| 线程模型 | 单线程 + 多线程 I/O | 多线程 |
结论:如果只需要简单的 K-V 缓存,Memcached 足够;如果需要更多功能,Redis 是更好的选择。
数据结构篇
Q4: ZSet 的底层实现是什么?
标准答案:
ZSet 底层是跳表(Skip List)+ 哈希表的组合。
- 跳表:支持 O(log n) 的范围查找和排序
- 哈希表:支持 O(1) 的 member 查找
两者结合,实现了「按分数排序」和「按 member 查分数」两种操作。
追问:为什么不用红黑树?
- 跳表实现更简单,代码量少
- 跳表范围查询更高效(链表天然支持)
- 跳表更容易做并发(不需要旋转平衡)
Q5: 什么是 QuickList?
标准答案:
QuickList 是 Redis 3.2 推出的 List 新实现,结合了「压缩列表」和「双向链表」的优点:
QuickList = [ZipList] <=> [ZipList] <=> [ZipList]- 每个 ZipList 默认 8KB
- 元素多时,增加新的 ZipList
- 空间利用率高,插入也快
持久化篇
Q6: RDB 和 AOF 的区别?
标准答案:
| 特性 | RDB | AOF |
|---|---|---|
| 原理 | 定时快照 | 记录命令 |
| 文件大小 | 小 | 大 |
| 恢复速度 | 快 | 慢 |
| 数据安全性 | 低 | 高(可配置) |
| 性能影响 | fork 子进程 | 持续写入 |
推荐配置:同时开启 RDB 和 AOF,使用混合持久化(Redis 4.0+)。
Q7: 持久化会影响性能吗?
标准答案:
- RDB:fork 子进程时可能阻塞,但 COW 机制让影响可控
- AOF:
everysec模式下,异步写入对主线程影响很小
生产环境中,持久化的性能影响是可以接受的,数据安全更重要。
高可用篇
Q8: 主从复制的原理?
标准答案:
- 完整同步:从节点首次连接或断线重连时,执行 BGSAVE 生成 RDB,发送给从节点加载
- 增量同步:日常通过命令传播,主节点每条写命令同时发送给从节点
关键机制:
- 复制偏移量:记录主从同步位置
- 复制积压缓冲区:默认 1MB,保存最近的写命令
Q9: Sentinel 和 Cluster 的区别?
标准答案:
| 特性 | Sentinel | Cluster |
|---|---|---|
| 数据分片 | ❌ | ✅ |
| 自动故障转移 | ✅ | ✅ |
| 最小节点数 | 3 Sentinel + 2 Redis | 6 Redis |
| 适用场景 | 数据量小 | 海量数据 |
选型建议:数据量小需要高可用选 Sentinel,数据量大需要分片选 Cluster。
Q10: 什么是脑裂?如何预防?
标准答案:
脑裂是网络分区导致集群中出现多个主节点的現象。
预防措施:
- 合理配置 Sentinel 数量:至少 3 个,分布在不同机房
- 设置足够的超时时间:
down-after-milliseconds不要太短 - 配置写入确认:
min-replicas-to-write要求写入同步到从节点
缓存篇
Q11: 缓存穿透、击穿、雪崩的区别?
标准答案:
| 概念 | 描述 | 区别 |
|---|---|---|
| 穿透 | 查询不存在的数据 | 数据库也没有 |
| 击穿 | 热点 key 过期 | 大量请求涌入 |
| 雪崩 | 大量 key 同时过期 | key 同时失效 |
解决方案:
- 穿透:布隆过滤器 + 缓存空值
- 击穿:互斥锁 / 逻辑过期 / 预热
- 雪崩:过期时间随机化 + 多级缓存 + 熔断降级
Q12: 缓存一致性怎么保证?
标准答案:
推荐 Cache Aside 模式:
读:缓存命中 → 返回;未命中 → 查库 → 回填缓存
写:先更新数据库 → 再删除缓存注意:删除缓存而不是更新缓存,因为删除比更新更简单,避免并发问题。
Q13: 如何实现分布式锁?
标准答案:
# 加锁
SET key value NX EX seconds
# 解锁(Lua 脚本)
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end关键点:
- value 要用唯一标识(UUID),防止误删
- 解锁要用 Lua 脚本保证原子性
- 过期时间要设置足够长
生产环境推荐使用 Redisson,它提供了看门狗续命、公平锁等高级功能。
Q14: Redis 6.0 的多线程是什么?
标准答案:
Redis 6.0 引入了多线程 I/O,但命令执行仍然是单线程。
客户端请求 → 多线程网络 I/O → 主线程命令执行 → 多线程响应发送适用场景:
- 小 Value:提升有限(瓶颈不在 I/O)
- 大 Value:提升明显(I/O 并行化效果好)
实战篇
Q15: 如何排查 Redis 变慢?
标准答案:
- 查看 INFO 命令:检查内存使用、命中率、持久化状态
- 查看慢查询日志:
SLOWLOG GET找出耗时命令 - 检查大 key:
redis-cli --bigkeys扫描 - 检查热 key:
redis-cli --hotkeys或客户端埋点
常见原因:
- 大 key 操作
- 使用了慢命令(KEYS、FLUSHALL 等)
- 内存满了,大量淘汰
- fork 子进程(持久化、复制)
Q16: Redis 内存满了怎么办?
标准答案:
根据 maxmemory-policy 配置的淘汰策略处理:
| 策略 | 说明 |
|---|---|
| allkeys-lru | 淘汰最久未使用的(推荐缓存场景) |
| volatile-lru | 只淘汰有过期时间的 |
| noeviction | 不淘汰,返回错误 |
建议:
- 设置
maxmemory,根据机器内存预留一部分 - 选择合适的淘汰策略
- 监控
evicted_keys,如果持续增长说明内存不够
Q17: Redis 如何做性能优化?
标准答案:
客户端优化:
- 使用连接池代替直连
- 使用 Pipeline 批量操作
- 避免大 Value
服务端优化:
- 选择合适的淘汰策略
- 合理设置过期时间
- 开启懒删除(UNLINK)
架构优化:
- 读写分离
- 分片存储
- 本地缓存兜底
总结
Redis 核心知识点
┌─────────────────────────────────────────────┐
│ Redis │
├─────────────────────────────────────────────┤
│ 数据结构:String, List, Hash, Set, ZSet... │
│ 持久化:RDB, AOF, 混合持久化 │
│ 高可用:主从, Sentinel, Cluster │
│ 缓存策略:穿透, 击穿, 雪崩, 一致性 │
│ 分布式:锁, 队列, 计数器, 排行榜 │
└─────────────────────────────────────────────┘面试技巧
- 原理要懂:不仅要知道怎么用,还要知道为什么这样设计
- 实践要会:能写出基本的 Java 代码
- 场景要熟:知道这些技术在实际项目中怎么用
- 追问要答:面试官追问时,能深入展开
祝你面试成功!
核心记忆点:Redis 面试主要考察数据结构、持久化、高可用、缓存策略、分布式应用五大方面。原理 + 实践 + 场景,是应对 Redis 面试的关键。
