Redis面试连环15问

1、Redis基本数据类型有哪些?

Redis 是一种基于键值对的NoSQL缓存数据库,key都是由字符串构成的,而它的值主要由string(字符串),hash(哈希),list(列表),set(集合),zset(有序集合)五种基本数据结构构成,除此之外还支持一些其他的数据结构和算法。在开发中,字符串类型是用的最多的数据类型,导致我们忽视了redis的其他四种数据类型,在具体场景下选择具体的数据类型对提升Redis性能有非常大的帮助。

  • String(字符串)

  • Hash(哈希)

  • List(列表)

  • Set(集合)

  • zset(有序集合)


2、Redis为什么这么快?

Redis的速度非常的快,单机的Redis就可以支撑每秒10几万的并发,相对于MySQL来说,性能是MySQL的几十倍。速度快的原因主要有几点:

  1. 完全基于内存操作

  2. C语言实现,优化过的数据结构,基于几种基础的数据结构,Redis做了大量的优化,性能极高

  3. 使用单线程,无上下文的切换成本

  4. 基于非阻塞的IO多路复用机制


3、那为什么Redis6.0之后又改用多线程呢?

Redis使用多线程并非是完全摒弃单线程,Redis还是使用单线程模型来处理客户端的请求,只是使用多线程来处理数据的读写和协议解析,执行命令还是使用单线程。

这样做的目的是因为Redis的性能瓶颈在于网络IO而非CPU,使用多线程能提升IO读写的效率,从而整体提高Redis的性能。


4、知道什么是热key吗?热key问题怎么解决?

所谓热key问题就是,突然有几十万的请求去访问Redis上的某个特定key,那么这样会造成流量过于集中,达到物理网卡上限,从而导致这台Redis的服务器宕机引发雪崩。

Redis面试连环15问_第1张图片

针对热key的解决方案:

  1. 提前把热key打散到不同的服务器,降低压力

  2. 加入二级缓存,提前加载热key数据到内存中,如果redis宕机,走内存查询


5、什么是缓存击穿、缓存穿透、缓存雪崩?

5.1 缓存穿透问题

缓存穿透:读请求访问时,缓存和数据库都没有某个值,这样就会导致每次对这个值的查询请求都会穿透到数据库,这就是缓存穿透。

缓存穿透一般都是这几种情况产生的:

  • 业务不合理的设计,比如大多数用户都没开守护,但是你的每个请求都去缓存,查询某个userid查询有没有守护。

  • 业务/运维/开发失误的操作,比如缓存和数据库的数据都被误删除了。

  • 黑客非法请求攻击,比如黑客故意捏造大量非法请求,以读取不存在的业务数据。

如何避免缓存穿透呢? 一般有三种方法:

1.如果是非法请求,我们在API入口,对参数进行校验,过滤非法值。

2.如果查询数据库为空,我们可以给缓存设置个空值,或者默认值。但是如有有写请求进来的话,需要更新缓存哈,以保证缓存一致性,同时,最后给缓存设置适当的过期时间。(业务上比较常用,简单有效)

3.使用布隆过滤器快速判断数据是否存在。即一个查询请求过来时,先通过布隆过滤器判断值是否存在,存在才继续往下查。

5.2 缓存雪奔问题

缓存雪奔: 指缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至down机。

  • 缓存雪奔一般是由于大量数据同时过期造成的,对于这个原因,可通过均匀设置过期时间解决,即让过期时间相对离散一点。如采用一个较大固定值+一个较小的随机值,5小时+0到1800秒酱紫。

  • Redis 故障宕机也可能引起缓存雪奔,这就需要构造Redis高可用集群。

5.3 缓存击穿问题

缓存击穿: 指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。

缓存击穿看着有点像,其实它两区别是,缓存雪奔是指数据库压力过大甚至down机,缓存击穿只是大量并发请求到了DB数据库层面。可以认为击穿是缓存雪奔的一个子集吧。有些文章认为它俩区别,是区别在于击穿针对某一热点key缓存,雪奔则是很多key。

解决方案就有两种:

1.使用互斥锁方案。缓存失效时,不是立即去加载db数据,而是先使用某些带成功返回的原子操作命令,如(Redis的setnx)去操作,成功的时候,再去加载db数据库数据和设置缓存。否则就去重试获取缓存。

