【Redis】Redis面试高频考点汇总Day15(2026年)

写在前面

经过前面14天的学习,我们已经全面掌握了Redis的核心知识。今天是Redis系列的最后一篇,我们将系统梳理Redis面试高频考点,帮助大家查漏补缺,顺利通过面试。

文章目录

    • 写在前面
    • 一、Redis基础面试题
      • [1.1 Redis是什么?有什么特点?](#1.1 Redis是什么?有什么特点?)
      • [1.2 Redis为什么这么快?](#1.2 Redis为什么这么快?)
      • [1.3 Redis单线程为什么还能高并发?](#1.3 Redis单线程为什么还能高并发?)
      • [1.4 Redis和Memcached的区别?](#1.4 Redis和Memcached的区别?)
    • 二、数据结构面试题
      • [2.1 Redis有哪些数据类型?各有什么应用场景?](#2.1 Redis有哪些数据类型?各有什么应用场景?)
      • [2.2 Redis String的内部编码有哪些?](#2.2 Redis String的内部编码有哪些?)
      • [2.3 Redis Hash的底层实现?](#2.3 Redis Hash的底层实现?)
      • [2.4 Redis ZSet为什么使用跳表而不是红黑树?](#2.4 Redis ZSet为什么使用跳表而不是红黑树?)
      • [2.5 Redis List的底层实现?](#2.5 Redis List的底层实现?)
    • 三、持久化面试题
      • [3.1 Redis持久化机制有哪些?](#3.1 Redis持久化机制有哪些?)
      • [3.2 RDB和AOF如何选择?](#3.2 RDB和AOF如何选择?)
      • [3.3 AOF重写是什么?](#3.3 AOF重写是什么?)
      • [3.4 Redis重启时如何选择恢复方式?](#3.4 Redis重启时如何选择恢复方式?)
    • 四、高可用面试题
      • [4.1 Redis主从复制的原理?](#4.1 Redis主从复制的原理?)
      • [4.2 哨兵模式的原理?](#4.2 哨兵模式的原理?)
      • [4.3 Redis Cluster的原理?](#4.3 Redis Cluster的原理?)
      • [4.4 Cluster和哨兵的区别?](#4.4 Cluster和哨兵的区别?)
    • 五、缓存应用面试题
      • [5.1 什么是缓存穿透、击穿、雪崩?](#5.1 什么是缓存穿透、击穿、雪崩?)
      • [5.2 如何保证缓存和数据库一致性?](#5.2 如何保证缓存和数据库一致性?)
      • [5.3 为什么是删除缓存而不是更新缓存?](#5.3 为什么是删除缓存而不是更新缓存?)
    • 六、分布式锁面试题
      • [6.1 Redis分布式锁如何实现?](#6.1 Redis分布式锁如何实现?)
      • [6.2 Redis分布式锁的可靠性如何保证?](#6.2 Redis分布式锁的可靠性如何保证?)
      • [6.3 Redis分布式锁和Zookeeper分布式锁的区别?](#6.3 Redis分布式锁和Zookeeper分布式锁的区别?)
    • 七、性能优化面试题
      • [7.1 如何排查Redis性能问题?](#7.1 如何排查Redis性能问题?)
      • [7.2 如何优化Redis内存使用?](#7.2 如何优化Redis内存使用?)
      • [7.3 为什么KEYS命令在生产环境禁用?](#7.3 为什么KEYS命令在生产环境禁用?)
    • 八、其他高频面试题
      • [8.1 Redis如何实现消息队列?](#8.1 Redis如何实现消息队列?)
      • [8.2 Redis如何实现延迟队列?](#8.2 Redis如何实现延迟队列?)
      • [8.3 Redis如何实现限流?](#8.3 Redis如何实现限流?)
      • [8.4 Redis如何实现分布式Session?](#8.4 Redis如何实现分布式Session?)
      • [8.5 Redis内存满了怎么办?](#8.5 Redis内存满了怎么办?)
    • 九、学习路线总结
      • [9.1 Redis学习路线图](#9.1 Redis学习路线图)
      • [9.2 面试重点总结](#9.2 面试重点总结)
    • 十、参考资料
    • 十一、互动话题

一、Redis基础面试题

1.1 Redis是什么?有什么特点?

答案:

Redis(Remote Dictionary Server)是一个开源的、基于内存的高性能键值对数据库。

主要特点:

特点 说明
高性能 基于内存,读写速度极快(10万+QPS)
丰富数据类型 String、Hash、List、Set、ZSet、Bitmap、HyperLogLog、Geo、Stream
持久化 RDB和AOF两种持久化方式
高可用 主从复制、哨兵模式、Cluster集群
单线程 核心处理流程采用单线程模型
支持事务 提供事务支持,保证原子性

1.2 Redis为什么这么快?

答案:

原因 说明
基于内存 数据存储在内存中,读写速度极快
单线程模型 避免多线程上下文切换开销
IO多路复用 使用epoll实现高并发连接处理
高效数据结构 使用跳表、压缩列表等高效数据结构
协议简单 RESP协议简单高效

详细解释:

  1. 单线程模型:Redis核心处理流程采用单线程,避免了多线程的锁竞争和上下文切换开销。

  2. IO多路复用:Redis使用epoll(Linux)实现IO多路复用,单线程可以处理大量并发连接。

  3. 高效数据结构:

    • 字符串使用SDS(Simple Dynamic String)
    • 列表使用quicklist
    • 有序集合使用跳表
    • 小数据量使用压缩列表

1.3 Redis单线程为什么还能高并发?

答案:

  1. 纯内存操作:内存访问速度极快,纳秒级

  2. 非阻塞IO:使用epoll实现IO多路复用,单线程处理多个连接

  3. 避免锁竞争:单线程不需要加锁,避免了锁开销

  4. CPU亲和性:单线程可以充分利用CPU缓存

注意:Redis 6.0引入了多线程,用于网络IO处理,核心命令执行仍然是单线程。

1.4 Redis和Memcached的区别?

答案:

对比项 Redis Memcached
数据类型 丰富(5种基础+扩展) 仅支持String
持久化 支持RDB/AOF 不支持
集群 原生支持Cluster 需要客户端分片
事务 支持 不支持
内存管理 更灵活 更简单
性能 高 高(略快于Redis)
适用场景 缓存+数据存储 纯缓存

二、数据结构面试题

2.1 Redis有哪些数据类型?各有什么应用场景?

答案:

数据类型 底层实现 应用场景
String SDS 缓存、计数器、分布式锁
Hash ziplist/hashtable 对象存储、购物车
List quicklist 消息队列、文章列表
Set intset/hashtable 标签、共同关注
ZSet skiplist+dict 排行榜、延时队列
Bitmap String 签到、布隆过滤器
HyperLogLog String 基数统计
Geo ZSet 地理位置
Stream listpack 消息队列

2.2 Redis String的内部编码有哪些?

答案:

编码 条件 特点
int 整数值且范围在long内 内存占用最小
embstr 字符串长度≤44字节 一次分配,紧凑存储
raw 字符串长度>44字节 SDS实现,可修改

查看编码:

redis 复制代码
OBJECT ENCODING mykey

2.3 Redis Hash的底层实现?

答案:

Redis Hash底层使用两种编码:

  1. ziplist(压缩列表):

    • 条件:元素数≤512,所有值长度≤64字节
    • 特点:内存紧凑,适合小数据量
    • 时间复杂度:O(N)
  2. hashtable(哈希表):

    • 条件:不满足ziplist条件
    • 特点:O(1)时间复杂度
    • 扩容:负载因子>1时扩容

2.4 Redis ZSet为什么使用跳表而不是红黑树?

答案:

对比项 跳表 红黑树
实现复杂度 简单 复杂
范围查询 高效 需要中序遍历
内存占用 略高 较低
并发友好 更好 一般
插入删除 简单 需要旋转调整

Redis选择跳表的原因:

  1. 实现简单:跳表比红黑树更容易实现和维护

  2. 范围查询高效:跳表在找到起点后,可以顺序遍历,效率更高

  3. 内存效率:虽然跳表内存略高,但Redis主要瓶颈不在内存

2.5 Redis List的底层实现?

答案:

Redis 3.2之后,List使用quicklist(快速列表)实现:

  • quicklist是ziplist的双向链表
  • 结合了ziplist的内存紧凑和链表的快速插入删除
  • 可以配置每个ziplist的大小和压缩策略
conf 复制代码
# 配置参数
list-max-ziplist-size -2  # 每个ziplist大小
list-compress-depth 0     # 压缩深度

三、持久化面试题

3.1 Redis持久化机制有哪些?

答案:

机制 RDB AOF
方式 快照 日志追加
文件大小 小 大
恢复速度 快 慢
数据安全性 可能丢失 更安全
系统资源 CPU消耗大 IO消耗大
适用场景 备份、主从复制 数据安全要求高

3.2 RDB和AOF如何选择?

答案:

推荐方案:同时开启RDB和AOF

场景 推荐方案
数据安全要求高 开启AOF
允许少量数据丢失 只开启RDB
生产环境 同时开启RDB+AOF
纯缓存场景 可不持久化

配置建议:

conf 复制代码
# RDB配置
save 900 1
save 300 10
save 60 10000

# AOF配置
appendonly yes
appendfsync everysec

3.3 AOF重写是什么?

答案:

AOF重写原理:

  • 随着写操作增加,AOF文件越来越大
  • 重写会创建一个新的AOF文件,只保留最终数据的写入命令
  • 重写过程中不影响正常服务

重写触发条件:

conf 复制代码
# AOF文件大小超过上次重写后大小的100%
auto-aof-rewrite-percentage 100
# AOF文件最小64MB才触发重写
auto-aof-rewrite-min-size 64mb

重写流程:

  1. Redis创建子进程进行重写
  2. 子进程根据内存数据生成新的AOF文件
  3. 父进程继续处理命令,写入AOF重写缓冲区
  4. 子进程完成后,父进程将重写缓冲区追加到新文件
  5. 用新文件替换旧AOF文件

3.4 Redis重启时如何选择恢复方式?

答案:

Redis启动时恢复数据的优先级:

  1. 如果开启AOF,优先使用AOF恢复
  2. 如果只开启RDB,使用RDB恢复
  3. 如果AOF文件损坏,可以使用redis-check-aof修复
shell 复制代码
# 修复AOF文件
redis-check-aof --fix appendonly.aof

# 检查RDB文件
redis-check-rdb dump.rdb

四、高可用面试题

4.1 Redis主从复制的原理?

答案:

主从复制流程:

复制代码
从节点连接主节点
    ↓
发送SYNC命令
    ↓
主节点执行BGSAVE生成RDB
    ↓
主节点发送RDB给从节点
    ↓
从节点加载RDB
    ↓
主节点发送缓冲区写命令
    ↓
进入增量复制阶段

复制方式:

方式 说明
全量复制 第一次同步或断开时间较长
增量复制 断开后重连,只同步差异部分
异步复制 主节点写完立即返回,异步同步

4.2 哨兵模式的原理?

答案:

哨兵功能:

  1. 监控:持续检查主从节点是否正常
  2. 通知:节点故障时通知管理员或其他应用
  3. 自动故障转移:主节点故障时自动选举新主节点

故障转移流程:

复制代码
哨兵检测主节点下线(主观下线)
    ↓
多个哨兵确认(客观下线)
    ↓
哨兵选举领导者
    ↓
领导者选举新主节点
    ↓
更新其他从节点的复制目标
    ↓
通知客户端新主节点地址

配置示例:

conf 复制代码
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000

4.3 Redis Cluster的原理?

答案:

核心概念:

  1. 哈希槽:将数据划分为16384个槽,分配给不同节点

  2. 数据分片:每个节点负责一部分槽

  3. Gossip协议:节点间通信,交换状态信息

槽位计算:

复制代码
slot = CRC16(key) % 16384

MOVED重定向:

当客户端访问的key不在当前节点时,返回MOVED错误,告知正确的节点。

4.4 Cluster和哨兵的区别?

答案:

对比项 Cluster 哨兵
数据分片 支持 不支持
高可用 支持 支持
最小节点数 6个 3个
扩展性 支持在线扩容 不支持
客户端 需要集群客户端 普通客户端
复杂度 较高 较低
适用场景 大数据量 小数据量

五、缓存应用面试题

5.1 什么是缓存穿透、击穿、雪崩?

答案:

问题 原因 解决方案
缓存穿透 查询不存在的数据 布隆过滤器、空值缓存
缓存击穿 热点key过期 互斥锁、热点预热
缓存雪崩 大量key同时过期 随机过期时间、多级缓存

详细解答:

缓存穿透:

  • 现象:查询不存在的key,请求穿透到数据库
  • 解决:布隆过滤器过滤不存在的key,或缓存空值

缓存击穿:

  • 现象:热点key过期瞬间,大量请求打到数据库
  • 解决:加互斥锁,只允许一个线程查询数据库

缓存雪崩:

  • 现象:大量key同时过期,或Redis宕机
  • 解决:随机过期时间、多级缓存、熔断降级

5.2 如何保证缓存和数据库一致性?

答案:

常用方案:Cache Aside模式

java 复制代码
// 更新数据
public void update(String key, Object value) {
    // 1. 先更新数据库
    db.update(key, value);
    // 2. 再删除缓存
    cache.delete(key);
}

// 读取数据
public Object get(String key) {
    // 1. 先查缓存
    Object value = cache.get(key);
    if (value != null) {
        return value;
    }
    // 2. 查数据库
    value = db.query(key);
    // 3. 写入缓存
    if (value != null) {
        cache.set(key, value, expire);
    }
    return value;
}

延迟双删:

java 复制代码
public void update(String key, Object value) {
    // 1. 删除缓存
    cache.delete(key);
    // 2. 更新数据库
    db.update(key, value);
    // 3. 延迟后再次删除缓存
    Thread.sleep(500);
    cache.delete(key);
}

5.3 为什么是删除缓存而不是更新缓存?

答案:

对比项 删除缓存 更新缓存
复杂度 低 高
性能 高(懒加载) 低(每次写都更新)
一致性 较好 可能不一致
并发问题 较少 较多

原因分析:

  1. 并发安全:删除是幂等操作,更新可能被覆盖

  2. 性能考虑:很多场景缓存可能不会被读取

  3. 数据新鲜:删除后下次读取时加载最新数据


六、分布式锁面试题

6.1 Redis分布式锁如何实现?

答案:

基本实现:

redis 复制代码
# 加锁
SET lock:key value NX PX 30000

# 解锁(Lua脚本保证原子性)
if redis.call('get', KEYS[1]) == ARGV[1] then
    return redis.call('del', KEYS[1])
else
    return 0
end

Java实现:

java 复制代码
public boolean lock(String key, String value, long expireTime) {
    return redisTemplate.opsForValue()
        .setIfAbsent(key, value, expireTime, TimeUnit.MILLISECONDS);
}

public boolean unlock(String key, String value) {
    String script = 
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "    return redis.call('del', KEYS[1]) " +
        "else " +
        "    return 0 " +
        "end";
    Long result = redisTemplate.execute(
        RedisScript.of(script, Long.class),
        Collections.singletonList(key), value);
    return result != null && result == 1L;
}

6.2 Redis分布式锁的可靠性如何保证?

答案:

问题 解决方案
死锁 设置过期时间
误删锁 使用唯一标识校验
锁超时 看门狗自动续期
单点故障 Redlock算法
主从切换丢锁 多节点部署

Redisson实现:

java 复制代码
RLock lock = redisson.getLock("myLock");
try {
    lock.lock();  // 自动续期
    // 执行业务
} finally {
    lock.unlock();
}

6.3 Redis分布式锁和Zookeeper分布式锁的区别?

答案:

对比项 Redis Zookeeper
实现方式 SET NX + 过期时间 临时顺序节点
一致性 最终一致 强一致
性能 高 中
锁释放 主动删除或过期 Session断开自动释放
可重入 需要自己实现 天然支持
适用场景 高并发 高可靠

七、性能优化面试题

7.1 如何排查Redis性能问题?

答案:

排查步骤:

  1. 查看慢查询日志
redis 复制代码
SLOWLOG GET 10
  1. 检查内存使用
redis 复制代码
INFO memory
  1. 检查大key
shell 复制代码
redis-cli --bigkeys
  1. 检查客户端连接
redis 复制代码
CLIENT LIST
  1. 实时监控
redis 复制代码
MONITOR

7.2 如何优化Redis内存使用?

答案:

优化方法 说明
选择合适的数据结构 使用编码效率高的类型
控制key长度 使用简短的key名
使用压缩编码 ziplist、intset
设置过期时间 及时清理无用数据
开启内存碎片整理 activedefrag
避免大key 拆分大key

7.3 为什么KEYS命令在生产环境禁用?

答案:

  1. 时间复杂度O(N):需要遍历所有key

  2. 阻塞主线程:Redis单线程,KEYS执行期间无法处理其他请求

  3. 影响可用性:大量key时可能导致服务不可用

替代方案:使用SCAN命令

redis 复制代码
SCAN 0 MATCH user:* COUNT 100

八、其他高频面试题

8.1 Redis如何实现消息队列?

答案:

方案 实现 特点
List LPUSH + BRPOP 简单,不支持消费组
Pub/Sub PUBLISH + SUBSCRIBE 实时,不持久化
Stream XADD + XREAD 支持消费组,可持久化

Stream实现:

redis 复制代码
# 生产消息
XADD mystream * field1 value1

# 消费消息
XREAD GROUP mygroup consumer1 COUNT 1 STREAMS mystream >

8.2 Redis如何实现延迟队列?

答案:

使用ZSet实现延迟队列:

java 复制代码
// 添加延迟任务
public void addDelayTask(String taskId, long delayTime) {
    long executeTime = System.currentTimeMillis() + delayTime;
    redisTemplate.opsForZSet().add("delay:queue", taskId, executeTime);
}

// 消费延迟任务
public void consumeDelayTask() {
    while (true) {
        long now = System.currentTimeMillis();
        Set<String> tasks = redisTemplate.opsForZSet()
            .rangeByScore("delay:queue", 0, now, 0, 10);
        
        for (String taskId : tasks) {
            // 尝试获取任务
            Long removed = redisTemplate.opsForZSet()
                .remove("delay:queue", taskId);
            if (removed > 0) {
                // 执行任务
                executeTask(taskId);
            }
        }
        Thread.sleep(100);
    }
}

8.3 Redis如何实现限流?

答案:

方案1:计数器限流

java 复制代码
public boolean allowRequest(String key, int limit, long period) {
    long count = redisTemplate.opsForValue().increment(key);
    if (count == 1) {
        redisTemplate.expire(key, period, TimeUnit.SECONDS);
    }
    return count <= limit;
}

方案2:滑动窗口限流

java 复制代码
public boolean allowRequest(String key, int limit, long period) {
    long now = System.currentTimeMillis();
    long start = now - period * 1000;
    
    // 移除过期请求
    redisTemplate.opsForZSet().removeRangeByScore(key, 0, start);
    
    // 统计当前窗口请求数
    long count = redisTemplate.opsForZSet().count(key, start, now);
    
    if (count < limit) {
        redisTemplate.opsForZSet().add(key, UUID.randomUUID().toString(), now);
        return true;
    }
    return false;
}

方案3:令牌桶限流

lua 复制代码
-- Lua脚本实现令牌桶
local tokens = redis.call('get', KEYS[1])
if tokens == false then
    tokens = ARGV[1]
end
if tonumber(tokens) > 0 then
    redis.call('decr', KEYS[1])
    return 1
else
    return 0
end

8.4 Redis如何实现分布式Session?

答案:

java 复制代码
// 存储Session
public void setSession(String sessionId, Object data) {
    String key = "session:" + sessionId;
    redisTemplate.opsForValue().set(key, data, 30, TimeUnit.MINUTES);
}

// 获取Session
public Object getSession(String sessionId) {
    String key = "session:" + sessionId;
    return redisTemplate.opsForValue().get(key);
}

// 删除Session
public void deleteSession(String sessionId) {
    String key = "session:" + sessionId;
    redisTemplate.delete(key);
}

8.5 Redis内存满了怎么办?

答案:

内存淘汰策略:

策略 说明
noeviction 不淘汰,写入报错
allkeys-lru 所有key使用LRU淘汰
volatile-lru 设置过期时间的key使用LRU淘汰
allkeys-lfu 所有key使用LFU淘汰
volatile-lfu 设置过期时间的key使用LFU淘汰
allkeys-random 所有key随机淘汰
volatile-random 设置过期时间的key随机淘汰
volatile-ttl 淘汰即将过期的key

配置:

conf 复制代码
maxmemory 4gb
maxmemory-policy allkeys-lru

九、学习路线总结

9.1 Redis学习路线图

复制代码
基础阶段
├── Redis简介与安装
├── 数据类型与命令
├── 持久化(RDB/AOF)
└── 主从复制

进阶阶段
├── 哨兵模式
├── Cluster集群
├── 缓存应用(穿透/击穿/雪崩)
└── 分布式锁

高级阶段
├── 性能优化
├── 内存管理
├── 监控运维
└── 源码分析

9.2 面试重点总结

知识点 重要程度 考察频率
数据类型与应用场景 ★★★★★ 必考
持久化机制 ★★★★★ 必考
主从复制原理 ★★★★☆ 高频
哨兵模式 ★★★★☆ 高频
Cluster集群 ★★★★☆ 高频
缓存三兄弟 ★★★★★ 必考
分布式锁 ★★★★★ 必考
性能优化 ★★★★☆ 高频

十、参考资料

Redis官方文档


十一、互动话题

恭喜你完成了Redis系列的学习!🎉

  1. 这个系列对你有帮助吗?欢迎反馈学习心得!
  2. 面试中遇到过哪些Redis问题?欢迎分享!
  3. 还想学习哪些技术?欢迎留言建议!

Redis系列文章完结撒花!感谢大家的陪伴!


相关推荐
程序员Sunday4 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
余槐i4 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
数据库小学妹4 小时前
PostgreSQL表膨胀怎么办?autovacuum清不动的根因与排查命令
数据库·postgresql·表膨胀·mvcc·数据库运维
mister_guo5 小时前
MySQL-1267错误:排序规则冲突的原因与解决方案
数据库·mysql
小 黄 鸡5 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
骇客野人5 小时前
在麒麟操作系统上 分别安装 jdk1.8, 达梦数据库,redis ,memcache 的操作实施方案和步骤
数据库·redis·memcached
美狐美颜SDK开放平台7 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
silvamux_7 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
花间相见8 小时前
【计算基础|MySQL01】【上手】安装连接、数据类型与建库建表
数据库·后端
花间相见8 小时前
【计算基础|MySQL02】【上手】SQL 增删改查
数据库·后端