Redis深入
2026/1/15大约 7 分钟Java面试Redis缓存后端
Redis 深入面试题
本章深入讲解 Redis 数据结构底层、持久化、集群、高可用等高频面试考点。
数据结构底层
Q1: Redis 的数据结构和底层实现?
| 数据类型 | 底层实现 | 使用场景 |
|---|---|---|
| String | SDS(简单动态字符串) | 缓存、计数器、分布式锁 |
| List | QuickList(双向链表+压缩列表) | 消息队列、最新列表 |
| Hash | listpack/hashtable | 对象存储 |
| Set | intset/hashtable | 去重、交并差集 |
| ZSet | listpack/skiplist+hashtable | 排行榜、延迟队列 |
Q2: SDS 相比 C 字符串的优势?
| 特性 | C 字符串 | SDS |
|---|---|---|
| 获取长度 | O(n) 遍历 | O(1) 直接读 len |
| 缓冲区溢出 | 可能 | 自动扩容 |
| 二进制安全 | 否(遇 \0 截断) | 是 |
| 内存重分配 | 每次修改都要 | 空间预分配+惰性释放 |
Q3: 跳表是什么?为什么 ZSet 用跳表?
跳表特点:
- 多层索引:通过跳跃快速定位
- 时间复杂度:查找、插入、删除都是 O(log n)
- 空间复杂度:O(n)
为什么不用红黑树?
- 跳表实现更简单
- 范围查询更方便(链表直接遍历)
- 内存占用可控(可调整层数)
Q4: Redis 7.0 的 listpack 是什么?
listpack 是 Redis 7.0 引入的新数据结构,替代 ziplist。
listpack vs ziplist:
- 解决了 ziplist 的连锁更新问题
- 每个 entry 记录自己的长度,不依赖前一个
持久化机制
Q5: RDB 和 AOF 的区别?
| 特性 | RDB | AOF |
|---|---|---|
| 文件格式 | 二进制快照 | 文本命令日志 |
| 数据安全 | 可能丢失分钟级数据 | 最多丢失 1 秒数据 |
| 恢复速度 | 快 | 慢(需重放命令) |
| 文件大小 | 小 | 大(需要重写) |
| 性能影响 | fork 时有影响 | 写入时有影响 |
Q6: AOF 重写是什么?
AOF 重写的作用:
- 压缩 AOF 文件大小
- 去除冗余命令(如多次 SET 同一个 key)
- 不阻塞主进程
Q7: Redis 4.0 的混合持久化?
# 开启混合持久化
aof-use-rdb-preamble yes优势:
- 恢复速度快(RDB 部分)
- 数据安全(AOF 部分)
内存管理
Q8: Redis 的内存淘汰策略?
| 策略 | 说明 |
|---|---|
| noeviction | 不淘汰,内存满时报错 |
| volatile-lru | 淘汰有过期时间的 key,LRU 算法 |
| volatile-lfu | 淘汰有过期时间的 key,LFU 算法 |
| volatile-ttl | 淘汰即将过期的 key |
| allkeys-lru | 淘汰所有 key,LRU 算法 |
| allkeys-lfu | 淘汰所有 key,LFU 算法(推荐) |
Q9: LRU 和 LFU 的区别?
| 算法 | 依据 | 问题 |
|---|---|---|
| LRU | 最近访问时间 | 偶发访问可能保留 |
| LFU | 访问频率 | 历史热点难以淘汰 |
Redis 的 LFU 实现:
- 使用 8 位计数器(0-255)
- 计数器会随时间衰减
- 解决了历史热点问题
高可用架构
Q10: Redis 主从复制原理?
复制方式:
- 全量复制:首次连接或复制积压缓冲区不足
- 增量复制:断线重连,通过 offset 续传
Q11: Redis Sentinel 哨兵机制?
Sentinel 功能:
- 监控:检测主从节点是否正常
- 通知:故障时通知客户端
- 自动故障转移:主节点故障时选举新主
- 配置中心:客户端通过 Sentinel 获取主节点地址
故障转移流程:
Q12: Redis Cluster 集群原理?
Cluster 特点:
- 数据分片:16384 个槽位,分布在不同节点
- 去中心化:节点间 Gossip 协议通信
- 高可用:每个主节点有从节点备份
槽位计算:
// CRC16 算法计算槽位
int slot = CRC16(key) % 16384;Q13: 什么是脑裂?如何解决?
脑裂问题:网络分区导致出现两个 Master,数据不一致。
解决方案:
# 配置最小从节点数
min-replicas-to-write 1
# 配置最大延迟
min-replicas-max-lag 10当主节点连接的从节点少于 1 个,或延迟超过 10 秒,主节点拒绝写入。
应用场景
Q14: Redis 分布式锁的实现?
// 加锁(原子操作)
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent("lock:order", uuid, 30, TimeUnit.SECONDS);
// 释放锁(Lua 脚本保证原子性)
String script = """
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
""";
redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
List.of("lock:order"), uuid);分布式锁问题:
- 锁过期:业务未完成锁就过期 → Redisson 看门狗续期
- 主从切换:主节点宕机锁丢失 → RedLock 算法
Q15: Redis 实现延迟队列?
// 添加延迟任务
long executeTime = System.currentTimeMillis() + delayMs;
redisTemplate.opsForZSet().add("delay:queue", taskId, executeTime);
// 消费延迟任务
Set<String> tasks = redisTemplate.opsForZSet()
.rangeByScore("delay:queue", 0, System.currentTimeMillis(), 0, 10);
for (String taskId : tasks) {
// 原子移除并处理
Long removed = redisTemplate.opsForZSet().remove("delay:queue", taskId);
if (removed > 0) {
processTask(taskId);
}
}小结
Redis 深入面试重点:
- 数据结构底层实现(SDS、跳表、listpack)
- 持久化机制(RDB、AOF、混合持久化)
- 内存淘汰策略(LRU、LFU)
- 高可用架构(主从、Sentinel、Cluster)
- 分布式锁实现和问题
- 延迟队列等应用场景
面试题预览
高频面试题
- Redis 为什么用跳表不用红黑树?
- RDB 和 AOF 的区别?
- Redis Cluster 如何分片?
- 分布式锁有什么问题?如何解决?
- 如何保证缓存和数据库一致性?
