Redis常见口试题汇总

打印 上一主题 下一主题

主题 507|帖子 507|积分 1521

1.Redis中的底层数据结构


  • String(字符串、整数或浮点数):

  • String 是Redis最基本的数据类型,一个key对应一个value,value的最大值为512M
  • String类型是二进制安全的(原理在2),意味着redis可以包含任何数据,如图片、视频(可以转换为二进制编码)和序列化对象

  • List(列表):redis列表是简单的字符串列表,单键多值,按照插入次序排序,可以选择添加一个元素到列表的表头或者表尾
  • Set(无序集合):redis的set是String类型的无序集合,可以实现元素的自动排重和判定元素是否存在
  • Hash(包含键值对的无序散列表):RedisHash是一个String类型的 field 和 value 的映射表,hash特别得当于存储对象
  • Zset(有序集合):Zset也就是SortedSet,每个元素都必要保存一个score值和一个member值,member必须唯一,可以根据score值进行排序,也可以根据member查询score。
2.Redis为什么那么快?

(1)完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存利用,非常快速,跟传统的磁盘文件数据存储相比,避免了通过磁盘IO读取到内存这部分的开销。
(2)数据结构简单,对数据利用也简单。Redis中的数据结构是专门进行设计的,每种数据结构都有一种或多种数据结构来支持。Redis正是依靠这些机动的数据结构,来提升读取和写入的性能。
(3)采用单线程,省去了很多上下文切换的时间以及CPU消耗,不存在竞争条件,不用去考虑各种锁的题目,不存在加锁释放锁利用,也不会出现死锁而导致的性能消耗。
(4)利用基于IO多路复用机制的线程模子,可以处理并发的链接。
3.表明一下什么是I/O多路复用模子?

I/O多路复用是指利用单个线程来同时监听多个Socket,并在某个Socket可读、可写时得到关照,从而避免无效的等待,充分利用CPU资源。现在的I/O多路复用都是采用的epoll模式实现,它会在关照用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不必要挨个遍历Socket来判定是否就绪,提升了性能。
其中Redis的网络模子就是利用I/O多路复用结合变乱的处理器来应对多个Socket请求,比如,提供了毗连应答处理器、命令回复处理器,命令请求处理器。
在Redis6.0之后,为了提升更好的性能,在命令回复处理器利用了多线程来处理回复变乱,在命令请求处理器中,将命令的转换利用了多线程,增长命令转换速率,在命令实行的时候,依然是单线程。
4.什么是缓存穿透 ? 怎么解决 ?

缓存穿透是指查询一个一定不存在的数据,假如从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到DB去查询,可能导致DB挂掉。这种情况大概率是遭到了攻击。解决方案的话,我们通常都会用布隆过滤器来解决它。
布隆过滤器:布隆过滤器重要是用于检索一个元素是否在一个集合中。我们当时利用的是redisson实现的布隆过滤器。
它的底层重要是先去初始化一个比较大的数组,内里存放的二进制0或1。在一开始都是0,当一个key来了之后经过3次hash盘算,模于数组长度找到数据的下标然后把数组中原来的0改为1,这样的话,三个数组的位置就能标明一个key的存在。查找的过程也是一样的。
当然是有缺点的,布隆过滤器有可能会产生一定的误判,我们一样平常可以设置这个误判率,大概不会凌驾5%,其实这个误判是必然存在的,要不就得增长数组的长度,其实已经算是很分别了,5%以内的误判率一样平常的项目也能接爱,不至于高并发下压倒数据库。
5.什么是缓存击穿 ? 怎么解决 ?

缓存击穿的意思是对于设置了过期时间的key,缓存在某个时间点过期的时候,恰好这时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一样平常都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把DB压垮。
解决方案有两种方式:
第一可以利用互斥锁:当缓存失效时,不立即去load db,先利用如Redis的setnx去设置一个互斥锁,当利用乐成返回时再进行load db的利用并回设缓存,否则重试get缓存的方法。
第二种方案可以设置当前key逻辑过期,大概是思绪如下:
在设置key的时候,设置一个过期时间字段一块存入缓存中,不给当前key设置过期时间。当查询的时候,从redis取出数据后判定时间是否过期。假如过期则开通另外一个线程进行数据同步,当火线程正常返回数据,这个数据不是最新的。
 当然两种方案各有利弊: 假如选择数据的强一致性,建议利用分布式锁的方案,性能上可能没那么高,锁必要等,也有可能产存亡锁的题目。 假如选择key的逻辑删除,则优先考虑的高可用性,性能比较高,但是数据同步这块做不到强一致。