2. “永不过期”,是指没有设置过期时间,但是热点数据快要过期时,异步线程去更新和设置过期时间


6、Redis的过期策略有哪些?

redis主要有2种过期删除策略

惰性删除

惰性删除指的是当我们查询key的时候才对key进行检测,如果已经达到过期时间,则删除。显然,他有一个缺点就是如果这些过期的key没有被访问,那么他就一直无法被删除,而且一直占用内存。

Redis面试连环15问_第2张图片

定期删除

定期删除指的是redis每隔一段时间对数据库做一次检查,删除里面的过期key。由于不可能对所有key去做轮询来删除,所以redis会每次随机取一些key去做检查和删除。

那么定期+惰性都没有删除过期的key怎么办?

假设redis每次定期随机查询key的时候没有删掉,这些key也没有做查询的话,就会导致这些key一直保存在redis里面无法被删除,这时候就会走到redis的内存淘汰机制。

  1. volatile-lru:从已设置过期时间的key中,移出最近最少使用的key进行淘汰

  2. volatile-ttl:从已设置过期时间的key中,移出将要过期的key

  3. volatile-random:从已设置过期时间的key中随机选择key淘汰

  4. allkeys-lru:从key中选择最近最少使用的进行淘汰

  5. allkeys-random:从key中随机选择key进行淘汰

  6. noeviction:当内存达到阈值的时候,新写入操作报错


7、Redis是单线程还是多线程呢?

Redis不同版本之间采用的线程模型是不一样的,在Redis4.0版本之前使用的是单线程模型,在4.0版本之后增加了多线程的支持。

在4.0之前虽然我们说Redis是单线程,也只是说它的网络I/O线程以及Set 和 Get操作是由一个线程完成的。但是Redis的持久化、集群同步还是使用其他线程来完成。

4.0之后添加了多线程的支持,主要是体现在大数据的异步删除功能上,例如 unlink keyflushdb asyncflushall async


8、为什么Redis在4.0之前会选择使用单线程?而且使用单线程还那么快?

选择单线程个人觉得主要是使用简单,不存在锁竞争,可以在无锁的情况下完成所有操作,不存在死锁和线程切换带来的性能和时间上的开销,但同时单线程也不能完全发挥出多核CPU的性能。

至于为什么单线程那么快我觉得主要有以下几个原因:

  1. Redis 的大部分操作都在内存中完成,内存中的执行效率本身就很快,并且采用了高效的数据结构,比如哈希表和跳表。

  2. 使用单线程避免了多线程的竞争,省去了多线程切换带来的时间和性能开销,并且不会出现死锁。

  3. 采用 I/O 多路复用机制处理大量客户端的Socket请求,因为这是基于非阻塞的 I/O 模型,这就让Redis可以高效地进行网络通信,I/O的读写流程也不再阻塞。


9、Redis是如何实现数据不丢失的呢?

Redis数据是存储在内存中的,为了保证Redis数据不丢失,那就要把数据从内存存储到磁盘上,以便在服务器重启后还能够从磁盘中恢复原有数据,这就是Redis的数据持久化。Redis数据持久化有三种方式。

  • AOF 日志(Append Only File,文件追加方式):记录所有的操作命令,并以文本的形式追加到文件中。

  • RDB 快照(Redis DataBase):将某一个时刻的内存数据,以二进制的方式写入磁盘。

  • 混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDB 和 AOF 的优点。


10、AOF和 RDB的实现原理?

AOF采用的是写后日志的方式,Redis先执行命令把数据写入内存,然后再记录日志到文件中。AOF日志记录的是操作命令,不是实际的数据,如果采用AOF方法做故障恢复时需要将全量日志都执行一遍。

RDB采用的是内存快照的方式,它记录的是某一时刻的数据,而不是操作,所以采用RDB方法做故障恢复时只需要直接把RDB文件读入内存即可,实现快速恢复。


11、RDB做快照时会阻塞线程吗?RDB 做快照的时候数据能修改吗?

Redis 提供了两个命令来生成 RDB 快照文件,分别是 save 和 bgsavesave 命令在主线程中执行,会导致阻塞。而 bgsave 命令则会创建一个子进程,用于写入 RDB 文件的操作,避免了对主线程的阻塞,这也是 Redis RDB 的默认配置。

