一、Redis 哈希表 进行 rehash 的触发时机是什么?

这道题目考察你对 rehash 操作原理的掌握。回答完触发时机后, 建议进⼀步扩展介绍 rehash 的执⾏时机,可以更好地展现你对 rehash 的深⼊理解。

回答要点:

1)Redis rehash 触发有两个条件:

  • 哈希表的 load factor ⼤于等于 1,同时,Redis ⽬前没有执⾏ RDB 创建或 AOF 重写操作;
  • 哈希表的 load factor ⼤于 5。

2)扩展回答

Redis rehash 在触发后,实际的执⾏时机有两种:⼀种是在处理请求时,会顺带进⾏数据迁移

;另⼀种是,Redis 后台会启动周期性任务进⾏数据迁移。

二、Redis 的 RDB 和 AOF 机制各自的优缺点是什么?这两种机制是否可以混合使用?

RDB、AOF 的优缺点是基本知识,两者混合使用需要做些扩展介绍,建议分成 Redis 4.0 前的同时使用 RDB、AOF,以及 Redis 4.0 后的混合持久化两种情况进行回答。

回答要点:

1)RDB 优点:采用⼦进程生成 RDB ⽂件,减少对 Redis 主线程的阻塞,保证 Redis 性能;RDB 是内存快照,恢复效率⾼。

2)RDB 不⾜:RDB 是间隔⼀段时间⽣成⼀次,两次 RDB 创建之前,如果Redis 发⽣故障,会发⽣数据丢失。

3)AOF 优点:采用 always 配置项时,可以每个命令做⼀次持久化,可靠性相比 RDB 更⾼。

4)AOF 不足:AOF ⽂件较⼤,会触发 AOF 重写,重写时会竞争内存资源;AOF 恢复是回放命令操作,恢复速度慢于 RDB。

5)RDB 和 AOF 可以混合使用:

Redis 4.0 前,两者同时使用时,会既⽣成 RDB,⼜记录 AOF ⽇志,恢复时,优先使用 AOF 日志。

Redis 4.0 后,提供了混合持久化功能,RDB 以⼀定的频率执⾏,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作,避免了⼀直记录 AOF 的开销(例如 AOF 重写)。

三、Redis 经常被称为单线程的系统,你如何理解 Redis 的单线程模型

这道题目考查对 Redis 线程模型、异步线程、⼦进程的理解和掌握。同时,还可以考查对 Redis 6.0 的了解程度。建议分成 Redis 6.0 前和 6.0 两种情况讨论。此外,建议可以介绍单线程模型的优势和不⾜。

回答要点:

1)Redis6.0 前的请求解析、键值数据读写、结果返回都是由⼀个线程完成,所以称 Redis 为单线程模型。

2)Redis 单线程容易阻塞,为了避免阻塞,Redis 设计了⼦进程和异步线程的⽅式来完成某些耗时操作,例如使用⼦进程实现 RDB ⽣成,AOF 重写;使用异步线程实现数据删除等。

3)Redis 6.0 开始,使用多个线程来完成请求解析和结果返回,提升对⽹络请求的处理,提升系统整体的吞吐量。

4)Redis 6.0 对于键值数据的读写仍然使用单线程来处理。

5)单线程的优势是开发简单、可以保证命令执⾏的原⼦性;不⾜是容易被阻塞。

四、Redis 的事务操作有哪些命令?Redis 事务能保证原子性吗?

这道题目考查 Redis 事务操作的基础命令,同时也考查对 Redis 事务操作特性的理解,建议对事务执⾏的不同情况做分析。

回答要点:

1)事务操作基本命令包括 MULTI、EXEC、DISCARD 和 WATCH。MULTI 表示事务开始;EXEC用来实际执⾏事务中命令;DISCARD 表示放弃事务执⾏;WATCH 本质是⼀个乐观锁,用于监控⼀个或多个键,如果被监控的键中有⼀个被修改或删除了,那么事务就放弃执⾏。

2)Redis 事务的原⼦性保证建议分三种情况解释:

  • 命令都正常执⾏,此时原⼦性可以保证;
  • 命令⼊队时出错,EXEC 时会拒绝执⾏所有命令,原⼦性可以保证;
  • 命令实际执⾏时出错,Redis 会执⾏剩余命令,原⼦性得不到保证。

所以,Redis 事务不保证原⼦性。

五、Redis 的惰性删除策略是否会导致大量的过期 key 占用过多的内存?

这道题目考查对 Redis 惰性删除

和定期删除的理解。⾸先回答惰性删除是什么,并建议扩展介绍其优势和不⾜;然后介绍定期删除对惰性删除的补偿机制。

回答要点:

1)惰性删除是指⼀个 key 过期后,并不会直接删除,⽽是等到该 key 被再次访问时,才执⾏删除。

2)惰性删除的设计是为了减少 key 过期删除对 CPU 资源的占用,这是它的优势。但是,带来的不足就是,如果有⼤量 key 过期了,但也没有再被访问,会导致这些 key 留在内存中,占用内存资源。

3)为了减少惰性删除对内存资源的占用,Redis 还有定期删除策略,即每隔⼀段时间,扫描⼀定数量设置了过期时间的 key,将其中已过期数据删除,避免这些 key ⻓期不被删除,占用内存,可以看做是对惰性删除的⼀种补偿机制。

六、 使用 Redis 主从集群时,从库的数据能和主库保持强⼀致吗?

