【面试题系列】Redis 常见面试题&答案

一、基础概念

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 yesappendfsync everysec

最佳实践:

同时开启 RDB 和 AOF,AOF 用于保证数据完整性,RDB 用于快速恢复。

二、核心原理

3. Redis 为什么单线程还能高性能?

答案:

  • 纯内存操作:数据存储在内存中,读写速度极快。
  • 非阻塞 I/O:使用多路复用(epoll)处理大量连接。
  • 单线程避免上下文切换:减少线程间竞争和锁开销。
  • 优化数据结构:例如跳表、哈希表的高效实现。

扩展:

Redis 6.0 引入多线程处理网络请求,但核心逻辑仍为单线程。

4. Redis 如何实现分布式锁?

答案:

Redis 分布式锁的实现方案:

  1. SETNX + EXPIRE (存在原子性问题):

    java 复制代码
    String result = jedis.set("lock_key", "unique_value", "NX", "EX", 10);
    if ("OK".equals(result)) {
        // 获得锁,执行业务逻辑
        jedis.del("lock_key");
    }
  2. 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 主从复制的原理是什么?

答案:

主从复制流程:

  1. 全量复制
    • 从节点发送 SYNC 命令,主节点生成 RDB 文件并发送给从节点。
    • 主节点将后续写命令缓存,待 RDB 同步完成后发送给从节点。
  2. 增量复制
    • 全量复制完成后,主节点将写命令以 PSYNC 方式同步给从节点。

配置:
slaveof <master_ip> <master_port>

四、性能与优化

7. 如何避免 Redis 缓存雪崩?

答案:

缓存雪崩指大量缓存同时失效,导致数据库压力激增。解决方案:

  1. 设置随机过期时间:避免所有键集中过期。
  2. 加锁限流:使用分布式锁(如 RedLock)保证同一时间只有少量请求访问数据库。
  3. 二级缓存:本地缓存(如 Caffeine)作为 Redis 的降级方案。
  4. 服务熔断:通过 Hystrix 等框架暂时拒绝部分请求。

8. Redis 内存淘汰策略有哪些?

答案:

Redis 内存不足时的淘汰策略(maxmemory-policy):

  • noeviction:默认策略,内存不足时拒绝写操作。
  • allkeys-lru:淘汰所有键中最久未使用的键。
  • volatile-lru:仅淘汰设置了过期时间的键中最久未使用的键。
  • allkeys-random:随机淘汰键。
  • volatile-ttl:优先淘汰剩余存活时间最短的键。

最佳实践:

通常使用 allkeys-lru,并结合监控调整内存大小。

五、实战问题

9. 如何监控 Redis 的慢查询?

答案:

  • 配置慢查询日志

    conf 复制代码
    slowlog-log-slower-than 10000  # 超过 10ms 的查询记录日志
    slowlog-max-len 128           # 最多保存 128 条慢查询
  • Java 监控工具
    使用 Redis SentinelRedis 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 高级工程师必须掌握的核心技术,需深入理解其数据结构、持久化、集群、锁机制等。面试中常考察问题的实际应用和原理结合,建议结合源码和生产实践进一步巩固。

相关推荐
try again!7 分钟前
个性化音乐推荐系统
android·数据库·sqlite
安 当 加 密1 小时前
TDE透明加密:免改造实现SQLServer数据库安全存储
数据库·sqlserver
fmdpenny2 小时前
Django创建数据库表失败处理方法
数据库·python·django
BirdMan982 小时前
Flask中实现对User模型的增删改查,并通过Flask-Alchemy与MySQL数据库交互
数据库·mysql·flask
xcbeyond2 小时前
Redis Sentinel 及 Redisson 连接问题全解析
redis·bootstrap·sentinel
isolusion2 小时前
Redis 主从复制详解:实现高可用与数据备份
数据库·redis·缓存
极客先躯3 小时前
高级java每日一道面试题-2025年2月18日-数据库篇-MySQL 如何做到高可用方案?
java·数据库·mysql·架构·高可用
墨香染城城4 小时前
Mmybatis xml 连接数据库的方法
xml·数据库
不要小看我们之间的羁绊啊4 小时前
PostgreSQL 多数据库集簇配置及多数据库复制方法【流程+代码实例】
数据库·postgresql
坐山龟4 小时前
PostgreSQL16 的双向逻辑复制
数据库·笔记·postgresql