save是同步的会阻塞客户端命令,bgsave的时候是可以修改的。


12、Redis如何实现高可用?

Redis实现高可用主要有三种方式:主从复制、哨兵模式,以及 Redis Cluster集群。

主从复制

将从前的一台 Redis 服务器,同步数据到多台从 Redis 服务器上,即一主多从的模式,这个跟MySQL主从复制的原理一样。

Redis面试连环15问_第3张图片


哨兵模式

使用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器出现故障宕机时,需要手动进行恢复,为了解决这个问题,Redis 增加了哨兵模式实现主从故障自动切换(因为哨兵模式做到了可以监控主从服务器,并且提供自动容灾恢复的功能)。

Redis面试连环15问_第4张图片


Redis Cluster(切片集群)

Redis Cluster 是一种分布式去中心化的运行模式,是在 Redis 3.0 版本中推出的 Redis 集群方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高 Redis 服务的读写性能。

Redis面试连环15问_第5张图片


13、为什么还需要使用Redis Cluster集群模式呢?

使用哨兵模式在数据上有副本数据做保证,在可用性上又有哨兵监控,一旦master宕机会选举salve节点为master节点,这种已经满足了我们的生产环境需要,为什么还会出现Redis Cluster。

哨兵模式归根节点还是主从模式,在主从模式下我们可以通过增加slave节点来扩展读并发能力,但是没办法扩展写能力和存储能力,存储能力只能是master节点能够承载的上限。所以为了扩展写能力和存储能力,我们就需要引入Redis Cluster集群模式。


14、Redis Cluster怎么实现节点选择的吗?

集群中那么多Master节点,redis cluster在存储的时候如何确定选择哪个节点呢?Redis Cluster采用的是类一致性哈希算法实现节点选择的。

Redis Cluster将自己分成了16384个Slot(槽位),哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中,具体执行过程分为两大步。

  • 根据键值对的 key,按照 CRC16 算法计算一个 16 bit 的值。

  • 再用 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。

每个Redis节点负责处理一部分槽位,假如你有三个master节点 ABC,每个节点负责的槽位如下:

节点 处理槽位
A 0-5000
B 5001 - 10000
C 10001 - 16383

客户端给一个Redis实例发送数据读写操作时,如果这个实例上并没有相应的数据,会怎么样呢?MOVED重定向和ASK重定向了解一下哈

在Redis cluster模式下,节点对请求的处理过程如下:

  1. 通过哈希槽映射,检查当前Redis key是否存在当前节点

  2. 若哈希槽不是由自身节点负责,就返回MOVED重定向

  3. 若哈希槽确实由自身负责,且key在slot中,则返回该key对应结果

  4. 若Redis key不存在此哈希槽中,检查该哈希槽是否正在迁出(MIGRATING)?

  5. 若Redis key正在迁出,返回ASK错误重定向客户端到迁移的目的服务器上

  6. 若哈希槽未迁出,检查哈希槽是否导入中?

  7. 若哈希槽导入中且有ASKING标记,则直接操作,否则返回MOVED重定向


15、了解Redis事务机制吗?

redis通过MULTI、EXEC、WATCH等命令来实现事务机制,事务执行过程将一系列多个命令按照顺序一次性执行,并且在执行期间,事务不会被中断,也不会去执行客户端的其他请求,直到所有命令执行完毕。事务的执行过程如下:

  1. 服务端收到客户端请求,事务以MULTI开始

  2. 如果客户端正处于事务状态,则会把事务放入队列同时返回给客户端QUEUED,反之则直接执行这个命令

  3. 当收到客户端EXEC命令时,WATCH命令监视整个事务中的key是否有被修改,如果有则返回空回复到客户端表示失败,否则redis会遍历整个事务队列,执行队列中保存的所有命令,最后返回结果给客户端

WATCH的机制本身是一个CAS的机制,被监视的key会被保存到一个链表中,如果某个key被修改,那么REDIS_DIRTY_CAS标志将会被打开,这时服务器会拒绝执行事务。


参考链接:

《我想进大厂》之Redis夺命连环11问

你可能感兴趣的:(Redis,Redis高频面试题,Redis常见问题)