Redis高频面试:数据结构+编码+分布式锁+缓存问题
一、Redis 五大基本数据结构(面试必背)
Redis 官方定义的五大基础数据结构为:String、List、Hash、Set、ZSet ,所有高级功能均基于这五种结构实现,也是面试基础必考内容。区别于普通数据结构,Redis所有结构均为线程安全、内存存储、高效读写,适配高并发业务场景。
1. String(字符串)
最基础、最常用的数据结构,是Redis的核心基石,支持存储字符串、数字、二进制数据,最大容量512MB。
核心特性:支持增删改查、自增自减、字符串截取、拼接,底层基于SDS(简单动态字符串)实现,区别于C语言原生字符串,无缓冲区溢出、支持动态扩容。
核心面试场景:全局缓存、用户信息缓存、接口限流、计数器(文章阅读量、点赞数)、分布式ID、session共享。
2. List(列表)
有序可重复的字符串列表,底层是双向链表结构,元素有序、可重复,支持头尾快速插入和删除,中间查询效率较低。
核心特性:左进右出、右进左出,天然适配队列、栈结构,读写时间复杂度头尾O(1),中间遍历O(n)。
核心面试场景:消息队列、任务队列、用户点赞列表、最新消息排行、时序数据存储。
3. Hash(哈希)
键值对集合,类似Java的HashMap,一个key对应多个field-value键值对,专门用于存储结构化数据。
核心特性:支持单独读写某个字段,无需序列化整个对象,节省内存、操作灵活。
核心面试场景:用户信息、商品信息、订单信息等结构化对象缓存,单点用户权限存储。
4. Set(集合)
无序、不可重复的字符串集合,底层支持去重、交集、并集、差集运算。
核心特性:自动去重,无重复元素,支持高效集合运算。
核心面试场景:用户点赞/收藏去重、好友交集、共同关注、黑名单、UV统计、标签筛选。
5. ZSet(有序集合)
有序且不可重复的集合,每个元素包含value(值)+score(分数),Redis通过score自动排序,是五大结构中唯一自带排序的结构。
核心特性:元素唯一、分数可重复,支持按分数范围查询、排序、排名。
核心面试场景:热搜排行榜、商品销量排行、积分排名、延时任务、带权重的队列。
二、Redis 底层编码与适配场景(进阶高频)
面试高频追问:五大数据结构只是对外暴露的逻辑结构,底层会根据数据量、数据类型自动切换最优编码,目的是兼顾内存占用和读写性能,所有编码切换均由Redis自动完成,无需人工干预。
1. String 编码:int / embstr / raw
-
int编码 :存储整数类型且数值在long范围内,直接使用整型存储,内存占用极小。适配场景:计数器、自增ID、数字状态值。
-
embstr编码 :字符串长度**≤39字节**,Redis将对象头和字符串数据连续存储,减少内存碎片、读写更快。适配场景:短文本、状态码、配置标识。
-
raw编码:字符串长度**>39字节**,采用SDS动态字符串存储,支持动态扩容。适配场景:长文本、序列化数据、大内容缓存。
2. List 编码:ziplist / linkedlist
-
ziplist(压缩列表):默认编码,满足两个条件:元素个数≤512个、单个元素值≤64字节。连续内存存储,无指针开销,内存极致压缩,读写效率高。适配场景:短列表、少量时序数据。
-
linkedlist(双向链表):不满足ziplist条件时自动切换,支持海量元素存储,头尾操作高效,中间查询慢。适配场景:海量消息队列、长列表数据。
3. Hash 编码:ziplist / hashtable
-
ziplist(压缩列表):字段数量≤512、所有field和value均≤64字节,内存紧凑、开销低。适配场景:小型结构化数据(用户基础信息、简单配置)。
-
hashtable(哈希表):数据超限后切换,底层哈希数组+链表,支持快速增删改查,适配海量字段数据。适配场景:复杂商品信息、海量用户配置。
4. Set 编码:intset / hashtable
-
intset(整数集合):所有元素均为整数、元素个数≤512个,纯整型紧凑存储,无多余开销。适配场景:数字ID集合、编号集合去重。
-
hashtable(哈希表):含非整数元素或数据超限,自动切换,支持任意字符串元素存储。适配场景:标签集合、字符串去重数据。
5. ZSet 编码:ziplist / skiplist
-
ziplist(压缩列表):元素个数≤128个、单个元素≤64字节,紧凑存储,内存最优。适配场景:小型排行榜、少量有序数据。
-
skiplist(跳跃表):数据超限切换,Redis自研跳跃表,平衡了二叉树和链表的优势,排序、范围查询效率极高,时间复杂度O(logn)。适配场景:海量数据排行榜、范围查询业务。
面试总结 :所有压缩列表(ziplist)都是为了节省内存,数据量小、内容简单时优先使用;数据量大、复杂时切换高性能编码,实现性能与内存的平衡。
三、基于Redis的分布式锁原理(基础版)
分布式锁核心目的:在分布式集群中,保证同一时间只有一个线程执行业务,解决并发争抢问题。相比于Zookeeper锁,Redis锁性能更高,适配高并发业务。
1. 核心实现命令(原子性关键)
传统分步set+expire存在宕机导致无过期时间、死锁问题,生产环境必须使用原子命令:
SET lock_key unique_value NX PX 30000
-
NX :key不存在才设置,保证锁的互斥性,同一时间仅一个客户端加锁成功
-
PX 30000 :设置锁30秒自动过期,解决服务宕机导致的死锁问题
-
unique_value:客户端唯一标识(UUID),用于区分锁的持有者,防止误删他人锁
2. 正确加锁、解锁流程
加锁:执行上述原子SET命令,成功则获取锁,执行业务;失败则自旋重试或直接返回繁忙。
解锁(核心禁忌:禁止直接DEL删除) :必须通过Lua脚本保证「判断锁归属+删除锁」原子执行。
Lua脚本逻辑:判断当前lock_key的value是否等于当前客户端唯一标识,相等则删除锁,否则不操作。避免锁过期后,当前线程误删其他线程的锁。
3. 原生Redis锁的致命缺陷(面试追问重点)
-
不支持可重入:同一线程多次加锁会直接失败,导致死锁
-
无锁续期机制:业务执行超时,锁自动过期,导致并发安全问题
-
主从架构锁失效:主节点加锁成功,未同步到从节点就宕机,从节点升级后主锁丢失,出现锁并发问题
四、Redisson 可重入锁 + 锁续期机制(进阶核心)
Redisson是基于Redis封装的分布式锁框架,解决了原生Redis锁的所有缺陷,是生产环境标准方案,面试重点考察可重入原理、看门狗续期两大核心。
1. 可重入锁实现原理
可重入定义:同一客户端、同一线程可以多次获取同一把锁,不会阻塞、不会死锁。
底层实现:基于Redis Hash结构实现
-
key:锁名称(全局唯一锁标识)
-
field:线程唯一ID(区分不同线程)
-
value:锁重入次数(计数器)
加锁逻辑:首次加锁,创建Hash结构,计数器置1;同一线程再次加锁,计数器+1,直接加锁成功。
解锁逻辑:计数器-1,计数器归0时,删除锁key,完全释放锁。
全程通过Lua脚本保证原子性,完美实现可重入特性。
2. 锁续期(看门狗机制)核心原理
原生锁最大问题:业务执行时间不确定,锁过期时间难以把控,过期太早导致并发,过期太晚导致死锁。Redisson通过**看门狗(WatchDog)**自动续期解决该问题。
(1)核心机制
默认锁过期时间30秒,看门狗是一个后台定时线程,每10秒检测一次:如果当前线程还持有锁、业务未执行完毕,自动将锁过期时间重置为30秒,实现无限续期。
(2)关键特性
-
主动终止:业务执行完成、主动解锁后,看门狗停止续期,不会无效续期
-
容错性高:服务宕机后,锁无续期,30秒自动过期,彻底避免死锁
-
无需手动设置过期时间,适配任意时长的业务场景
3. Redisson锁其他优势(面试加分项)
-
支持公平锁、读写锁、联锁、红锁,适配复杂并发场景
-
支持锁等待、超时重试,避免无限自旋
-
完美解决主从锁失效问题(红锁机制)
五、缓存三大问题解决方案复盘(面试压轴)
Redis缓存穿透、缓存击穿、缓存雪崩是面试必考三大经典问题,必须掌握问题成因+危害+多级解决方案+优劣对比。
1. 缓存穿透
问题定义 :查询Redis和数据库都不存在的数据,请求直接穿透到数据库,大量恶意空请求会压垮数据库。
典型场景:恶意传入非法ID、爬虫批量查询无效数据。
解决方案(优先级从高到低)
-
布隆过滤器(最优方案):将所有合法业务Key预加载到布隆过滤器,请求进来先过滤,无效Key直接拦截,不访问Redis和数据库。优点:内存占用极小、拦截效率高;缺点:存在微小误判率、不支持数据删除。
-
缓存空值/默认值:查询数据库为空时,在Redis缓存空对象,设置短期过期时间,避免重复穿透。优点:实现简单、无复杂度;缺点:无效数据占用少量内存。
-
接口校验限流:前端参数校验、后端接口限流、黑名单拦截,从源头拦截非法请求。
2. 缓存击穿
问题定义 :热点Key过期瞬间,大量并发请求同时穿透到数据库,瞬间压垮数据库。
典型场景:秒杀商品、首页热点数据、高频访问的单个Key过期。
解决方案
-
互斥锁(Redisson分布式锁):热点Key过期后,只放行一个线程查询数据库、更新缓存,其他线程等待,避免并发击穿。优点:数据一致性高;缺点:少量请求等待,牺牲部分吞吐量。
-
热点Key永不过期:手动移除过期时间,后台异步定时更新缓存,从根源杜绝过期击穿。优点:性能最高、无并发问题;缺点:需主动维护缓存更新。
-
过期时间随机偏移:给热点Key过期时间增加1-3秒随机值,避免大量Key同时过期。
3. 缓存雪崩
问题定义 :大量缓存Key同时过期 / Redis集群宕机,所有请求全部访问数据库,导致数据库瞬间过载、服务雪崩宕机。
击穿与雪崩区别 :击穿是单个热点Key 过期,雪崩是批量Key/整个缓存集群失效。
解决方案(分层防护)
-
过期时间随机化(基础防护):所有业务Key过期时间增加随机偏移,避免批量同时过期,杜绝时效型雪崩。
-
Redis高可用集群(核心防护):搭建主从+哨兵/集群架构,避免单节点宕机导致整体缓存失效,解决宕机型雪崩。
-
多级缓存降级(兜底防护):本地缓存(Caffeine)+ Redis分布式缓存,Redis失效时,本地缓存兜底;同时开启服务限流、熔断,拒绝超额请求,保护数据库。
-
定时预热缓存:对热点数据提前刷新,避免集中过期。
六、阿里Redis与数据库读写不一致终极解决方案(Canal落地方案)
常规的Cache Aside、延时双删 方案,仅能降低数据不一致概率,无法彻底根治,存在并发读写、删缓存失败、业务异常导致的长期数据不一致问题。阿里生产环境(订单、库存、支付核心链路)统一采用业务层策略 + Canal Binlog异步兜底 的组合方案,实现短时弱一致、最终强一致,是目前工业级最优解。
1、常规缓存一致性方案的残留痛点
- 延时双删依赖延时队列,仍存在极小概率并发脏数据写入;
- 业务代码删缓存失败(网络抖动、服务异常),会永久产生数据不一致;
- 主从延迟、读写分离场景,读从库旧数据回写缓存,引发脏缓存问题。
2、Canal核心原理(阿里开源CDC组件)
Canal 是阿里巴巴开源的数据库增量日志订阅消费组件 ,核心基于MySQL主从复制机制实现,全程无侵入业务代码,异步同步缓存,完美解决读写不一致问题。
核心机制:Canal 伪装成 MySQL 的从库节点,向主库发送dump协议,实时订阅、解析MySQL的Binlog日志,捕获所有增删改数据变更,再通过MQ投递变更事件,异步更新/删除Redis缓存。
3、完整工作流程(生产标准链路)
前置要求 :MySQL开启Binlog,且必须配置为ROW模式,精准记录每行数据变更前后内容,避免日志解析偏差。
-
业务写库:业务线程执行数据库增删改操作,MySQL记录对应的Binlog日志;
-
Canal监听捕获:Canal Server实时拉取Binlog,解析出表名、主键、操作类型(INSERT/UPDATE/DELETE)、新旧数据;
-
MQ可靠投递:Canal将解析后的变更事件推送至RocketMQ/Kafka,利用MQ实现重试、削峰、可靠投递;
-
消费端同步缓存 :业务消费者监听MQ消息,根据数据变更类型,执行删除Redis脏缓存/更新新缓存操作;
-
最终一致兜底:无论业务层是否删缓存成功,Canal都会基于Binlog完成二次缓存修正,彻底消除数据偏差。
4、阿里组合最优方案(业务层+Canal双层保障)
生产环境不单独使用Canal,采用双层策略兼顾实时性 和最终一致性:
-
业务层:延时双删:解决即时并发读写不一致问题,缩小数据不一致时间窗口,保证业务实时性;
-
中间件层:Canal+MQ异步兜底:解决业务删缓存失败、网络异常、主从延迟等极端场景,兜底实现最终数据强一致。
5、Canal方案核心优势(面试核心加分点)
-
业务零侵入:无需改动业务代码,仅通过中间件监听日志完成同步,低耦合、易维护;
-
天然可靠可重试:基于MQ消息机制,消费失败可自动重试,彻底解决缓存更新失败问题;
-
解耦高性能:缓存同步异步执行,不阻塞业务主流程,不影响接口响应速度,适配高并发核心链路;
-
覆盖全场景异常:兼容服务宕机、网络抖动、主从延迟、并发脏写等所有导致数据不一致的场景;
-
精准同步:ROW模式Binlog精准记录数据变更,无批量更新误差,同步精度极高。
6、适用场景与短板
✅ 适用场景
电商订单、库存、价格、支付、用户余额等高并发、高一致性要求的核心业务。
❌ 存在短板
属于异步同步方案,存在毫秒级数据延迟,无法实现绝对实时强一致;架构复杂度更高,需要运维Canal、MQ集群。
7、面试满分话术总结
针对Redis与MySQL读写不一致问题,阿里生产环境采用延时双删+Canal Binlog异步兜底的双层方案:业务层通过延时双删缩小不一致时间窗口,保障业务实时性;中间件层通过Canal伪装MySQL从库,实时解析Binlog变更,结合MQ异步更新缓存,兜底解决所有极端异常导致的数据不一致问题,在不牺牲高并发性能的前提下,实现缓存与数据库的最终强一致。
七、面试高频总结(答题话术精简版)
-
五大数据结构核心:String存通用数据、List做队列、Hash存对象、Set去重、ZSet做排序。
-
底层编码核心:小数据用ziplist/intset省内存,大数据用hashtable/skiplist保性能。
-
Redis分布式锁:原子SET命令加锁+Lua解锁,原生锁不支持可重入和续期。
-
Redisson核心:Hash结构实现可重入,看门狗定时续期,解决锁超时死锁问题。
-
缓存三大问题:穿透用布隆过滤器+空缓存;击穿用分布式锁+永不过期;雪崩用随机过期+高可用+降级兜底。
-
缓存一致性:常规方案无法彻底根治不一致,阿里终极方案为延时双删+Canal Binlog异步兜底,兼顾实时性与最终强一致,适配高并发核心业务。