这道题主要考查强⼀致性的概念,以及对 Redis 主从复制机制的理解。此外,建议扩展介绍下数据⼀致性维护的开销,即 Redis 对数据⼀致性保证的设计考虑。

回答要点:

1)强⼀致性是指主从库的数据时刻保持⼀致。

2)Redis 是CAP模型中的AP模型,保证的是可用性(A),而不是强一致性(C),故主从库的数据不是强⼀致性保证,Redis 主库接收到写请求后,并不会等到写请求在从库上同步完成后再返回给客户端。因此,从库上的数据可能和主库不⼀致。

3)扩展回答: 主从库间维护数据强⼀致性,需要主库等待从库完成写请求,该同步等待过程会受到主从库间⽹络情况、从库⾃身负载情况的影响,如果⽹络有阻塞、或是从库负载压⼒较⼤时,会导致主库同步等待时间增加,导致请求延迟增加,系统整体吞吐率会收到影响。Redis 为了提供⾼性能,没有实现强⼀致性保证。

七、如果在组建 Redis 切⽚集群时,直接使用 Hash 函数计算 key 的哈希值,然后再将哈希值对集群实例个数取模,从而决定数据的放置位置,这样做好吗?

回答要点:

1)将 key 的哈希值直接对实例个数取模,再根据取模值决定放置的实例,这个⽅法容易实现。但是,潜在的问题是:如果实例个数发⽣变化,会导致数据⼤量迁移,例如新增⼀个实例,那么数据的放置位置基本都会发⽣变化,需要进⾏迁移。

2)Redis Cluster 使用的基于哈希槽的放置⽅法,增加了⼀层哈希槽的映射。哈希槽

的个数固定,数据和哈希槽的对应关系就固定。即使有实例的增减,也只用迁移⼩部分哈希槽就⾏,避免⼤量数据迁移。在可扩展集群中更加适用。

3)扩展回答:⼀致性哈希的设计⽬的也是避免集群节点变化时,数据⼤量迁移。

八、Redis 数据库中有 50 万个具有相同 key 前缀的键值数据,现在希望把这些数据读取出来,你会使用什么⽅法?

这道题目需要你理解 keys、SCAN 等扫描操作的开销。

回答要点:

1)可以使用 keys 对具有相同 key 前缀的键值数据进⾏扫描读取,但是该命令复杂度⾼,会阻塞 Redis。

2)建议根据具体使用的数据类型,采用 SCAN 命令,分批获取数据,避免对 Redis 的阻塞。

3)SCAN 命令返回结果可能有重复,注意在客户端去重。

九、请列举⼀些 Redis 常⻅的应用场景。

这道题目考查 Redis 不同数据类型的常⻅应用,建议在答题时,同时介绍 Redis 的哪些特性适合所述的应用场景。

回答要点:

1)用于缓存:Redis 最常⻅的应用场景,受益于 Redis 的⾼性能访问特性,以及⾃带的多种数据淘汰策略;

2)用于排⾏榜:受益于 Redis 的有序集合类型;

3)用于计数器:受益于 Redis 的 INCR/DECR 操作;

4)用于队列:受益于 Redis 的 List 类型;

注意:List的大小一般控制在5000个以内。

5)用于分布式锁:受益于 Redis 的⾼性能和原⼦性操作;

注意:Redis是AP模型,并不能完全保证强一致性,所以进入锁后,要再做业务上的一道校验,比如基于数据库的乐观锁

6)用于统计计数:受益于 Redis 的 Set 集合、Bitmap、HyperLogLog 数据类型;

十、Redis 作为缓存使用时,发⽣缓存雪崩和缓存击穿有什么区别吗?

这道题考查你对缓存雪崩和击穿的理解及两者的区别。建议回答完两者区别后,补充介绍应对雪崩和击穿的⽅法。

回答要点:

1)缓存雪崩是指⼤量数据同时失效,导致请求压⼒打到数据库层;

2)缓存击穿是指某个或某些热点数据失效,导致请求压⼒打到数据库层;

3)雪崩和击穿的表现都是数据库层压⼒增加,但是两者的原因不同;

4)雪崩的解决⽅法:避免给⼤量数据设置相同的过期时间,可以在过期时间上增加随机数,将过期时间打散错开(不要在某各时间点大量key过期);

5)击穿的解决⽅法:不给热点数据设置过期时间,让其⻓期留存在缓存中;

十一、Redis 数据淘汰策略使用的 LRU 是标准的 LRU 算法吗?

这个考查你对 LRU 算法的掌握,以及 Redis 实际实现的 LRU。建议对 Redis 实现的 LRU 的设计出发点做些介绍,即 Redis 为什么这么实现LRU。

回答要点:

1)标准的 LRU 是要对所有数据维护 LRU 链,有数据进⼊缓存、被再次访问时,都需要对 LRU 链表进⾏操作。

2)Redis 实现的 LRU 不是标准的 LRU 算法,即不是对所有数据维护 LRU 链,⽽是随机选出 N 个数据作为数据淘汰的候选集,并在候选集中根据数据的LRU字段淘汰最早访问的数据。

3)Redis 更新候选集中数据时,也是选取被候选集中 LRU值更⼩的数据进⼊候选集,以保证更早访问的数据能被淘汰。

4)扩展回答:Redis 实现的 LRU 可以看做是标准 LRU 的变种,主要为了避免标准 LRU 实现中的慢速链表操作,避免影响 Redis 性能。