6.什么是缓存雪崩 ? 怎么解决 ?

缓存雪崩意思是设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请责备部转发到DB,DB瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多key,击穿是某一个key缓存。
解决方案:重要是可以将缓存失效时间分散开,比如可以在原有的失效时间底子上增长一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的变乱。
7.redis做为缓存,mysql的数据怎样与redis进行同步呢?(双写一致性)

双写一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致。
强一致性:假如项目要求数据库与Redis保持高度一致,可以采用读写锁保证强一致性。采用redisson实现的读写锁,在读的时候添加共享锁,可以保证读读不互斥,读写互斥。当更新数据的时候,添加排他锁,它是读写,读读都互斥,这样就能保证在写数据的同时是不会让其他线程读数据的,避免了脏数据。这内里必要留意的是读方法和写方法上必要利用同一把锁才行。
允许短暂耽误:可以采用的阿里的canal组件实现数据同步:不必要更改业务代码,摆设一个canal服务。canal服务把自己伪装成mysql的一个从节点,当mysql数据更新以后,canal会读取binlog数据,然后在通过canal的客户端获取到数据更新缓存即可。
耽误双删:在一个线程删除缓存以后,可以设置一个时间间隔,让这个线程再删除一次缓存,只要其他的线程的写缓存利用是在这个线程两次删缓存利用之间实行的,这个线程就可以在第二次删除缓存时把其他线程写的脏数据给删撤除。但是其中这个延时多久不太好确定,在延时的过程中可能会出现脏数据,并不能保证强致性,所以一样平常不采用。
8.Redis的数据持久化是怎么做的?

在Redis中提供了两种数据持久化的方式:1、RDB 2、AOF:

  • RDB是一个快照文件,它是把redis内存存储的数据写到磁盘上,当redis实例宕机恢复数据的时候,方便从RDB的快照文件中恢复数据。
  • AOF的含义是追加文件,当redis利用写命令的时候,都会存储这个文件中,当redis实例宕机恢复数据的时候,会从这个文件中再次实行一遍命令来恢复数据。
速率快慢:RDB由于是二进制文件,在保存的时候体积也是比较小的,它恢复的比较快,但是它有可能会丢数据,我们通常在项目中也会利用AOF来恢复数据,固然AOF恢复的速率慢一些,但是它丢数据的风险要小很多,在AOF文件中可以设置刷盘策略,我们当时设置的就是每秒批量写入一次命令。
9.Redis的数据过期策略有哪些 ?

在redis中提供了两种数据过期删除策略。
第一种是惰性删除,在设置该key过期时间后,我们不去管它,当必要该key的时候,我们再检查其是否过期,假如过期,我们就删掉它,反之返回该key。
第二种是定期删除,就是说每隔一段时间,我们就对一些key进行检查,删除内里过期的key。定期删除的两种模式:


  • SLOW模式是定时任务,实行频率默认为10hz,每次不凌驾25ms,以通过修改设置文件redis.conf的hz选项来调解这个次数。
  • FAST模式实行频率不固定,每次变乱循环会尝试实行,但两次间隔不低于2ms,每次耗时不凌驾1ms。
通常情况下惰性删除+定期删除两种策略进行配合利用。
10.Redis的数据镌汰策略有哪些 ?

