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

embedded/2025/3/14 9:09:25/

在这里插入图片描述

一、基础概念

1. Redis 有哪些数据结构?各自的应用场景是什么?

答案:
Redis 支持以下数据结构:

  • String:最基础类型,存储字符串、数字、二进制数据。
    场景:缓存用户信息、计数器、分布式锁。
  • Hash:键值对集合,类似 Java 的 HashMap。
    场景:存储对象(如用户属性)。
  • List:双向链表,支持左右插入和弹出。
    场景:消息队列(LPUSH + RPOP)、微博时间线。
  • Set:无序唯一集合,支持交集、并集、差集操作。
    场景:好友关系、标签系统。
  • Sorted Set:有序唯一集合,基于跳表实现。
    场景:排行榜、带权重的任务队列。
  • BitMap:位操作,存储空间极小。
    场景:用户签到、统计活跃用户。
  • HyperLogLog:基数统计,误差率约 0.81%。
    场景:统计 UV。
  • Geospatial:地理空间索引。
    场景:附近的人、路线规划。

Java 示例(Jedis):

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(存在原子性问题):
    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):

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 的慢查询?

答案:

  • 配置慢查询日志
    slowlog-log-slower-than 10000  # 超过 10ms 的查询记录日志
    slowlog-max-len 128           # 最多保存 128 条慢查询
    
  • Java 监控工具
    使用 Redis SentinelRedis Insight 分析慢查询。
    通过 Jedis 执行 SLOWLOG GET 命令获取慢查询列表。

10. Redis 事务支持回滚吗?

答案:
Redis 事务不支持回滚,因为设计哲学是“快速失败”:

  • 若事务中的命令在入队阶段出现语法错误,整个事务会被取消。
  • 若命令在执行阶段失败(如操作类型错误),其他命令仍会执行。
  • 需通过应用层逻辑保证数据一致性。

示例:

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 高级工程师必须掌握的核心技术,需深入理解其数据结构、持久化、集群、锁机制等。面试中常考察问题的实际应用和原理结合,建议结合源码和生产实践进一步巩固。


http://www.ppmy.cn/embedded/172454.html

相关文章

考研复试c语言常见问答题汇总2

11. 关键字和一般标识符有什么不同&#xff1f; C语言中关键字与一般标识符区别&#xff1a; 定义&#xff1a;关键字是C语言预定义的特殊单词&#xff08;如int、for&#xff09;&#xff0c;有固定含义&#xff1b;标识符是自定义的名称&#xff08;如变量名、函数名&#xf…

【MySQL篇】MySQL内置函数

目录 1&#xff0c;日期函数 2&#xff0c;字符串函数 3&#xff0c;数学函数 4&#xff0c;其他函数 实战OJ 1&#xff0c;日期函数 日期类型在之前文章【数据类型】中有描述 传送门&#xff1a;【MySQL篇】数据类型_mysql 数据类型-CSDN博客 函数名称描述current_dat…

RocketMQ开发实战篇

一、生产者开发指南 1. Java API使用详解 在使用RocketMQ进行消息生产时&#xff0c;首先需要引入相关的依赖。在Maven项目中&#xff0c;可以在pom.xml文件中添加以下依赖&#xff1a; <dependency><groupId>org.apache.rocketmq</groupId><artifactI…

记录一下返修

1.对复杂度的分析还不够&#xff1b; 2.融合两种指标的解释还不够&#xff0c;审稿人认为这两种指标存在冲突&#xff0c;不能同时优化&#xff0c;但其实我们考虑的是公平性保证整个调度周期内用户分配到了更加平均的sum-rate,而se是为了追求每个调度时刻都尽可能找到信道条件…

条款1:理解模版性别推导

目录 问题引出 情况1&#xff1a;ParamType是个指针或引用&#xff0c;但不是个万能引用。 情况2&#xff1a;ParamType是个万能引用 情况3&#xff1a;ParamType既非指针也非引用 问题引出 函数模板大致形如&#xff1a; template<typename T> void f(ParamType p…

EngineerCMS完整版支持OnlyOffice8.2文档协作

这次从OO5.3那个时代的接口&#xff0c;改到支持8.2接口&#xff0c;颇费周折。centos升级和docker升级 - Powered by MinDoc (itdos.net) 1. 首先是升级centos 手动升级centos7内核&#xff08;版本自行选择&#xff0c;亲测内核下载链接有效&#xff09;_centos内核下载-CS…

微信小程序防止弹框下面穿透滚动

‌使用catchtouchmove属性‌&#xff1a;在需要防止穿透滚动的元素上添加catchtouchmove"true"属性。这样&#xff0c;当用户在该元素上进行滚动操作时&#xff0c;不会触发下层的滚动事件&#xff0c;从而防止穿透滚动。 例如&#xff1a; 修改前&#xff0c;在弹框…

JAVA面试_进阶部分_Java JVM:垃圾回收(GC 在什么时候,对什么东西,做了什么事情)

在什么时候&#xff1a; 首先需要知道&#xff0c;GC又分为minor GC 和 Full GC&#xff08;major GC&#xff09;。Java堆内存分为新生代和老年代&#xff0c;新生代 中又分为1个eden区和两个Survior区域。 一般情况下&#xff0c;新创建的对象都会被分配到eden区&#xff…