乐趣区

关于java:Redis夺命十二问差点没抗住

Redis 是面试中绕不过的槛,只有在简历中写了用过 Redis,必定逃不过。明天咱们就来模仿一下面试官在 Redis 这个话题上是如何一步一步深刻,全面考查候选人对于 Redis 的掌握情况。

小二:面试官,你好。我是来加入面试的。

面试官:你好,小二。我看了你的简历,熟练掌握 Redis,那么我就轻易问你几个 Redis 相干的问题吧。首先我的问题是,Redis 是单线程还是多线程呢

小二:Redis 不同版本之间采纳的线程模型是不一样的,在 Redis4.0 版本之前应用的是单线程模型,在 4.0 版本之后减少了多线程的反对。

在 4.0 之前尽管咱们说 Redis 是单线程,也只是说它的网络 I/O 线程以及 Set 和 Get 操作是由一个线程实现的。然而 Redis 的长久化、集群同步还是应用其余线程来实现。

4.0 之后增加了多线程的反对,次要是体现在大数据的异步删除性能上,例如 unlink key、flushdb async、flushall async 等

面试官:答复的很好,那为什么 Redis 在 4.0 之前会抉择应用单线程?而且应用单线程还那么快

小二:抉择单线程集体感觉次要是应用简略,不存在锁竞争,能够在无锁的状况下实现所有操作,不存在死锁和线程切换带来的性能和工夫上的开销,但同时单线程也不能齐全施展出多核 CPU 的性能。

至于为什么单线程那么快我感觉次要有以下几个起因:

  • Redis 的大部分操作都在内存中实现,内存中的执行效率自身就很快,并且采纳了高效的数据结构,比方哈希表和跳表。
  • 应用单线程防止了多线程的竞争,省去了多线程切换带来的工夫和性能开销,并且不会呈现死锁。
  • 采纳 I/O 多路复用机制解决大量客户端的 Socket 申请,因为这是基于非阻塞的 I/O 模型,这就让 Redis 能够高效地进行网络通信,I/O 的读写流程也不再阻塞。

面试官:不错,那 Redis 是如何实现数据不失落的呢

小二:Redis 数据是存储在内存中的,为了保障 Redis 数据不失落,那就要把数据从内存存储到磁盘上,以便在服务器重启后还可能从磁盘中复原原有数据,这就是 Redis 的数据长久化。Redis 数据长久化有三种形式。

1)AOF 日志(Append Only File,文件追加形式):记录所有的操作命令,并以文本的模式追加到文件中。

2)RDB 快照(Redis DataBase):将某一个时刻的内存数据,以二进制的形式写入磁盘。

3)混合长久化形式:Redis 4.0 新增了混合长久化的形式,集成了 RDB 和 AOF 的长处。

面试官:那你别离说说 AOF 和 RDB 的实现原理 吧。

小二:AOF 采纳的是写后日志的形式,Redis 先执行命令把数据写入内存,而后再记录日志到文件中。AOF 日志记录的是操作命令,不是理论的数据,如果采纳 AOF 办法做故障复原时须要将全量日志都执行一遍。

RDB 采纳的是内存快照的形式,它记录的是某一时刻的数据,而不是操作,所以采纳 RDB 办法做故障复原时只须要间接把 RDB 文件读入内存即可,实现疾速复原。

面试官:你刚提到了 AOF 采纳的是“写后日志”的形式,咱们平时用的 MySQL 则采纳的是“写前日志”,那 Redis 为什么要先执行命令,再把数据写入日志呢

小二:这个次要是因为 Redis 在写入日志之前,不对命令进行语法查看,所以只记录执行胜利的命令,避免出现记录谬误命令的状况,而且在命令执行后再写日志不会阻塞以后的写操作。

面试官:那后写日志又有什么危险呢

小二:我 … 这个我不会。

面试官:好吧,后写日志次要有两个危险可能会产生:

  • 数据可能会失落:如果 Redis 刚执行完命令,此时产生故障宕机,会导致这条命令存在失落的危险。
  • 可能阻塞其余操作:AOF 日志其实也是在主线程中执行,所以当 Redis 把日志文件写入磁盘的时候,还是会阻塞后续的操作无奈执行。