默认是noeviction,不删除任何数据,内部不足直接报错。
Redis的数据镌汰策略是可以在redis的设置文件中进行设置的,内里有两个非常紧张的概念,一个是LRU,另外一个是LFU。
LRU的意思就是近来最少利用,用当前时间减去最后一次访问时间,这个值越大则镌汰优先级越高。
LFU的意思是最少频率利用。会统计每个key的访问频率,值越小镌汰优先级越高。
我们在项目设置的allkeys-lru,挑选近来最少利用的数据镌汰,把一些经常访问的key留在redis中。
11.数据库有1000万数据 ,Redis只能缓存20w数据, 怎样保证Redis中的数据都是热点数据 ?

可以利用allkeys-lru(挑选近来最少利用的数据镌汰)镌汰策略,那留下来的都是经常访问的数据,也就是热点数据。
12.Redis的内存用完了会发生什么?

这个要看redis的数据镌汰策略是什么,假如是默认的设置,redis内存用完以后则直接报错。我们当时设置的allkeys-lru策略。把近来最常访问的数据留在缓存中,删除近来不经常访问的数据,腾出内存空间。
13.Redis分布式锁怎样实现 ?

在redis中提供了一个命令setnx(SET if not exists),利用setnx的原子特性实现分布式锁,由于redis的单线程的,用了命令之后,只能有一个客户端对某一个key设置值,在没有过期或删除key的时候是其他客户端是不能设置这个key的。
重要实现流程:

  • 首先辈行一个循环条件判定,判定是否乐成获取了锁;
  • 假如缓存中存在着这个数据,则结束循环条件判定,直接返回结果;
  • 假如缓存中不存在这个数据,则获取分布式锁,并设置一个过期时间防止加锁后宕机造成死锁;
  • 假如获取锁失败,表示有其他线程正在利用锁,则等待一段时间后再次进入循环条件判定;
  • 添加锁乐成,则添加缓存然后再释放锁,最后返回数据。在释放锁的时候,利用利用LUA脚本保证获取和删除利用的原子性。
14.怎样控制Redis实现分布式锁有效时长呢?

redis的setnx指令不好控制这个题目,我们当时采用的redis的一个框架redisson实现的。
在redisson中必要手动加锁,而且可以控制锁的失效时间和等待时间,当锁住的一个业务还没有实行完成的时候,在redisson中引入了一个看门狗机制,就是说每隔一段时间就检查当前业务是否还持有锁,假如持有就增长加锁的持偶然间,当业务实行完成之后必要利用释放锁就可以了。
另有一个好处就是,在高并发下,一个业务有可能会实行很快,先客户1持有锁的时候,客户2来了以后并不会立刻拒绝,它会自旋不停尝试获取锁,假如客户1释放之后,客户2就可以立刻持有锁,性能也得到了提升。
15.redisson实现的分布式锁是可重入的吗?

redisson实现的分布式锁是可以重入的。这样做是为了避免死锁的产生。这个重入其实在内部就是判定是否是当火线程持有的锁,假如是当火线程持有的锁就会计数,假如释放锁就会在盘算上减一。在存储数据的时候采用的是hash结构,大key可以按照自己的业务进行定制,其中小key是当火线程的唯一标识,value是当火线程重入的次数。
16.redisson实现的分布式锁能解决主从一致性的题目吗

这个是不能的,比如,当线程1加锁乐成后,master节点数据会异步复制到slave节点,此时当前持有Redis锁的master节点宕机,slave节点被提升为新的master节点,假如现在来了一个线程2,再次加锁,会在新的master节点上加锁乐成,这个时候就会出现两个节点同时持有一把锁的题目。
我们可以利用redisson提供的红锁来解决这个题目,它的重要作用是,不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁,而且要求在大多数redis节点上都乐成创建锁,红锁中要求是redis的节点数量要过半。这样就可以避免线程1加锁乐成后master节点宕机导致线程2乐成加锁到新的master节点上的题目了。
但是,假如利用了红锁,由于必要同时在多个节点上都添加锁,性能就变的很低了,而且运维维护成本也非常高,所以,我们一样平常在项目中也不会直接利用红锁,而且官方也临时废弃了这个红锁。
17.Redis集群有哪些方案, 知道嘛 ?

在Redis中提供的集群方案统共有三种:主从复制、哨兵模式、Redis分片集群
18.先容一下Redis的主从同步流程

