收录内容#
Redis 总结里的高频问题清单Redis常见面试题里的缓存定位、数据结构、线程模型、持久化笔记
Redis 知识点总览#
知识点#
使用思维导图进行总结
牛客小月:高频问题:
- Redis 的数据类型有哪些?应用场景?
- Redis 的数据类型的底层数据结构你了解吗?
- ZSet 为什么使用 SkipList 跳表实现?SkipList 跳表是什么?
- Redis 如何实现分布锁?
- SetNx 实现的分布锁有什么问题?
- Redisson 分布式锁底层使用什么数据结构?
- Redisson 分布式锁的好处有哪些?
- 解释一下如何实现可重入?
- 超市续约的看门狗机制了解吗?
- Redisson 分布式锁的问题是什么?如何解决?
- 介绍 Redis 的持久化方式(RDB、AOF、混合持久化)?优缺点?
- Redis 的内存淘汰策略有哪些?
- 什么是缓存击穿/穿透/雪崩?分别怎么解决?
- 什么是热 Key 问题?影响?解决方案?
- 什么是大 Key 问题?影响?解决方案?
- Redis 的高可用了解吗?主从?哨兵?Redis cluster?
- 除了官方的还了解过其他的 Redis 高可用方案吗?
- 主从数据同步的原理了解吗?
- Redis 是 AP 还是 CP 的?
- Redis 支持事务吗?
- Redis 支持事务回滚吗?
为什么大家总爱把 Redis 放到 MySQL 前面#
Apple Notes 里这块写得很直接:Redis 之所以常被拿来做 MySQL 缓存,就是因为它同时占住了高性能和高并发。
- MySQL 的主存储在磁盘,哪怕有 Buffer Pool,随机读写的平均代价也明显高于内存。
- Redis 直接把热点数据放在内存里,读路径短,QPS 可以远高于 MySQL。
- 所以很多读请求根本不该一路打到数据库,而是先被 Redis 挡掉。
这题面试里别答成“Redis 快,所以用 Redis”。更稳的说法是:
- Redis 适合承接热点读、临时状态、计数器、排行榜、短期会话信息;
- MySQL 负责真正的持久化主存储;
- 两者搭配以后,数据库承担的是回源和最终一致性,不再直接扛所有高频读取。
Redis 和 Memcached 的区别#
这块也是 Apple Notes 里的高频点:
共同点:
- 都是基于内存的数据库;
- 都能拿来做缓存;
- 都支持过期;
- 性能都很高。
不同点:
- Memcached 基本就是纯
key-value;Redis 数据结构丰富很多。 - Memcached 没有 Redis 这一套比较完整的持久化机制。
- Memcached 没有 Redis 原生的集群、发布订阅、Lua、事务等能力。
- Redis 更像“内存数据结构服务器”,而不只是一个缓存盒子。
Redis 数据类型和使用场景#
这些类型底层大概是什么#
String#
原笔记和 Apple Notes 都提到了 SDS:
- 二进制安全,不只存文本;
- 取长度是 ,因为有
len字段; - 拼接前会检查空间,不会像 C 字符串那样容易缓冲区溢出。
List#
- 老资料里常写双向链表 / 压缩列表;
- 现在更应该记成
quicklist + listpack这条线。
你面试里不用把版本细节背得很死,但要知道:Redis 会针对“小而紧凑”和“大而频繁变更”的场景切不同实现,不是所有结构都一把梭哈希表。
Hash#
- 小对象时会尽量紧凑存;
- 大一点再切到真正的哈希表结构。
所以它很适合缓存对象,尤其是“对象里只会更新少数字段”的场景。
Set#
- 元素全是整数且规模不大时,会走整数集合;
- 否则走哈希表。
ZSet#
这一块经常被追问:为什么底层爱说“跳表”?
因为 ZSet 的核心需求是两件事同时成立:
- 能按成员快速查;
- 还能按
score有序遍历、做范围查询。
所以通常会把:
- 哈希表用来做成员到分值的定位;
- 跳表用来做按分值排序和区间操作。
哪些结构最容易出现在业务里#
String:缓存详情页、验证码、计数器。Hash:用户资料、购物车。Set:去重关系。ZSet:排行榜、延迟任务。Bitmap:签到统计。HyperLogLog:UV。
为什么 Redis 单线程还这么快#
这题很容易答偏。Apple Notes 里专门强调了一句:
Redis 的“单线程”主要是指从接收请求到执行命令、返回结果这一条主命令路径是单线程。
它并不是整个进程里只有一个线程。
Redis 真正的线程模型#
- 主线程:事件循环、网络读写、命令执行。
- 后台线程(BIO):处理关闭文件、AOF 刷盘、惰性释放内存等耗时任务。
- Redis 6 之后:还可以开 I/O 线程分担网络收发压力,但命令执行仍然是单线程。
为什么快#
这块按笔记里的顺序记就很顺:
- 大部分操作都在内存里完成;
- 数据结构专门为高频读写设计;
- 命令执行单线程,省掉了大量锁竞争和线程切换;
- 用
epoll这种 I/O 多路复用,一条线程就能同时盯很多连接。
所以 Redis 的瓶颈很多时候不在 CPU,而在:
- 内存;
- 网络带宽;
- 大 Key / 热 Key;
- 慢命令和不合理数据结构。
Redis 6 为什么又引入了 I/O 线程#
并不是因为“单线程不行了”,而是网络 I/O 有时会先成为瓶颈。
所以 Redis 6 做的是:
- 让多个 I/O 线程分担网络读写;
- 命令真正执行仍然交给主线程。
也就是说,它优化的是“收发包”,不是把命令执行模型改成多线程并发执行。
持久化:Redis 不只是一个一断电就没数据的缓存#
RDB#
RDB 是快照:
- 在某个时间点把内存里的数据整体落成一个快照文件;
- 恢复快;
- 文件通常也更紧凑;
- 但两次快照之间如果宕机,会丢这一段窗口内的数据。
AOF#
AOF 是把写命令追加到日志里。
Apple Notes 里这块强调的是:Redis 的 AOF 是执行完命令之后再记日志。
优点:
- 少了一步额外的命令合法性检查;
- 当前命令执行路径更直接。
代价:
- 如果命令执行完但 AOF 还没来得及落盘就宕机,还是会丢数据;
- AOF 记录本身如果都在主线程路径上,也可能影响后续命令。
三种常见刷盘策略#
appendfsync always:每次写都刷盘,最稳但最慢;appendfsync everysec:每秒刷一次,实践里常用;appendfsync no:交给操作系统决定何时刷。
混合持久化#
Redis 4.0 开始支持混合持久化,可以理解成:
- 先用 RDB 装一大段基础状态;
- 后面再接增量 AOF。
这样既避免纯 AOF 重放太慢,也能比纯 RDB 少丢一些数据。
这一篇最适合怎么答#
如果面试官一句话问“Redis 为什么适合做缓存”,我会按这条线说:
- 内存存储,热点读写非常快;
- 数据结构丰富,不只是查字符串;
- 命令执行模型简单,单线程避免锁竞争;
- 能做持久化,不只是临时缓存;
- 能继续往外接高可用、分布式锁、消息队列这些能力。
下一篇再把这些更偏工程的问题接上:
- 分布式锁;
- 消息队列;
- HyperLogLog;
- 主从 / 哨兵 / Cluster;
- 缓存一致性。