Redis 八股文面试题

一、Redis 知识点全景概览

要真正掌握 Redis,不能只零散记忆命令或知识点,而需从单点出发,梳理清楚知识点间的关联,构建完整知识网络。下面就从 Redis 的核心优势切入,带大家由点及面认识 Redis 各知识点的联系。

二、Redis 核心优势:为什么选择 Redis?

Redis 能在众多缓存 / 数据库中脱颖而出,源于其三大核心优势:

1. 极致性能

  • 单线程设计:Redis 采用单线程模型处理客户端请求(持久化、异步复制等操作由后台线程处理)。单线程避免了线程切换和锁竞争的开销,结合内存存储,使得 Redis 能达到每秒数万次读写的高性能。
  • IO 多路复用:通过 epoll/select 等机制,单线程可同时处理多个客户端连接的网络 IO,进一步提升吞吐量。

2. 丰富数据结构

Redis 提供了远超普通键值对的8 种核心数据结构

  • 字符串(String):存储文本、数字,支持自增 / 自减、位图(Bitmap)等操作。
  • 列表(List):双向链表结构,支持栈(LIFO)、队列(FIFO)操作,可做消息队列。
  • 集合(Set):无序不重复集合,支持交集、并集、差集等聚合操作。
  • 有序集合(Sorted Set):基于跳表实现,元素带分数(score),支持按分数范围查询、排名等。
  • 哈希(Hash):存储键值对集合,适合存对象(如用户信息)。
  • 位图(Bitmap):按位存储,用于统计(如日活用户)。
  • HyperLogLog:基数统计(近似去重计数)。
  • 地理空间(Geo):存储地理位置信息,支持距离计算、范围查询。

3. 高可靠性

通过持久化机制复制机制保证数据不丢失、服务高可用:

  • 持久化:RDB 快照 + AOF 日志,确保内存数据能持久化到磁盘。
  • 复制:主从复制实现读写分离、故障转移,提升系统可靠性。

三、Redis 适用场景:什么时候该用 Redis?

Redis 不是银弹,这些场景最能发挥它的价值:

  • 缓存层:缓解数据库压力,存储热点数据(如商品详情、用户会话)。
  • 计数器:利用 String 自增特性,实现文章阅读数、点赞数、限流计数等。
  • 消息队列:通过 List 的 lpush/brpop 或 Pub/Sub 实现简单消息队列。
  • 分布式锁:解决分布式系统中资源竞争问题(如秒杀、订单防重)。
  • 实时统计:借助 Set、Sorted Set、HyperLogLog 实现 UV 统计、排行榜、去重计数等。
  • 地理位置服务:通过 Geo 结构实现附近的人、打车距离计算等功能。

四、Redis vs MySQL

1.核心区别在哪里?

特性RedisMySQL
存储介质内存(支持持久化到磁盘)磁盘
数据结构丰富(String、List、Set 等 8 种)基于表的关系型结构
性能极高(万级 QPS)较低(千级 QPS,依赖索引优化)
事务支持简单事务(不支持回滚)完整事务(ACID 特性)
适用场景缓存、高并发计数、实时统计等持久化业务数据、复杂关系查询

2.Redis 与 MySQL 一致性问题

在缓存与数据库双写场景下,容易出现数据一致性问题,常见解决方案:

  • 延时双删:写数据库后,删除缓存 → 休眠一段时间(如 500ms)→ 再次删除缓存(防止读写并发导致的脏数据)。
  • 读时双检:读缓存时,若缓存命中则返回;若未命中,先查数据库,再将数据写入缓存(需加锁避免并发写脏数据)。
  • Canal 订阅 binlog:通过 Canal 监听 MySQL binlog,异步更新 Redis 缓存,保证最终一致性。

五、Redis 数据结构:每种结构的典型用法

1. String

  • 用法:存储用户 token、商品价格、验证码等;结合 incr/decr 做计数器。
  • 底层:简单动态字符串(SDS),支持预分配空间减少扩容开销。

2. List

  • 用法:做消息队列(lpush + brpop)、存储用户操作历史(如浏览记录)。
  • 底层:双向链表 + 压缩列表(小数据量时)。

3. Set

  • 用法:存储用户标签(如 “喜欢科幻的用户”)、实现抽奖功能(srandmember)。
  • 底层:哈希表 + 整数集合(小整数且无重复时)。

4. Sorted Set

  • 用法:实现排行榜(如 “销量 Top10 商品”)、延迟任务(结合 score 为时间戳)。
  • 底层:跳表 + 哈希表,跳表保证有序性,哈希表保证查询效率。

5. Hash

  • 用法:存储对象(如用户信息:user:{id} → {name: "xxx", age: 18})。
  • 底层:哈希表 + 压缩列表(小数据量时)。

六、Redis 持久化机制:RDB vs AOF

Redis 提供两种持久化方式,保障内存数据能落地到磁盘:

1. RDB(快照持久化)

  • 原理:在指定时间间隔内,将内存中的全量数据快照写入 RDB 文件(如 dump.rdb)。
  • 触发方式
    • 手动触发:save(阻塞)或 bgsave(非阻塞,fork 子进程执行)。
    • 自动触发:配置 save <秒> <修改次数>(如 save 300 10 表示 300 秒内修改 10 次则触发)。
  • 生成 RDB 时如何处理请求bgsave 时,父进程继续处理客户端请求,子进程负责写 RDB 文件,互不影响。
  • 优点:文件体积小,恢复速度快。
  • 缺点:快照间隔内的数据可能丢失(如突然宕机)。

