Redis 由浅到深面试题(分层次版)

一、 基础入门篇(初 / 中级必问,占比 30%)

1. Redis 是什么?它的核心优势有哪些?

答案要点

  • 定义:开源的内存型键值对数据库,支持丰富数据结构,可用于缓存、分布式锁、消息队列等场景。
  • 核心优势:
    1. 高性能:基于内存操作 + 单线程模型 + IO 多路复用,QPS 可达 10w+。
    2. 丰富数据结构:String、Hash、List、Set、ZSet 五种基本结构,支持 BitMap、HyperLogLog 等扩展结构。
    3. 持久化:支持 RDB、AOF 两种持久化方式,保证内存数据不丢失。
    4. 高可用:支持主从复制、哨兵、集群模式,避免单点故障。
    5. 原子操作:所有命令都是原子性的,支持事务、Lua 脚本,适合并发场景。

2. Redis 支持哪些数据结构?分别有哪些典型应用场景?

答案要点

数据结构 核心特性 典型场景
String 二进制安全,支持字符串、数字、二进制数据 缓存用户信息、计数器(阅读量)、分布式锁(SETNX)
Hash 键值对集合,适合存储对象 缓存商品详情(field 对应属性)、用户信息
List 双向链表,支持两端增删 消息队列(LPUSH+BRPOP)、最新消息列表
Set 无序不重复集合,支持交集 / 并集 / 差集 标签系统、用户关注关系、抽奖(SPOP)
ZSet 有序不重复集合,按 score 排序 排行榜(销量榜、积分榜)、延迟队列

3. Redis 的过期策略有哪些?内存淘汰机制有哪些?

答案要点

  • 过期策略 (三种结合):
    1. 定时过期:为每个过期 key 设置定时器,到期立即删除 → 内存友好,CPU 压力大。
    2. 惰性过期:访问 key 时才判断是否过期,过期则删除 → CPU 友好,内存压力大。
    3. 定期过期:每隔一段时间扫描过期 key 字典,随机抽取部分 key 删除 → 平衡 CPU 和内存。
  • 内存淘汰机制 (内存达到 maxmemory 时触发):
    1. volatile-lru:淘汰设置过期时间的 key 中,最近最少使用的。
    2. allkeys-lru:淘汰所有 key 中最近最少使用的(最常用)。
    3. volatile-ttl:淘汰过期时间最近的 key。
    4. noeviction:默认策略,不淘汰,内存不足时拒绝写入(报错 OOM)。

4. Redis 的持久化机制 RDB 和 AOF 有什么区别?如何选择?

答案要点

特性 RDB AOF
原理 定时生成内存数据的快照文件(二进制) 记录所有写命令到日志文件(文本)
数据完整性 差,可能丢失最后一次快照后的所有数据 好,支持 appendfsync 三种策略(always/everysec/no)
文件大小 小,二进制压缩 大,命令日志,可重写压缩
恢复速度 快,直接加载快照 慢,需要重新执行所有命令
性能影响 低,fork 子进程执行,不阻塞主线程(大数据量 fork 会阻塞) 较高,写命令实时追加,everysec 模式性能适中
选择建议 1. 追求高性能、可接受数据少量丢失 → RDB2. 追求数据完整性、不允许丢失 → AOF(everysec 模式)3. 生产环境推荐 RDB + AOF 混合持久化(Redis 4.0+ 支持)

5. 什么是缓存穿透?如何解决?

答案要点

  • 定义 :请求不存在的 key,缓存和数据库都查询不到,请求直接打穿到数据库,高并发下导致 DB 压力过大。
  • 解决方案
    1. 缓存空值:查询不到的数据也缓存(设置短过期时间,如 5 分钟)。
    2. 布隆过滤器:在缓存前加一层布隆过滤器,判断 key 是否存在,不存在则直接拒绝请求(适合海量数据场景)。

二、 进阶原理篇(中 / 高级必问,占比 40%)

1. Redis 为什么是单线程的?为什么单线程还能这么快?

答案要点

  • 为什么单线程
    1. Redis 的性能瓶颈是 内存和网络带宽,不是 CPU,单线程足够处理。
    2. 单线程避免了线程切换和锁竞争的开销,简化了并发编程模型。
  • 单线程快的核心原因
    1. 基于内存操作:所有数据都在内存中,读写速度远超磁盘。
    2. 高效的 IO 多路复用模型:利用 epoll/kqueue 等机制,单线程监听多个 Socket,实现高并发网络 IO。
    3. 命令处理简单:Redis 命令都是原子性的,处理逻辑简单,无复杂计算。
    4. 避免了锁开销:单线程无需加锁,省去了锁的获取和释放时间。

2. Redis 6.0 引入的多线程是干什么的?和之前的单线程有什么区别?

