Redis面试题汇总一

社会主义新天地 提交于 2019-12-14 04:33:27

1、什么是Redis

redis本质是一个key-value类型的内存数据库,整个数据库统统加载在内存中进行操作,定期通过异步操作把数据库数据flush到硬盘上保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。除此之外,redis还支持多种数据结构(如list,string,set,zset,hash)。

2、Redis为什么这么快?

①、redis完全基于内存
②、使用单线程,避免了不必要的上下文切换和竞争条件
③、使用了I/O多路复用模型
关于redis I/O多路复用解释如下图:
在这里插入图片描述
这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。

3、为什么Redis是单线程的?

对于Redis的单线程解释:单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。

官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)看完官方文档我们大致可以总结出使用单线程的原因:使用单线程已经足够快了,没必要在使用多线程。

4、Redis持久化机制

Redis是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到硬盘文件来保证数据持久化。当Redis重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目的。

快照(snapshotting)持久化(RDB)

Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用,对应产生的数据文件为 dump.rdb。

快照持久化是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置:

save 900 1              #在900(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 300 10            #在300(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000        #在60(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
AOF(append-only file)持久化

与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:

appendonly yes

开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。
在Redis的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:

appendfsync always     #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no      #让操作系统决定何时进行同步

为了兼顾数据和写入性能,用户可以考虑 appendfsync everysec 选项 ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。

当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。

AOF重写:

AOF重写可以产生一个新的AOF文件,这个新的AOF文件和原有的AOF文件所保存的数据库状态一样,但体积更小。

AOF重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有AOF文件进行任伺读入、分析或者写入操作。

在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态一致。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件重写操作

Redis如何做持久化的?
bgsave做镜像全量持久化,aof做增量持久化。因为bgsave会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。在redis实例重启时,优先使用aof来恢复内存的状态,如果没有aof日志,就会使用rdb文件来恢复。
如果再问aof文件过大恢复时间过长怎么办?你告诉面试官,Redis会定期做aof重写,压缩aof文件日志大小。如果面试官不够满意,再拿出杀手锏答案,Redis4.0之后有了混合持久化的功能,将bgsave的全量和aof的增量做了融合处理,这样既保证了恢复的效率又兼顾了数据的安全性。这个功能甚至很多面试官都不知道,他们肯定会对你刮目相看。
如果对方追问那如果突然机器掉电会怎样?取决于aof日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据。

更多redis持久化阅读:一起看懂Redis两种持久化方式的原理

5、Redis内存淘汰机制

redis提供了对键过期的设置,实现了几种淘汰机制以便应对各种场景,过期时间如果不加以设置默认为永久。

redis清除过期key的方式

定期删除+惰性删除

  • 定期删除:redis设定是每隔100ms 随机抽取 设置了过期时间的key,并对其进行检查,如果已经过期了,则删除key。为什么是随机抽取?因为如果数据比较多,遍历会影响性能。
  • 惰性删除:每次获取key时会对key进行判断是否还存活,如果已经过期了则删除。

注意:Redis中过期的key并不会马上删除,因为定期删除可能正好没抽取到它,我们也没有访问它触发惰性删除

为什么不使用定时删除策略?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略

redis内存淘汰机制

如果定期删除漏掉了很多过期的key,而且我们也没有再去访问它们,如果没有加以处理,可能会导致内存耗尽。

可以在Redis配置文件中可以设置maxmemory,内存的最大使用量,到达限度时会执行 内存淘汰机制

redis内存淘汰机制有如下几种,默认是no-eviction

  • volatile-lru: 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  • allkeys-lru: 当内存不足写入新数据时淘汰最近最少使用的Key
  • volatile-random: 从已设置过期时间的数据集中挑选任意数据淘汰
  • allkeys-random: 从数据集中任意选择数据淘汰,当内存达到限制的时候,对所有数据集挑选随机淘汰,可写入新的数据集
  • volatile-ttl: 从已设置过期时间的数据集中挑选将要过期的数据淘汰
  • noeviction: 当内存不足写入新数据时,写入操作会报错,同时不删除数据

说明:

volatile为前缀的策略都是从已过期的数据集中进行淘汰。
allkeys为前缀的策略都是面向所有key进行淘汰。
lru(least recently used)最近最少用到的。
它们的触发条件都是Redis使用的内存达到阈值时。

设置内存淘汰机制语法:config set maxmemory-policy noeviction

6、Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?

使用keys指令可以扫出指定模式的key列表。
对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
这个时候你要回答redis关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
关于keys与scan命令参考:redis 用scan 代替keys

7、如果有大量的key需要设置同一时间过期,一般需要注意什么?

如果大量的key过期时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。

8、缓存雪崩

①、什么是缓存雪崩?

缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

②、缓存雪崩解决办法
  • 事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。
  • 事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉,尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)
  • 事后:利用 redis 持久化机制保存的数据尽快恢复缓存
    在这里插入图片描述

9、缓存穿透

①、什么是缓存穿透?

缓存穿透是指查询一个一定不存在的数据。由于缓存不命中,并且出于容错考虑,如果从数据库查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,失去了缓存的意义。 简而言之,缓存穿透就是:请求的数据在缓存大量不命中,导致请求走数据库。

②、缓存穿透解决办法
  • 最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力
  • 另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!