单节点Redis的并发本领是有上限的,要进一步提高Redis的并发本领,可以搭建主从集群,实现读写分离。一样平常都是一主多从,主节点负责写数据,从节点负责读数据,主节点写入数据之后,必要把数据同步到从节点中。
主从同步数据流程:
主从同步分为了两个阶段,一个是全量同步,一个是增量同步。
全量同步是指从节点第一次与主节点创建毗连的时候利用全量同步,流程是这样的:

  • 第一:从节点请求主节点同步数据,其中从节点会携带自己的replication id和offset偏移量。
  • 第二:主节点判定是否是第一次请求,重要判定的依据就是,主节点与从节点是否是同一个replication id,假如不是,就说明是第一次同步,那主节点就会把自己的replication id和offset发送给从节点,让从节点与主节点的信息保持一致。
  • 第三:在同时主节点会实行bgsave,天生rdb文件后,发送给从节点去实行,从节点先把自己的数据清空,然后实行主节点发送过来的rdb文件,这样就可以保持了一致。
当然,假如在rdb天生实行期间,依然有请求到了主节点,而主节点会以命令的方式记录到缓冲区,缓冲区是一个日记文件,最后把这个日记文件发送给从节点,这样就能保证主节点与从节点完全一致了,后期再同步数据的时候,都是依靠于这个日记文件,这个就是全量同步
增量同步指的是,当从节点服务重启之后,数据就不一致了,所以这个时候,从节点会请求主节点同步数据,主节点还是判定不是第一次请求,不是第一次就获取从节点的offset值,然后主节点从命令日记中获取offset值之后的数据,发送给从节点进行数据同步。
19.怎么保证Redis的高并发高可用

首先可以搭建主从集群,再加上利用redis中的哨兵模式,哨兵模式可以实现主从集群的自动故障恢复,内里就包含了对主从服务的监控、自动故障恢复、关照;假如master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主;同时Sentinel也充当Redis客户端的服务发现泉源,当集群发生故障转移时,会将最新信息推送给Redis的客户端,所以一样平常项目都会采用哨兵的模式来保证redis的高并发高可用。
20.你们利用redis是单点还是集群,哪种集群

我们当时利用的是主从(1主1从)加哨兵。一样平常单节点不凌驾10G内存,假如Redis内存不足则可以给差异服务分配独立的Redis主从节点。只管不做分片集群。由于集群维护起来比较麻烦,而且集群之间的心跳检测和数据通信会消耗大量的网络带宽,也没有办法利用lua脚本和变乱。
21.什么是redis集群脑裂,该怎么解决呢?

有的时候由于网络等缘故原由可能会出现脑裂的情况,就是说,由于redis master节点和redis slave节点和sentinel处于差异的网络分区,使得sentinel没有能够心跳感知到master,所以通过选举的方式提升了一个salve为master,这样就存在了两个master,就像大脑分裂了一样,这样会导致客户端还在old master那边写入数据,新节点无法同步数据,当网络恢复后,sentinel会将old master降为salve,这时再重新master同步数据,这会导致old master中的大量数据丢失。
关于解决的话,我记得在redis的设置中可以设置:第一可以设置最少的salve节点个数,比如设置至少要有一个从节点才能同步数据,第二个可以设置主从数据复制和同步的耽误时间,达不到要求就拒绝请求,就可以避免大量的数据丢失。
22.redis的分片集群有什么作用?

分片集群重要解决的是,海量数据存储的题目,集群中有多个master,每个master保存差异数据,而且还可以给每个master设置多个slave节点,就可以继承增大集群的高并发本领。同时每个master之间通过ping监测彼此康健状态,就类似于哨兵模式了。当客户端请求可以访问集群恣意节点,最终都会被转发到正确节点。
23.Redis分片集群中数据是怎么存储和读取的?

Redis集群引入了哈希槽的概念,有16384个哈希槽,集群中每个主节点绑定了一定范围的哈希槽范围,key通过CRC16校验后对16384取模来决定放置哪个槽,通过槽找到对应的节点进行存储。取值的逻辑是一样的。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

雁过留声

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表