
本文主要介绍Redis 的面试题,涵盖持久化、集群、缓存策略、事务等方面
一、持久化机制
1. RDB 与 AOF 的核心区别及适用场景?
答案:
特性 | RDB | AOF |
---|---|---|
存储内容 | 内存快照(二进制文件) | 写命令日志(文本格式) |
数据完整性 | 可能丢失最后一次快照后的数据 | 可配置 everysec 保证秒级丢失 |
恢复速度 | 快(直接加载二进制文件) | 慢(需重放所有命令) |
文件大小 | 小(压缩) | 大(未压缩) |
适用场景 | 定期全量备份,快速恢复 | 实时备份,数据完整性要求高 |
混合持久化(Redis 4.0+):
AOF 重写时会将 RDB 快照写入文件开头,结合两者优势。
2. RDB 快照触发机制有哪些?
答案:
- 自动触发 :
- 满足
save
配置条件(如save 60 1000
)。 - 执行
flushall
命令。 - 主从复制时主节点生成快照。
- 满足
- 手动触发 :
SAVE
(阻塞主线程)。BGSAVE
(后台 fork 子进程生成快照)。
二、集群与高可用
3. Redis Cluster 节点通信机制是什么?
答案:
- Gossip 协议 :节点通过周期性广播
PING/PONG
消息同步集群状态。 - 消息类型 :
MEET
:邀请新节点加入集群。PONG
:响应请求或广播自身状态。FAIL
:标记节点为下线。
- 节点握手:新节点加入时需与至少一个已知节点通信,逐步同步整个集群的槽位映射。
4. Redis Sentinel 如何实现故障转移?
答案:
- 监控 :Sentinel 定期向主从节点发送
PING
检测存活状态。 - 主观下线(SDOWN):若节点超时未响应,标记为 SDOWN。
- 客观下线(ODOWN):半数以上 Sentinel 确认节点不可达时,标记为 ODOWN。
- 选举领导者:Sentinel 通过 Raft 协议选举主节点。
- 故障转移 :
- 提升某个从节点为主节点。
- 其他从节点重新指向新主节点。
- 通知客户端新主节点地址。
三、缓存策略
5. 缓存穿透、缓存雪崩、缓存击穿的区别与解决方案?
答案:
问题 | 描述 | 解决方案 |
---|---|---|
穿透 | 查询不存在的数据,直接打到数据库 | 布隆过滤器、空值缓存(设置短过期时间) |
雪崩 | 大量缓存同时过期,数据库压力激增 | 随机过期时间、加锁限流、二级缓存 |
击穿 | 热点数据过期瞬间,大量请求打到数据库 | 互斥锁(SETNX )、永不过期(异步更新) |
Java 示例(布隆过滤器):
java
BloomFilter<String> bloomFilter = BloomFilter.create(
Funnels.stringFunnel(Charset.defaultCharset()),
1000000, 0.01); // 100万容量,误差率1%
if (!bloomFilter.mightContain(key)) {
return null; // 直接返回,避免查数据库
}
6. Redis 内存淘汰策略中 LRU 和 LFU 的区别?
答案:
- LRU(Least Recently Used):淘汰最久未使用的键。
- LFU(Least Frequently Used):淘汰访问频率最低的键。
- Redis 实现 :
- LRU 使用近似算法(随机采样+淘汰最旧)。
- LFU 通过
logc(访问频率)
和lru(最近访问时间)
综合判断。
- 适用场景 :
- LRU 适合热点数据不明显的场景。
- LFU 适合长期低频但短期高频的键(如促销活动商品)。
四、事务与并发控制
7. Redis 事务的原子性如何保证?
答案:
Redis 事务不保证原子性,但通过以下机制提供部分保证:
- 入队阶段:所有命令先放入队列,若语法错误则整个事务被取消。
- 执行阶段:命令按顺序执行,中途出错不回滚,但后续命令仍执行。
- WATCH 机制:通过乐观锁监控键变化,若被修改则事务失败。
示例(WATCH 实现 CAS):
java
jedis.watch("balance");
String balance = jedis.get("balance");
if (Integer.parseInt(balance) >= 100) {
Transaction tx = jedis.multi();
tx.decrBy("balance", 100);
List<Object> result = tx.exec();
if (result == null) {
// 数据被修改,重试逻辑
}
}
jedis.unwatch();
8. Redis 如何实现乐观锁?
答案:
- WATCH/MULTI/EXEC :
- 监控指定键,若事务执行前键被修改,
EXEC
返回null
。
- 监控指定键,若事务执行前键被修改,
- Check-and-Set(CAS) :
- 使用
GETSET
或SET key value NX
实现条件更新。
- 使用
- 版本号机制 :
- 对每个键维护版本号,更新时校验版本号是否匹配。
五、实战优化
9. Redis 连接池的配置参数有哪些?
答案:
- MaxTotal:最大连接数(默认 8)。
- MaxIdle:最大空闲连接数(默认 8)。
- MinIdle:最小空闲连接数(默认 0)。
- MaxWaitMillis:获取连接的最大等待时间(默认 -1,无限等待)。
- TestOnBorrow :获取连接时是否测试连通性(默认
false
)。
Java 配置示例(JedisPoolConfig):
java
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(100);
config.setMaxIdle(20);
config.setTestOnBorrow(true);
JedisPool jedisPool = new JedisPool(config, "localhost", 6379);
10. 如何监控 Redis 的内存使用情况?
答案:
- 命令行工具 :
INFO memory
:查看内存使用统计。MEMORY USAGE key
:查看单个键的内存占用。
- 可视化工具 :
- RedisInsight、Prometheus + Grafana。
- 关键指标 :
used_memory
:已使用内存。mem_fragmentation_ratio
:内存碎片率(理想值 1.0-1.5)。evicted_keys
:被淘汰的键数量。
总结
Redis 的核心设计理念(单线程、内存优先、异步持久化)是理解其高性能的关键。面试中需结合具体场景分析问题,如缓存策略需区分穿透/雪崩/击穿的不同解决方案,集群需掌握节点通信和故障转移原理。建议通过 Redis-cli
实操和源码阅读加深理解。