当前位置: 首页 > 后端技术 > Java

Redis的致命十二问,我差点忍不住!

时间:2023-04-02 00:14:39 Java

Redis是面试中绕不过去的一道坎。只要你简历中用过Redis,就绝对逃不掉。今天我们就模拟一下面试官是如何一步步深入Redis的话题,全面考察应聘者对Redis的掌握程度。小二:面试官你好。我是来面试的采访者:你好,小二。看了你的简历,我精通Redis,所以就问你几个Redis相关的问题。首先我的问题是,Redis是单线程的还是多线程的?小2:不同版本的Redis使用的线程模型是不一样的。Redis4.0之前采用的是单线程模型,4.0版本之后增加了对多线程的支持。在4.0之前,虽然我们说Redis是单线程的,但只是说它的网络I/O线程和Set、Get操作都是一个线程完成的。但是Redis的持久化和集群同步还是使用其他线程来完成的。4.0之后加入了多线程支持,主要体现在大数据的异步删除功能上,比如unlinkkey、flushdbasync、flushallasync等。面试官:这个回答很好,那为什么Redis会选择在4.0之前使用单线程?而且单线程还这么快?小二:选择单线程主要是因为好用,没有锁竞争,所有的操作都可以在没有锁的情况下完成。没有死锁和线程切换带来的性能和时间开销,但同时,单线程不能充分发挥多核CPU的性能。至于为什么单线程那么快,我觉得主要有以下几个原因:Redis的大部分操作都是在内存中完成的,本身在内存中的执行效率就非常快,使用了高效的数据结构,比如hash表和跳过。表面。使用单线程避免了多线程竞争,节省了多线程切换带来的时间和性能开销,不会造成死锁。I/O多路复用机制用于处理大量的客户端Socket请求,因为它是基于非阻塞I/O模型的,这使得Redis可以高效地通过网络进行通信,I/O读写进程不再阻塞。面试官:对,Redis是怎么防止数据丢失的?第二:Redis数据存放在内存中。为了保证Redis的数据不丢失,数据必须从内存存储到磁盘,这样服务器重启后才能从磁盘恢复原来的数据。这就是Redis数据持久化。持久化Redis数据的三种方式。1)AOF日志(AppendOnlyFile,文件追加方式):记录所有的操作命令,并以文本形式追加到文件中。2)RDB快照(RedisDataBase):将某一时刻的内存数据以二进制形式写入磁盘。3)混合持久化方式:Redis4.0增加了混合持久化方式,它综合了RDB和AOF的优点。面试官:那分别说说AOF和RDB的实现原理。第二:AOF采用post-writelog方式。Redis首先执行命令将数据写入内存,然后将日志记录到文件中。AOF日志记录的是操作命令,并不是实际的数据。如果采用AOF方式进行故障恢复,整个日志需要执行一次。RDB采用内存快照的方式,记录的是某一时刻的数据,而不是操作,所以在使用RDB方式进行故障恢复时,只需要直接将RDB文件读入内存即可实现快速恢复。面试官:您刚刚提到AOF采用的是“先写后记录”的方式,而我们平时使用的MySQL采用的是“先记录后记录”的方式,那么为什么Redis会先执行命令,再将数据写入日志呢?小二:这主要是因为Redis在写日志之前不会检查命令的语法,所以只记录成功执行的命令,避免记录错误的命令,命令执行后写日志不会阻塞当前写操作。面试官:那写日志有什么风险呢?小二:我……我不知道怎么办。面试官:嗯,写日志后主要有两个风险:数据可能会丢失:如果Redis刚刚执行完命令,此时出现故障,就会有丢失这条命令的风险。可能会阻塞其他操作:AOF日志实际上是在主线程中执行的,所以当Redis将日志文件写入磁盘时,仍然会阻塞后续操作,无法执行。我的问题是,RDB做快照的时候线程会不会被阻塞?第二:Redis提供了两条命令来生成RDB快照文件,分别是save和bgsave。save命令在主线程中执行,会造成阻塞。bgsave命令会创建一个写入RDB文件的子进程,避免阻塞主线程,这也是RedisRDB的默认配置。面试官:RDB做快照的时候可以修改数据吗?第二:save是同步的,会阻塞客户端命令,但是在bgsave的时候可以修改。面试官:那么Redis是如何在bgsave做快照的时候允许修改数据的呢?小二:嗯,这个我不是很了解。。。面试官:这个主要是用bgsave的子线程实现的。具体操作如下:如果主线程执行了read操作,则主线程和bgsave的子进程不会相互影响;如果主线程执行写操作时,会复制一份修改后的数据,然后bgsave子进程将复制的数据写入到RDB文件中。在这个过程中,主线程仍然可以直接修改原始数据。需要注意的是,Redis对于RDB的执行频率非常重要,因为它会影响快照数据的完整性和Redis的稳定性,所以在Redis4.0之后,增加了AOF和RDB相结合的数据持久化机制:putdata在RDB中写入AOF格式的文件,然后将后续的操作命令以AOF格式保存在文件中,这样既保证了Redis的重启速度,又降低了数据丢失的风险。小二:学到了。我学会了。面试官:那你说说Redis是怎么实现高可用的?小二:Redis实现高可用主要有三种方式:主从复制、哨兵模式、Redis集群。1)主从复制是将数据从之前的一台Redis服务器同步到多台Redis从服务器,即主从模式,与MySQL主从复制原理相同。2)哨兵模式使用Redis主从服务时,会出现一个问题,就是当Redis的主从服务器出现故障时,需要手动恢复。为了解决这个问题,Redis增加了sentinel模式(因为sentinel模式确实可以监控主从服务器,提供自动容灾功能)。3)RedisCluster(集群)RedisCluster是一种分布式、去中心化的运行模式。是Redis3.0版本推出的Redis集群解决方案。它将数据分布在不同的服务器上,减少系统对单主节点的依赖,从而提高Redis服务的读写性能。面试官:使用sentinel模式有copydata作为数据的保障,有sentinel监控可用性。一旦master宕机,slave节点就会被选举为主节点。这已经满足了我们生产环境的需求,那为什么还要用呢?集群模式呢?小二:哨兵模式还是根节点的主从模式。在主从模式下,我们可以通过增加从节点来扩展并发读能力,但是没有办法扩展写能力和存储能力。存储容量只能是主节点可以承载的上限。.所以为了扩展写入和存储能力,我们需要引入集群模式。面试官:集群中有这么多Master节点,RedisCluster在存储时如何确定选择哪个节点?小二:这个应该用什么hash算法,但我不确定。..采访者:好了,今天的采访就到这里。回去等我们的面试通知。小二:好的,谢谢面试官,请问RedisCluster是如何实现节点选择的?面试官:RedisCluster采用了类似的一致性哈希算法来实现节点选择。至于什么是一致性哈希算法,大家可以自己回去看看。RedisCluster将自己划分为16384个Slots(槽)。哈希槽类似于数据分区。每个键值对将根据其键映射到一个哈希槽。具体执行过程分为两步。.1)根据键值对的key,按照CRC16算法计算出一个16位的值。2)然后用16bit的值对16384取模得到0~16383范围内的模数,每个模数代表一个对应编号的哈希槽。每个Redis节点负责处理一部分槽。如果有3个master节点ABC,每个节点负责的槽位如下:节点处理槽位A0-5000B5001-10000C10001-16383这样就实现了集群节点的选择。好了,今天关于Redis的采访就到这里了,你怎么看,你能答对吗?