面试被吊打系列 - Redis原理

小张兴冲冲去面试,结果被面试官吊打!面试

小张:redis

面试官,你好。我是来参加面试的。算法

面试官:服务器

你好,小张。我看了你的简历,熟练掌握Redis,那么我就随便问你几个Redis相关的问题吧。首先个人问题是,Redis是单线程仍是多线程呢?网络

小张:数据结构

Redis不一样版本之间采用的线程模型是不同的,在Redis4.0版本以前使用的是单线程模型,在4.0版本以后增长了多线程的支持。多线程

在4.0以前虽然咱们说Redis是单线程,也只是说它的网络I/O线程以及Set 和 Get操做是由一个线程完成的。可是Redis的持久化、集群同步仍是使用其余线程来完成。并发

4.0以后添加了多线程的支持,主要是体如今大数据的异步删除功能上,例如 unlink keyflushdb asyncflushall async异步

面试官:async

回答的很好,那为何Redis在4.0以前会选择使用单线程?并且使用单线程还那么快?

小张:

选择单线程我的以为主要是使用简单,不存在锁竞争,能够在无锁的状况下完成全部操做,不存在死锁和线程切换带来的性能和时间上的开销,但同时单线程也不能彻底发挥出多核CPU的性能。

至于为何单线程那么快我以为主要有如下几个缘由:

  1. Redis 的大部分操做都在内存中完成,内存中的执行效率自己就很快,而且采用了高效的数据结构,好比哈希表和跳表。
  2. 使用单线程避免了多线程的竞争,省去了多线程切换带来的时间和性能开销,而且不会出现死锁。
  3. 采用 I/O 多路复用机制处理大量客户端的Socket请求,由于这是基于非阻塞的 I/O 模型,这就让Redis能够高效地进行网络通讯,I/O的读写流程也再也不阻塞。

面试官:

不错,那Redis是如何实现数据不丢失的呢?

小张:

Redis数据是存储在内存中的,为了保证Redis数据不丢失,那就要把数据从内存存储到磁盘上,以便在服务器重启后还可以从磁盘中恢复原有数据,这就是Redis的数据持久化。Redis数据持久化有三种方式。

  • AOF 日志(Append Only File,文件追加方式):记录全部的操做命令,并以文本的形式追加到文件中。
  • RDB 快照(Redis DataBase):将某一个时刻的内存数据,以二进制的方式写入磁盘。
  • 混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDB 和 AOF 的优势。

面试官:

那你分别说说 AOF和 RDB的实现原理吧。

小张:

AOF采用的是写后日志的方式,Redis先执行命令把数据写入内存,而后再记录日志到文件中。AOF日志记录的是操做命令,不是实际的数据,若是采用AOF方法作故障恢复时须要将全量日志都执行一遍。image.png

RDB采用的是内存快照的方式,它记录的是某一时刻的数据,而不是操做,因此采用RDB方法作故障恢复时只须要直接把RDB文件读入内存便可,实现快速恢复。

面试官:

你刚提到了AOF采用的是 “写后日志” 的方式,咱们平时用的MySQL则采用的是 “写前日志”,那 Redis为何要先执行命令,再把数据写入日志呢?

小张:额头开始冒汗,问的是些啥问题呀。。。

额,这个主要是因为Redis在写入日志以前,不对命令进行语法检查,因此只记录执行成功的命令,避免出现记录错误命令的状况,并且在命令执行后再写日志不会阻塞当前的写操做。

面试官:

后写日志又有什么风险呢?

小张:

我... 这个我不会。

面试官:

好吧,后写日志主要有两个风险可能会发生:

  • 数据可能会丢失: 若是 Redis 刚执行完命令,此时发生故障宕机,会致使这条命令存在丢失的风险。
  • 可能阻塞其余操做: AOF 日志其实也是在主线程中执行,因此当 Redis 把日志文件写入磁盘的时候,仍是会阻塞后续的操做没法执行。

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

小张:

Redis 提供了两个命令来生成 RDB 快照文件,分别是 savebgsavesave 命令在主线程中执行,会致使阻塞。而 bgsave 命令则会建立一个子进程,用于写入 RDB 文件的操做,避免了对主线程的阻塞,这也是 Redis RDB 的默认配置。

面试官:

RDB 作快照的时候数据能修改吗?

小张:

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

面试官:

那Redis是怎么解决在bgsave作快照的时候容许数据修改呢?

小张:(你咋还问。。。我™不会啊!)

额,这个我不太清楚...

image.png

面试官:

这里主要是利用 bgsave的子线程实现的,具体操做以下:

  • 若是主线程执行读操做,则主线程和bgsave 子进程互相不影响;
  • 若是主线程执行写操做,则被修改的数据会复制一份副本,而后bgsave子进程会把该副本数据写入 RDB 文件,在这个过程当中,主线程仍然能够直接修改原来的数据。

image.png

要注意,Redis 对 RDB 的执行频率很是重要,由于这会影响快照数据的完整性以及 Redis 的稳定性,因此在 Redis 4.0 后,增长了 AOF 和 RDB 混合的数据持久化机制: 把数据以 RDB 的方式写入文件,再将后续的操做命令以 AOF 的格式存入文件,既保证了 Redis 重启速度,又下降数据丢失风险。

小张:

学到了学到了。

面试官:

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

小张:

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

主从复制

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

image.png

哨兵模式

使用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器出现故障宕机时,须要手动进行恢复,为了解决这个问题,Redis 增长了哨兵模式(由于哨兵模式作到了能够监控主从服务器,而且提供自动容灾恢复的功能)。

image.png

Redis Cluster(集群)

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

image.png

面试官:

使用哨兵模式在数据上有副本数据作保证,在可用性上又有哨兵监控,一旦master宕机会选举salve节点为master节点,这种已经知足了咱们的生产环境须要,那为何还须要使用集群模式呢?

小张:

额,哨兵模式归根节点仍是主从模式,在主从模式下咱们能够经过增长salve节点来扩展读并发能力,可是没办法扩展写能力和存储能力,存储能力只能是master节点可以承载的上限。因此为了扩展写能力和存储能力,咱们就须要引入集群模式。

面试官:

集群中那么多Master节点,redis cluster在存储的时候如何肯定选择哪一个节点呢?

小张:

这应该是使用了某种hash算法,可是我不太清楚。。。

image.png

面试官:

那好,今天的面试就到这里吧,你先回去等咱们的面试通知。

小张:

好的,谢谢面试官,你能告诉我redis cluster怎么实现节点选择的吗?

面试官:

Redis Cluster采用的是类一致性哈希算法实现节点选择的,至于什么是一致性哈希算法你本身回去看看。

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

  • 根据键值对的 key,按照 CRC16 算法计算一个 16 bit 的值。
  • 再用 16bit 值对 16384 取模,获得0~16383 范围内的模数,每一个模数表明一个相应编号的哈希槽。

每一个Redis节点负责处理一部分槽位,加入你有三个master节点 ABC,每一个节点负责的槽位以下:

节点 处理槽位
A 0-5000
B 5001 - 10000
C 10001 - 16383

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

好了,各位看官朋友们,Redis原理的这些面试点大家记住了吗?但愿大家的面试不会被这个问题难倒哟~

相关文章
相关标签/搜索