我还有个问题是 RDB 做快照时会阻塞线程吗

小二:Redis 提供了两个命令来生成 RDB 快照文件,别离是 save 和 bgsave。save 命令在主线程中执行,会导致阻塞。而 bgsave 命令则会创立一个子过程,用于写入 RDB 文件的操作,防止了对主线程的阻塞,这也是 Redis RDB 的默认配置。

面试官:RDB 做快照的时候数据能批改吗

小二:save 是同步的会阻塞客户端命令,bgsave 的时候是能够批改的。

面试官:那 Redis 是 怎么解决在 bgsave 做快照的时候容许数据批改呢

小二:额,这个我不太分明 …

面试官:这里次要是利用 bgsave 的子线程实现的,具体操作如下:

  • 如果主线程执行读操作,则主线程和 bgsave 子过程相互不影响;
  • 如果主线程执行写操作,则被批改的数据会复制一份正本,而后 bgsave 子过程会把该正本数据写入 RDB 文件,在这个过程中,主线程依然能够间接批改原来的数据。

要留神,Redis 对 RDB 的执行频率十分重要,因为这会影响快照数据的完整性以及 Redis 的稳定性,所以在 Redis 4.0 后,减少了 AOF 和 RDB 混合的数据长久化机制:把数据以 RDB 的形式写入文件,再将后续的操作命令以 AOF 的格局存入文件,既保证了 Redis 重启速度,又升高数据失落危险。

小二:学到了学到了。

面试官:那你再跟我说说 Redis 如何实现高可用 吧?

小二:Redis 实现高可用次要有三种形式:主从复制、哨兵模式,以及 Redis 集群。

1)主从复制

将从前的一台 Redis 服务器,同步数据到多台从 Redis 服务器上,即一主多从的模式,这个跟 MySQL 主从复制的原理一样。

2)哨兵模式

应用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器呈现故障宕机时,须要手动进行复原,为了解决这个问题,Redis 减少了哨兵模式(因为哨兵模式做到了能够监控主从服务器,并且提供主动容灾复原的性能)。

3)Redis Cluster(集群)

Redis Cluster 是一种分布式去中心化的运行模式,是在 Redis 3.0 版本中推出的 Redis 集群计划,它将数据分布在不同的服务器上,以此来升高系统对单主节点的依赖,从而进步 Redis 服务的读写性能。

面试官:应用哨兵模式在数据上有正本数据做保障,在可用性上又有哨兵监控,一旦 master 宕机会选举 salve 节点为 master 节点,这种曾经满足了咱们的生产环境须要,那为什么还须要应用集群模式呢

小二:哨兵模式归根节点还是主从模式,在主从模式下咱们能够通过减少 salve 节点来扩大读并发能力,然而没方法扩大写能力和存储能力,存储能力只能是 master 节点可能承载的下限。所以为了扩大写能力和存储能力,咱们就须要引入集群模式。

面试官:集群中那么多 Master 节点,Redis Cluster 在存储的时候如何确定抉择哪个节点呢

小二:这应该是应用了某种 hash 算法,然而我不太分明。。。

面试官:那好,明天的面试就到这里吧,你先回去等咱们的面试告诉。

小二:好的,谢谢面试官,你能通知我 Redis Cluster 怎么实现节点抉择的吗?

面试官:Redis Cluster 采纳的是类一致性哈希算法实现节点抉择的,至于什么是一致性哈希算法你本人回去看看。

Redis Cluster 将本人分成了 16384 个 Slot(槽位),哈希槽相似于数据分区,每个键值对都会依据它的 key,被映射到一个哈希槽中,具体执行过程分为两大步。

1)依据键值对的 key,依照 CRC16 算法计算一个 16 bit 的值。

2)再用 16bit 值对 16384 取模,失去 0~16383 范畴内的模数,每个模数代表一个相应编号的哈希槽。

每个 Redis 节点负责解决一部分槽位,如果你有三个 master 节点 ABC,每个节点负责的槽位如下:

节点 解决槽位
A 0-5000
B 5001 – 10000
C 10001 – 16383

这样就实现了 cluster 节点的抉择。

好了,明天对于 Redis 的面试就到这里了,你们感觉如何,都能答对吗?

退出移动版