2. AOF( append-only file,追加式日志)

  • 原理:将所有写操作命令以文本形式追加到 AOF 文件,恢复时重新执行这些命令。
  • 触发方式
    • 实时同步(appendfsync always):每次写操作都同步到磁盘,性能差但安全性高。
    • 每秒同步(appendfsync everysec):每秒同步一次,是默认且推荐的配置。
    • 操作系统控制(appendfsync no):由操作系统决定何时同步,性能好但安全性低。
  • 优点:数据丢失少(最多丢失 1 秒数据),日志可读性强。
  • 缺点:AOF 文件体积大,恢复速度比 RDB 慢。

3. 混合持久化(Redis 4.0+)

结合 RDB 和 AOF 的优点:AOF 文件中前半部分是 RDB 格式的全量数据,后半部分是增量的 AOF 命令。恢复时先加载 RDB 部分,再执行增量 AOF 命令,兼顾了恢复速度和数据安全性。

七、Redis 缓存常见问题:穿透、击穿、雪崩

1. 缓存穿透

  • 问题:大量请求访问缓存和数据库都不存在的数据,导致请求直接打在数据库上,可能压垮数据库。
  • 解决方案
    • 布隆过滤器:提前过滤不存在的键。
    • 缓存空值:即使数据库无数据,也在缓存中存一个空值(设置短过期时间)。

2. 缓存击穿

  • 问题:某个热点 key 过期瞬间,大量请求同时访问该 key,直接打在数据库上。
  • 解决方案
    • 热点 key 永不过期:业务层面保证热点数据长期有效。
    • 互斥锁:第一个请求构建缓存时,其他请求等待(如用 Redis 分布式锁)。

3. 缓存雪崩

  • 问题:大量 key 在同一时间过期,或 Redis 集群宕机,导致请求大量涌入数据库。
  • 解决方案
    • 过期时间打散:为 key 设置随机过期时间,避免集中过期。
    • 多级缓存:结合本地缓存(如 Guava Cache)和 Redis 缓存,降低单缓存层压力。
    • 集群高可用:通过主从、哨兵或集群模式保证 Redis 服务不宕机。

八、Redis 内存满了怎么办?过期淘汰策略

当 Redis 内存达到 maxmemory 限制时,会触发过期淘汰策略删除部分 key,释放内存:

  • volatile-lru:在设置了过期时间的 key中,淘汰最近最少使用的 key。
  • volatile-ttl:在设置了过期时间的 key 中,淘汰剩余过期时间最短的 key。
  • volatile-random:在设置了过期时间的 key 中,随机淘汰。
  • volatile-lfu:在设置了过期时间的 key 中,淘汰最近最少频率使用的 key(Redis 4.0+ 支持)。
  • allkeys-lru:在所有 key中,淘汰最近最少使用的 key。
  • allkeys-random:在所有 key 中,随机淘汰。
  • allkeys-lfu:在所有 key 中,淘汰最近最少频率使用的 key(Redis 4.0+ 支持)。
  • noeviction:默认策略,不淘汰任何 key,写操作会报错。

九、Redis 性能瓶颈与解决方案

1. 单点故障(主从复制 + 哨兵机制)

  • 问题:单台 Redis 宕机导致服务不可用。
  • 解决方案
    • 主从复制:一台主节点(写),多台从节点(读),实现读写分离和数据备份。
    • 哨兵(Sentinel):监控主从节点状态,当主节点宕机时自动将从节点提升为主节点,实现故障转移

2. 数据量过大(集群)

  • 问题:单台 Redis 内存 / 性能无法支撑海量数据。
  • 解决方案:Redis 集群(Cluster),通过 ** 哈希槽(16384 个)** 将数据分片到多台节点,支持横向扩容。

十、Redis 分布式锁:如何实现与常见问题

1. 基础分布式锁实现(Redis 命令)

Redis 支持通过 Lua 脚本执行原子性操作,优点:

  • 减少网络往返:将多个命令打包成脚本执行,降低网络开销。
  • 原子性保证:脚本执行过程中不会被其他命令打断。

典型用法:实现复杂的业务逻辑(如库存扣减 + 订单创建)、分布式锁的原子性释放等。

利用 Redis 的 setnx(set if not exists)命令实现:

lua

# 加锁:key 为锁标识,value 为随机值(用于释放时校验),ex 为过期时间
set lock:order {randomValue} nx ex 10

# 释放锁:通过 Lua 脚本保证原子性(先校验 value,再删除)
if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

2. 常见问题与解决方案

(1)锁丢失问题
  • 场景:锁过期了,但业务还没执行完,导致其他线程获取到锁。
  • 解决方案
    • Redisson 看门狗机制:自动延长锁的过期时间,只要业务还在执行,锁就不会过期。
    • 业务逻辑优化:缩短持有锁的时间,或预估业务执行时间,合理设置锁过期时间。
(2)RedLock 红锁(多节点分布式锁)
  • 原理:在多个独立的 Redis 节点(如 5 个)上同时加锁,超过半数节点加锁成功则认为锁获取成功,保证分布式环境下的锁可靠性。
  • 适用场景:对锁安全性要求极高的场景(如金融交易)。
(3)Redisson 分布式锁
  • 优势:封装了复杂的分布式锁逻辑,支持自动续期(看门狗)、可重入、公平锁等特性,使用简单。

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值