答案要点

  • 多线程的作用 :Redis 6.0 的多线程仅用于处理网络 IO 的读写 (Socket 读数据、写响应),命令执行仍然是单线程
  • 和单线程的区别
    1. Redis < 6.0:网络 IO + 命令执行 都由主线程完成。
    2. Redis 6.0+:主线程负责命令执行,多线程负责网络读写,解决了网络带宽瓶颈(大报文场景性能提升明显)。
  • 核心原则:命令执行的单线程模型不变,保证了 Redis 的原子性和简洁性。

3. 如何用 Redis 实现分布式锁?有哪些坑?如何解决?

答案要点

  • 基础实现(RedisTemplate)
    1. 加锁:SET key value NX PX 30000(NX = 不存在才设置,PX = 过期时间,原子操作)。
    2. 解锁:用 Lua 脚本保证原子性(判断 value 是否为自己的,是则删除,避免误删其他线程的锁)。
  • 常见坑 & 解决方案
    1. 死锁:必须设置过期时间,避免服务宕机导致锁无法释放。
    2. 锁过期 :业务逻辑未执行完锁就过期 → 用 Redisson 的看门狗机制(自动续期锁)。
    3. 误删锁:解锁前必须验证 value(唯一标识,如 UUID)→ Lua 脚本原子解锁。
    4. 单点故障 :Redis 主从切换时锁丢失 → 用 Redisson 的红锁(多节点加锁,半数以上成功才算锁成功)。
  • 工业级方案 :推荐用 Redisson,封装了分布式锁的所有细节(可重入锁、公平锁、看门狗),无需手写代码。

4. 缓存击穿和缓存雪崩有什么区别?分别如何解决?

答案要点

问题 定义 解决方案
缓存击穿 热点 key 过期瞬间,大量并发请求直接打穿到 DB 1. 热点 key 永不过期 + 后台异步更新2. 加分布式锁,只有一个线程去 DB 查询并更新缓存3. 缓存预热,提前加载热点 key
缓存雪崩 大量 key 同时过期,或 Redis 宕机,导致所有请求打穿到 DB 1. 给 key 设置随机过期时间,避免同时过期2. 部署 Redis 集群(主从 + 哨兵),提高可用性3. 加熔断降级机制,保护 DB4. 本地缓存兜底(如 Caffeine)

5. Redis 主从复制的原理是什么?数据同步的过程是怎样的?

答案要点

  • 主从复制的作用:数据备份、读写分离(主库写,从库读)、负载均衡。
  • 数据同步过程(全量同步 + 增量同步)
    1. 建立连接 :从库发送 SLAVEOF 命令,与主库建立连接。
    2. 全量同步
      • 主库执行 bgsave 生成 RDB 快照,发送给从库。
      • 从库加载 RDB 快照,恢复数据。
      • 主库将快照生成期间的写命令,记录到复制缓冲区,发送给从库。
    3. 增量同步:全量同步完成后,主库将后续的写命令实时发送给从库,从库执行命令,保持数据一致。
  • 核心优化 :Redis 2.8+ 支持 PSYNC 命令,断线重连时只同步增量数据(基于偏移量),无需全量同步。

三、 高级优化篇(资深必问,占比 20%)

1. Redis 集群(Redis Cluster)的原理是什么?如何实现数据分片和高可用?

答案要点

  • 核心目的:解决 Redis 单机内存和并发的瓶颈,实现水平扩容。
  • 数据分片
    1. 采用 CRC16 哈希算法 ,将 key 映射到 0~16383 的槽位(Slot)。
    2. 集群中每个节点负责一部分槽位(如主节点 A 负责 0~5000 槽位)。
    3. 客户端根据 key 的槽位,直接访问对应的节点。
  • 高可用
    1. 集群采用 主从架构,每个主节点对应一个或多个从节点。
    2. 主节点宕机后,从节点通过投票机制(半数以上主节点同意)晋升为主节点。
    3. 哨兵模式负责节点的故障检测和自动切换。
  • 核心特性 :支持自动分片故障转移,但不支持跨节点的事务和 Lua 脚本。

2. Redis 性能优化有哪些手段?(内存、网络、命令层面)

答案要点

  • 内存优化
    1. 选择合适的数据结构:如用 Hash 存储对象,比 String 更节省内存(ziplist 编码)。
    2. 设置合理的过期策略:及时淘汰无用数据,避免内存溢出。
    3. 开启内存压缩:Redis 支持对 ziplist、intset 等编码的数据进行压缩。
    4. 避免大 key:大 key 会导致内存碎片、网络阻塞,拆分大 key(如大 Hash 拆分为多个小 Hash)。
  • 网络优化
    1. 开启 Redis 6.0 的多线程 IO,提升网络读写性能。
    2. 使用 Pipeline 批量命令:将多个命令打包发送,减少网络往返次数。
    3. 合理设置 TCP 配置:增大 TCP 缓冲区,减少延迟。
  • 命令优化
    1. 避免使用 O(N) 命令(如 KEYS *HGETALL),改用 SCAN 命令(分批遍历)。
    2. 禁用慢查询命令,设置 slowlog-log-slower-than 记录慢查询,优化慢命令。
    3. 使用 Lua 脚本:将多个命令封装为 Lua 脚本,减少网络往返,保证原子性。

