小张兴冲冲去面试,结果被面试官吊打!面试
小张: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
等异步
面试官:async
回答的很好,那为何Redis在4.0以前会选择使用单线程?并且使用单线程还那么快?
小张:
选择单线程我的以为主要是使用简单,不存在锁竞争,能够在无锁的状况下完成全部操做,不存在死锁和线程切换带来的性能和时间上的开销,但同时单线程也不能彻底发挥出多核CPU的性能。
至于为何单线程那么快我以为主要有如下几个缘由:
面试官:
不错,那Redis是如何实现数据不丢失的呢?
小张:
Redis数据是存储在内存中的,为了保证Redis数据不丢失,那就要把数据从内存存储到磁盘上,以便在服务器重启后还可以从磁盘中恢复原有数据,这就是Redis的数据持久化。Redis数据持久化有三种方式。
面试官:
那你分别说说 AOF和 RDB的实现原理吧。
小张:
AOF采用的是写后日志的方式,Redis先执行命令把数据写入内存,而后再记录日志到文件中。AOF日志记录的是操做命令,不是实际的数据,若是采用AOF方法作故障恢复时须要将全量日志都执行一遍。
RDB采用的是内存快照的方式,它记录的是某一时刻的数据,而不是操做,因此采用RDB方法作故障恢复时只须要直接把RDB文件读入内存便可,实现快速恢复。
面试官:
你刚提到了AOF采用的是 “写后日志” 的方式,咱们平时用的MySQL则采用的是 “写前日志”,那 Redis为何要先执行命令,再把数据写入日志呢?
小张:额头开始冒汗,问的是些啥问题呀。。。
额,这个主要是因为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 集群。
主从复制
将从前的一台 Redis 服务器,同步数据到多台从 Redis 服务器上,即一主多从的模式,这个跟MySQL主从复制的原理同样。
哨兵模式
使用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器出现故障宕机时,须要手动进行恢复,为了解决这个问题,Redis 增长了哨兵模式(由于哨兵模式作到了能够监控主从服务器,而且提供自动容灾恢复的功能)。
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,被映射到一个哈希槽中,具体执行过程分为两大步。
0~16383
范围内的模数,每一个模数表明一个相应编号的哈希槽。每一个Redis节点负责处理一部分槽位,加入你有三个master节点 ABC,每一个节点负责的槽位以下:
节点 | 处理槽位 |
---|---|
A | 0-5000 |
B | 5001 - 10000 |
C | 10001 - 16383 |
这样就实现了cluster节点的选择。
好了,各位看官朋友们,Redis原理的这些面试点大家记住了吗?但愿大家的面试不会被这个问题难倒哟~