
一、基础概念
1. Redis 有哪些数据结构?各自的应用场景是什么?
答案:
Redis 支持以下数据结构:
- String :最基础类型,存储字符串、数字、二进制数据。
场景:缓存用户信息、计数器、分布式锁。 - Hash :键值对集合,类似 Java 的 HashMap。
场景:存储对象(如用户属性)。 - List :双向链表,支持左右插入和弹出。
场景:消息队列(LPUSH + RPOP)、微博时间线。 - Set :无序唯一集合,支持交集、并集、差集操作。
场景:好友关系、标签系统。 - Sorted Set :有序唯一集合,基于跳表实现。
场景:排行榜、带权重的任务队列。 - BitMap :位操作,存储空间极小。
场景:用户签到、统计活跃用户。 - HyperLogLog :基数统计,误差率约 0.81%。
场景:统计 UV。 - Geospatial :地理空间索引。
场景:附近的人、路线规划。
Java 示例(Jedis):
java
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("user:10086", "{\"name\":\"Alice\",\"age\":25}");
2. Redis 持久化机制有哪些?区别是什么?
答案:
Redis 提供两种持久化方式:
-
RDB(快照)
- 定期将内存数据快照写入磁盘。
- 优点:恢复速度快,适合全量备份。
- 缺点:可能丢失最后一次快照后的所有数据。
- 配置:
save 900 1
(900 秒内至少 1 次修改触发快照)。
-
AOF(Append-Only File)
- 记录所有写操作命令,追加到日志文件。
- 优点:数据更完整(可配置每秒刷盘)。
- 缺点:文件体积大,恢复速度较慢。
- 配置:
appendonly yes
,appendfsync everysec
。
最佳实践:
同时开启 RDB 和 AOF,AOF 用于保证数据完整性,RDB 用于快速恢复。
二、核心原理
3. Redis 为什么单线程还能高性能?
答案:
- 纯内存操作:数据存储在内存中,读写速度极快。
- 非阻塞 I/O:使用多路复用(epoll)处理大量连接。
- 单线程避免上下文切换:减少线程间竞争和锁开销。
- 优化数据结构:例如跳表、哈希表的高效实现。
扩展:
Redis 6.0 引入多线程处理网络请求,但核心逻辑仍为单线程。
4. Redis 如何实现分布式锁?
答案:
Redis 分布式锁的实现方案:
-
SETNX + EXPIRE (存在原子性问题):
javaString result = jedis.set("lock_key", "unique_value", "NX", "EX", 10); if ("OK".equals(result)) { // 获得锁,执行业务逻辑 jedis.del("lock_key"); }
-
RedLock 算法 (Redis 官方推荐):
- 基于多个独立 Redis 节点,避免单点故障。
- 步骤:
① 向半数以上节点获取锁;
② 计算总耗时,若超过锁有效期则释放所有锁。
注意事项:
- 锁的有效期需合理设置,防止业务未完成锁已过期。
- 使用 UUID 保证解锁时的幂等性,避免误删他人锁。
三、集群与高可用
5. Redis Cluster 的分片机制是什么?
答案:
Redis Cluster 使用**哈希槽(Hash Slot)**分配数据:
- 总共有 16384 个槽,每个键通过 CRC16 算法计算哈希值,对 16384 取模得到槽位。
- 每个节点负责一部分槽,槽位可动态迁移。
- 客户端通过询问节点或缓存槽位信息,直接定位数据所在节点。
Java 示例(JedisCluster):
java
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("node1", 6379));
JedisCluster jedisCluster = new JedisCluster(nodes);
jedisCluster.set("key", "value");
6. Redis 主从复制的原理是什么?
答案:
主从复制流程:
- 全量复制 :
- 从节点发送
SYNC
命令,主节点生成 RDB 文件并发送给从节点。 - 主节点将后续写命令缓存,待 RDB 同步完成后发送给从节点。
- 从节点发送
- 增量复制 :
- 全量复制完成后,主节点将写命令以
PSYNC
方式同步给从节点。
- 全量复制完成后,主节点将写命令以
配置:
slaveof <master_ip> <master_port>
。
四、性能与优化
7. 如何避免 Redis 缓存雪崩?
答案:
缓存雪崩指大量缓存同时失效,导致数据库压力激增。解决方案:
- 设置随机过期时间:避免所有键集中过期。
- 加锁限流:使用分布式锁(如 RedLock)保证同一时间只有少量请求访问数据库。
- 二级缓存:本地缓存(如 Caffeine)作为 Redis 的降级方案。
- 服务熔断:通过 Hystrix 等框架暂时拒绝部分请求。
8. Redis 内存淘汰策略有哪些?
答案:
Redis 内存不足时的淘汰策略(maxmemory-policy
):
noeviction
:默认策略,内存不足时拒绝写操作。allkeys-lru
:淘汰所有键中最久未使用的键。volatile-lru
:仅淘汰设置了过期时间的键中最久未使用的键。allkeys-random
:随机淘汰键。volatile-ttl
:优先淘汰剩余存活时间最短的键。
最佳实践:
通常使用 allkeys-lru
,并结合监控调整内存大小。
五、实战问题
9. 如何监控 Redis 的慢查询?
答案:
-
配置慢查询日志 :
confslowlog-log-slower-than 10000 # 超过 10ms 的查询记录日志 slowlog-max-len 128 # 最多保存 128 条慢查询
-
Java 监控工具 :
使用Redis Sentinel
或Redis Insight
分析慢查询。
通过 Jedis 执行SLOWLOG GET
命令获取慢查询列表。
10. Redis 事务支持回滚吗?
答案:
Redis 事务不支持回滚,因为设计哲学是"快速失败":
- 若事务中的命令在入队阶段出现语法错误,整个事务会被取消。
- 若命令在执行阶段失败(如操作类型错误),其他命令仍会执行。
- 需通过应用层逻辑保证数据一致性。
示例:
java
Transaction transaction = jedis.multi();
transaction.set("a", "1");
transaction.incr("a"); // 类型错误,执行时失败
transaction.exec(); // 返回 [OK, (error) ERR value is not an integer or out of range]
总结
Redis 是 Java 高级工程师必须掌握的核心技术,需深入理解其数据结构、持久化、集群、锁机制等。面试中常考察问题的实际应用和原理结合,建议结合源码和生产实践进一步巩固。