3. Redis 的慢查询日志是什么?如何排查慢查询问题?

答案要点

  • 慢查询日志 :Redis 记录执行时间超过 slowlog-log-slower-than(默认 10ms)的命令日志,用于排查性能问题。
  • 排查步骤
    1. 查看慢查询日志:SLOWLOG GET 10(获取最近 10 条慢查询)。
    2. 分析慢命令:常见慢命令有 KEYS *HGETALLSMEMBERS 等 O (N) 命令。
    3. 优化方案:
      • 替换 O (N) 命令为 SCAN 命令(分批遍历)。
      • 拆分大 key,减少单次命令处理的数据量。
      • 优化命令参数,避免全量查询。

4. Redis 主从复制中,为什么会出现数据不一致?如何解决?

答案要点

  • 数据不一致的原因
    1. 网络延迟:主库的写命令同步到从库有延迟,主从切换时从库数据可能落后。
    2. 异步复制:Redis 主从复制是异步的,主库发送命令后不等待从库确认。
    3. 脑裂问题:主库宕机后,从库晋升为主库,原主库恢复后成为从库,数据可能被覆盖。
  • 解决方案
    1. 配置 min-replicas-to-write (主库至少有 N 个从库连接)和 min-replicas-max-lag(从库最大延迟时间),主库达不到条件则拒绝写命令。
    2. 采用 Redis Cluster哨兵模式,减少主从切换的时间。
    3. 业务层最终一致性:通过定时任务校验主从数据,不一致时手动修复。

四、 实战方案篇(架构设计必问,占比 10%)

1. 缓存和数据库的一致性如何保证?有哪些方案?

答案要点

  • 核心原则 :缓存的更新策略要避免并发场景下的数据不一致,推荐 Cache-Aside Pattern(旁路缓存模式)
  • 方案 1:先更新数据库,再删除缓存(推荐)
    1. 写操作:更新 DB → 删除缓存(而非更新缓存)。
    2. 读操作:读缓存 → 缓存未命中 → 读 DB → 写入缓存。
    3. 优势:避免了并发更新缓存导致的不一致,实现简单。
    4. 注意:删除缓存失败时,需重试或记录日志,人工修复。
  • 方案 2:延迟双删(解决并发写问题)
    1. 写操作:删除缓存 → 更新 DB → 延迟 1 秒再删除一次缓存。
    2. 适用场景:高并发写场景,避免更新 DB 后,其他线程读取旧数据写入缓存。
  • 方案 3:基于 Canal 的增量更新
    1. 利用 Canal 监听 MySQL 的 binlog 日志,当数据变更时,自动更新或删除缓存。
    2. 优势:无需业务代码侵入,适合大规模分布式系统。

2. 高并发秒杀场景下,如何用 Redis 做限流和防超卖?

答案要点

  • 限流方案(防止请求过载)
    1. Redis + Lua 脚本 :基于 INCR 命令,限制用户 / IP 的请求次数(如每分钟 10 次)。
    2. Redisson 令牌桶算法RRateLimiter 实现平滑限流,避免流量突刺。
  • 防超卖方案(核心是分布式锁 + 原子操作)
    1. 库存预扣减 :将库存存入 Redis,秒杀时用 DECR 命令原子扣减库存,判断结果是否 ≥ 0。
    2. 分布式锁:用 Redisson 锁锁住商品 ID,确保同一商品同一时间只有一个线程扣减库存。
    3. 最终一致性:Redis 扣减库存成功后,异步写入 MySQL,失败时回滚 Redis 库存。
  • 兜底方案
    1. 前端限流(按钮置灰)+ 网关限流(Nginx)+ 后端限流,多层防护。
    2. 熔断降级:当 Redis 宕机时,直接返回 "活动火爆",保护后端系统。
相关推荐
-XWB-2 小时前
【Oracle】Oracle诊断系列(1/6):健康体检指南——快速掌握数据库状态
数据库·oracle
杨了个杨89822 小时前
Redis常用命令
数据库·redis·缓存
-XWB-2 小时前
【MySQL】XtraBackup 全量备份还原操作指南(MySQL 5.7 / 8.0 通用)
数据库·mysql·adb
Tancenter2 小时前
Mysql和ElasticsSearch
数据库·mysql·elasticsearch
fai厅的秃头姐!2 小时前
2026-1-13
数据库·mysql
dishugj2 小时前
【oracle】RMAN Catalog 与 Nocatalog 核心区别及实操指南
数据库·oracle·rman
heartbeat..2 小时前
MySQL 索引从入门到精通:核心概念、类型与实战优化
java·数据库·mysql·索引
heartbeat..2 小时前
MySQL 存储引擎解析:InnoDB/MyISAM/Memory 原理与选型
java·数据库·mysql·存储引擎
Freed&2 小时前
Redis 缓存三大经典问题详解:缓存穿透、缓存击穿与缓存雪崩
数据库·redis·缓存