北京雀斑医院地图 http://m.39.net/news/a_9134159.html打卡Day20,祝大家每天进步亿点点!本篇总结Redis相关面试题~
1、Redis是单线程还是多线程的?
redis4.0之前,redis是完全单线程的。
redis4.0时,redis引入了多线程,但是额外的线程只是用于后台处理,例如:删除对象,核心流程还是完全单线程的。(核心流程指的是redis正常处理客户端请求的流程,通常包括:接收命令、解析命令、执行命令、返回结果等。)
redis6.0中,多线程主要用于网络I/O阶段,也就是接收命令和写回结果阶段,而在执行命令阶段,还是由单线程串行执行。
为什么Redis是单线程?
在redis6.0之前,redis的核心操作是单线程的。因为redis是完全基于内存操作的,通常情况下CPU不会是redis的瓶颈,redis的瓶颈最有可能是机器内存的大小或者网络带宽。
既然CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了,因为如果使用多线程的话会更复杂,同时需要引入上下文切换、加锁等等,会带来额外的性能消耗。
Redis为什么使用单进程、单线程也很快?
主要有以下几点:
1、Redis基于内存的操作
2、Redis使用了I/O多路复用模型,select、epoll等,基于reactor模式开发了自己的网络事件处理器
3、单线程可以避免不必要的上下文切换和竞争条件,减少了这方面的性能消耗。
2、Redis在项目中的使用场景
缓存(核心)、分布式锁(set+lua脚本)、排行榜(zset)、计数(incrby)、消息队列(stream)、地理位置(geo)、访客统计(hyperloglog)等。
3、Redis常见的数据结构
基础的5种:
String:字符串,最基础的数据类型。
List:列表。
Hash:哈希对象。
Set:集合。
SortedSet:有序集合,Set的基础上加了个分值。
高级的4种:
HyperLogLog:通常用于基数统计(例如,网站访客统计)。
Bitmap:位图。
Stream:主要用于消息队列,类似于kafka,可以认为是pub/sub的改进版。提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
Geo:redis3.2版本的新特性。可以将用户给定的地理位置信息储存起来,并对这些信息进行操作:获取2个位置的距离、根据给定地理位置坐标获取指定范围内的地理位置集合。
4、Redis删除过期键的策略(缓存失效策略、数据过期策略)
定时删除:在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。对内存最友好,对CPU时间最不友好。
惰性删除:放任键过期不管,但是每次获取键时,都检査键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。对CPU时间最优化,对内存最不友好。
定期删除:每隔一段时间,默认ms,程序就对数据库进行一次检査,删除里面的过期键。至于要删除多少过期键,以及要检査多少个数据库,则由算法决定。前两种策略的折中,对CPU时间和内存的友好程度较平衡。
Redis使用惰性删除和定期删除。
5、Redis的内存淘汰(驱逐)策略
当redis的内存空间(maxmemory参数配置)已经用满时,redis将根据配置的驱逐策略(maxmemory-policy参数配置),进行相应的淘汰动作。
noeviction:默认策略,不淘汰任何key,直接返回错误。
allkeys-lru:在所有的key中,使用LRU算法淘汰部分key。
allkeys-lfu:在所有的key中,使用LFU算法淘汰部分key,该算法于Redis4.0新增。
allkeys-random:在所有的key中,随机淘汰部分key。
volatile-lru:在设置了过期时间的key中,使用LRU算法淘汰部分key。
volatile-lfu:在设置了过期时间的key中,使用LFU算法淘汰部分key,该算法于Redis4.0新增。
volatile-random:在设置了过期时间的key中,随机淘汰部分key。
volatile-ttl:在设置了过期时间的key中,挑选TTL(timetolive,剩余时间)短的key淘汰。
6、淘汰算法
FIFO:FirstInFirstOut,先进先出。新访问的数据插入FIFO队列尾部,数据在FIFO队列中顺序移动,淘汰FIFO队列头部的数据。
LRU:LeastRecentlyUsed,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。
新数据插入到链表头部,每当缓存数据被访问,则将数据移到链表头部,当链表满的时候,将链表尾部的数据丢弃。
LFU:LeastFrequentlyUsed,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
把数据加入到链表中,按频次排序,一个数据被访问过,把它的频次+1,发生淘汰的时候,把频次低的淘汰掉。
7、Redis的持久化机制有哪几种,各自的实现原理和优缺点?
Redis的持久化机制有:RDB、AOF、混合持久化(RDB+AOF,Redis4.0引入)。
①RDB
描述:类似于快照。在指定的时间间隔内将内存中的数据集快照写入磁盘,可以指定时间归档数据,但不能做到实时持久化,RDB持久化功能生成的RDB文件是经过压缩的二进制文件。
命令:有两个Redis命令可以用于生成RDB文件,一个是SAVE,另一个是BGSAVE。
开启:使用savepoint配置,满足savepoint条件后会触发BGSAVE来存储一次快照,这边的savepoint检查就是在上文提到的serverCron中进行。
savepoint格式:savesecondschanges,含义是Redis如果在seconds秒内数据发生了changes次改变,就保存快照文件。例如Redis默认就配置了以下3个:
save#秒内有1个key发生了变化,则触发保存RDB文件save#秒内有10个key发生了变化,则触发保存RDB文件save6000#60秒内有00个key发生了变化,则触发保存RDB文件
关闭:1)注释掉所有savepoint配置可以关闭RDB持久化。2)在所有savepoint配置后增加:save"",该配置可以删除所有之前配置的savepoint。
save""
SAVE:生成RDB快照文件,但是会阻塞主进程,服务器将无法处理客户端发来的命令请求,所以通常不会直接使用该命令。
BGSAVE:fork子进程来生成RDB快照文件,阻塞只会发生在fork子进程的时候,之后主进程可以正常处理请求。
RDB的优点:
RDB文件是是经过压缩的二进制文件,占用空间很小,它保存了Redis某个时间点的数据集,很适合用于做备份。
RDB在恢复大数据集时的速度比AOF的恢复速度要快。
RDB可以最大化redis的性能。父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘I/O操作。
RDB的缺点:
RDB在服务器故障时容易造成数据的丢失。RDB允许我们通过修改savepoint配置来控制持久化的频率。但是,因为RDB文件需要保存整个数据集的状态,所以它是一个比较重的操作,如果频率太频繁,可能会对Redis性能产生影响。所以通常可能设置至少5分钟才保存一次快照,这时如果Redis出现宕机等情况,则意味着最多可能丢失5分钟数据。
RDB保存时使用fork子进程进行数据的持久化,如果数据比较大的话,fork可能会非常耗时,造成Redis停止处理服务N毫秒。如果数据集很大且CPU比较繁忙的时候,停止服务的时间甚至会到一秒。
②AOF
描述:以日志的形式记录服务器所处理的每一个写、删除操作(查询操作不会记录),以文本的方式记录,并在服务器启动时,通过重新执行这些命令来还原数据集。
开启:AOF持久化默认是关闭的,可以通过配置:appendonlyyes开启。
关闭:使用配置appendonlyno可以关闭AOF持久化。
AOF的优点:
AOF比RDB可靠,支持秒级持久化,就算发生故障停机,也最多只会丢失一秒钟的数据。
当AOF文件太大时,Redis会自动在后台进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。当新文件重写完毕,Redis会把新旧文件进行切换,然后开始把数据写到新文件上。
AOF的缺点:
对于相同的数据集,AOF文件的大小一般会比RDB文件大。
RDB存储的是压缩二进制格式记录数据命令,AOF是通过文本日志形式记录数据命令,所以采用AOF数据恢复比RDB慢。
③混合持久化
描述:混合持久化并不是一种全新的持久化方式,而是对已有方式的优化。混合持久化只发生于AOF重写过程。使用了混合持久化,重写后的新AOF文件前半段是RDB格式的全量数据,后半段是AOF格式的增量数据。
优点:结合RDB和AOF的优点,更快的重写和恢复。
8、为什么需要AOF重写文件?
AOF持久化是通过保存被执行的写命令来记录数据库状态的,随着写入命令的不断增加,AOF文件中的内容会越来越多,文件的体积也会越来越大。
如果不加以控制,体积过大的AOF文件可能会对Redis服务器、甚至整个宿主机造成影响,并且AOF文件的体积越大,使用AOF文件来进行数据还原所需的时间就越多。
举个例子,如果你对一个计数器调用了次INCR,那么仅仅是为了保存这个计数器的当前值,AOF文件就需要使用条记录。然而在实际上,只使用一条SET命令已经足以保存计数器的当前值了,其余99条记录实际上都是多余的。
为了处理这种情况,Redis引入了AOF重写:可以在不打断服务端处理请求的情况下,对AOF文件进行重建(rebuild)。
9、介绍下AOF重写的过程、AOF后台重写存在的问题、如何解决AOF后台重写存在的数据不一致问题
AOF后台重写存在的问题:
AOF后台重写使用子进程进行从写,解决了主进程阻塞的问题,但是仍然存在另一个问题:子进程在进行AOF重写期间,服务器主进程还需要继续处理命令请求,新的命令可能会对现有的数据库状态进行修改,从而使得当前的数据库状态和重写后的AOF文件保存的数据库状态不一致。
如何解决AOF后台重写存在的数据不一致问题:
为了解决上述问题,Redis引入了AOF重写缓冲区(aof_rewrite_buf_blocks),这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令追加到AOF缓冲区和AOF重写缓冲区。
这样一来可以保证:
1、现有AOF文件的处理工作会如常进行。这样即使在重写的中途发生停机,现有的AOF文件也还是安全的。
2、从创建子进程开始,也就是AOF重写开始,服务器执行的所有写命令会被记录到AOF重写缓冲区里面。
这样,当子进程完成AOF重写工作后,父进程会在serverCron中检测到子进程已经重写结束,则会执行以下工作:
1、将AOF重写缓冲区中的所有内容写入到新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致。
2、对新的AOF文件进行改名,原子的覆盖现有的AOF文件,完成新旧两个AOF文件的替换。
之后,父进程就可以继续像往常一样接受命令请求了。
10、同时开启RDB和AOF,服务重启时如何加载
简单来说,如果同时启用了AOF和RDB,Redis重新启动时,会先使用AOF文件来重建数据集,因为通常来说,AOF的数据会更完整。
而在引入了混合持久化之后,使用AOF重建数据集时,会通过文件开头是否为“REDIS”来判断是否为混合持久化。
完整流程如下图所示:
文章参考:全网最硬核Redis高频面试题解析(年最新版)
总结的面试题也挺费时间的,文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,还请三连支持一下,后续会亿点点的更新!
预览时标签不可点收录于话题#个上一篇下一篇