Redis面试视频|当前热门考点全景
基于2024年各大厂最新面经提炼,聚焦高频、易错、易忽略的Redis面试核心问题,内容实时更新,拒绝过时题库。
为什么Redis单线程却能高性能?
很多候选人误以为多线程一定更快,其实Redis的高性能源于:
① 完全基于内存操作;② 避免线程切换与锁竞争;③ 使用I/O多路复用(epoll/kqueue);④ 数据结构高效。
注意陷阱:Redis 6.0后引入了多线程I/O,但命令执行仍为单线程——这并非退步,而是为突破网络带宽瓶颈。
SDS(简单动态字符串)如何优于C字符串?
C字符串以'\0'结尾,无法快速获取长度;而Redis的SDS:
• 存储len字段,O(1)获取长度;
• 采用空间预分配(alloc = len + free),避免频繁扩容;
• 惰性空间释放,减少内存碎片。
示例:执行APPEND时,若剩余空间足够则不重新分配,仅更新len。
RDB与AOF:如何选择?
RDB:快照模式,适合备份与灾难恢复;但可能丢失最后一次快照后的数据。
AOF:追加日志,可配置每秒/每次写入;数据更安全,但文件体积大、恢复慢。
最佳实践:主从架构中,主节点用AOF(保证数据不丢),从节点用RDB(加速重启与复制)。
缓存穿透、击穿、雪崩怎么破?
穿透:查不存在数据 → 用布隆过滤器或缓存空值(短TTL);
击穿:热点key过期 → 互斥锁或逻辑过期+异步更新;
雪崩:大量key同时过期 → 随机过期时间+二级缓存+熔断降级。
案例:某电商大促时,用SETNX实现分布式锁防止击穿,配合EXPIRE避免死锁。
Redis Cluster的Gossip协议原理
集群节点间通过ping/pong消息交换状态,每秒随机PING 3个节点,再PING剩余节点中最近通信最久的1个。消息包含:
• 节点ID、IP/端口
• 标记(主/从、故障?)
• 配置Epoch
• 槽位分配信息
关键点:故障判定需半数以上节点同意,避免脑裂。
分布式ID生成方案对比
• Snowflake:依赖时间戳,需解决时钟回拨
• Redis INCR:简单高效,但单点风险
• Redis Cluster分片INCR:高可用方案
• UUID:无序,查询性能差
推荐方案:基于Redis的INCRBY + 槽位分片(如:id:order:{slot}),配合TTL自动清理。
底层原理深度解析
不满足于“会用”,更要理解“为什么这样设计”。本模块系统拆解Redis核心数据结构与内存模型。
SDS:Redis字符串的底层实现
Redis没有直接使用C语言的字符串(以'\0'结尾的字符数组),而是自定义了简单动态字符串(Simple Dynamic String, SDS),其结构如下:
len:已使用字节数(字符串长度)alloc:分配的总字节数(含'\0')buf[]:实际数据缓冲区
优势:
• O(1)获取长度;
• 减少内存分配次数(预分配机制:len < 1MB时free=alloc/2);
• 二进制安全(可存储图片、视频等二进制数据);
• 兼容部分C字符串函数(末尾自动补'\0')。
面试提示:当执行SET key "hello"后,再APPEND key "world",若原buf空间不足,SDS会扩容至2倍(不足1MB)或+1MB(超过1MB)。
哈希结构:字典与渐进式rehash
Redis的哈希(Hash)底层使用字典(Dict)实现,包含两个哈希表(ht[0]和ht[1]),用于渐进式rehash:
- 插入新键:只写入ht[1],ht[0]保持只读
- 查询/更新:先查ht[0],未找到再查ht[1]
- 渐进式rehash:每次操作时迁移1~N个槽位,避免阻塞
- 触发条件:负载因子 > 1(ht[0])或 > 5(ht[1])
典型问题:为什么不用一次性rehash?
答:避免长阻塞。1000万键的字典,一次性rehash可能卡住数秒,而渐进式可平滑过渡。
列表结构:QuickList与ziplist优化
Redis列表(List)底层为QuickList结构,由双向链表 + 压缩列表(ziplist)组成:
- QuickListNode:每个节点是一个ziplist
- ziplist:紧凑内存结构,适合小数据(默认阈值:512字节/项数)
- 配置项:
list-max-ziplist-size(默认-2,表示8KB)
示例:LPUSH users user1 user2 user3 → 若初始ziplist未超限,直接插入;超限时分裂为两个ziplist节点。
注意:ziplist会因插入/删除触发连锁更新(连续反转),故大列表建议用链表或Stream。
集合:intset与hashtable的切换
Redis集合(Set)底层有两种实现:
- intset:整数集合,适用于全为整数且数量≤512的情况(内存更省)
- hashtable:哈希表,支持任意类型,O(1)操作
升级规则:
• 新增元素为非整数 → 自动升级为hashtable
• 元素数>512 → 强制升级
示例:SADD numbers 1 2 3 → 使用intset;SADD numbers 1.5 → 转为hashtable,所有整数转为字符串。
有序集合:跳跃表(Skip List)原理
ZSet底层由dict + skiplist组成:
- dict:维护member→score映射(O(1)查分值)
- skiplist:按score排序,支持O(logN)范围查询
跳跃表结构:
• 每层链表节点数约为下层一半
• 插入时随机生成层数(1~32层)
• 头节点层数为32,实际平均层数≈2~3
为什么不用AVL树?
答:跳跃表实现更简单,区间查询更高效(无需旋转),且并发友好(Redis单线程无需复杂锁)。
Redis面试真题演进路径
从初级到高级,层层递进掌握Redis面试核心逻辑。附真实面试场景与参考回答思路。
Q:Redis有哪些基本数据类型?
5种核心类型:String、Hash、List、Set、ZSet;2种特殊结构:Bitmap、HyperLogLog;Stream(Redis 5.0新增)。
“String是二进制安全的,可存储文本、图片;Hash适合对象存储;List用于消息队列;Set用于去重;ZSet用于排行榜。”
Q:如何保证缓存与数据库的双写一致性?
常见方案:
① 先更新DB→再删缓存(推荐,避免脏数据);
② 串行化写操作;
③ 使用 Canal 监听DB变更;
④ 读写分离场景下,读从库可能延迟。
某金融系统曾因“先删缓存再更新DB”导致并发时读到旧DB数据,回填缓存污染,后改用“更新DB成功后再删缓存”解决。
Q:Redis集群脑裂时如何保证数据一致性?
Redis Cluster通过quorum(多数派)机制防止脑裂:
• 故障节点需半数以上主节点投票才能标记为故障
• 分区外节点无法写入(因槽位不可达)
• 客户端需配置cluster-require-full-coverage no(允许部分槽位不可用)
min-replicas-to-write 1:至少1个从节点在线才允许写入min-replicas-max-lag 10:从节点延迟超10秒不参与写入投票
Q:如何设计一个高可用的Redis缓存架构?
分层策略:
① 主从 + 哨兵/Cluster(高可用层)
② 本地缓存(Caffeine) + Redis(多级缓存)
③ 熔断降级(Sentinel限流)
④ 异步写回 + 事务日志(持久化保障)
⑤ 监控告警(延迟、内存、连接数)
商品详情页:本地缓存TTL=2min → Redis集群(3主3从)→ MySQL集群
订单系统:Redis Stream做削峰 → 持久化AOF → 异步写入DB
网友们还关心这些问题
以下内容基于2024年各大技术社区真实提问整理,涵盖Redis面试延伸场景与避坑指南。