阿里程序员去面外包,竟因Redis跪了!Redis面试连环炮,你能顶住第几问?

77 阅读18分钟

01 前言

大家好,我是救火队队长~

"兄弟,我今天面试直接被Redis干懵了..."

深夜11点,我刚准备睡觉,一个老同事的微信就来了。他上周刚被裁员,今天去面了个外包岗先试试水。

"不是吧?外包面试还能被Redis问倒?"我有点不敢相信。

"别提了,面试官一个接一个的问题,越问越深,最后直接原形毕露了..."

看着小王发来的面试过程,我冷汗直冒。这哪是外包面试,简直是Redis连环炮啊...

下面我们来看看同事被问的Redis一些问题,看看你能抗住几个。

02 说说Redis基本数据结构类型有哪些?

  • 字符串。没有采⽤C语⾔的传统字符串,⽽是⾃⼰实现的⼀个简单动态字符串SDS的抽象类型,并保存了⻓度信息。
  • 链表(linkedlist)。双向⽆环链表结构,每个链表的节点由⼀个listNode结构来表示,每个节点都有前置和后置节点的指针
  • 字典(hashtable)。保存键值对的抽象数据结构,底层使⽤hash表,每个字典带有两个hash表,供平时使⽤和rehash时使⽤。
  • 跳跃表(skiplist)。跳跃表是有序集合的底层实现之⼀。redis跳跃表由zskiplist和zskiplistNode组成,zskiplist⽤于保存跳跃表 信息(表头、表尾节点、⻓度等),zskiplistNode⽤于表示表跳跃节点,每个跳跃表的层⾼都是1- 32的随机数,在同⼀个跳跃表中,多个节点可以包含相同的分值,但是每个节点的成员对象必须是唯⼀的,节点按照分值⼤⼩排序,如果分值相同,则按照成员对象的⼤⼩排序。
  • 整数集合(intset)。⽤于保存整数值的集合抽象数据结构,不会出现复元素,底层实现为数组。
  • 压缩列表(ziplist)。为节约内存⽽开发的顺序性数据结构,可以包含多个节点,每个节点可以保存⼀个字节数组或者整数值。

03 Redis支持哪些数据类型?

五种常⽤数据类型: String 、 Hash 、 Set 、 List 、 SortedSet 。三种特殊的数据类型: Bitmap 、 HyperLogLog 、 Geospatial ,其中Bitmap 、HyperLogLog的底层都是 String 数据类型,Geospatial 底层是 Sorted Set 数据类型。

  • 字符串对象string:int整数、embstr编码的简单动态字符串、raw简单动态字符串
  • 列表对象list:ziplist、linkedlist
  • 哈希对象hash:ziplist、hashtable
  • 集合对象set:intset、hashtable
  • 有序集合对象zset:ziplist、skiplist

五种常用数据类型:

04 Redis为什么那么快?

  • 完全基于内存,没有磁盘IO上的开销,异步持久化除外。
  • 单线程,避免多个线程切换的性能损耗。
  • ⾮阻塞的IO多路复⽤机制。
  • 底层的数据存储结构优化,使⽤原⽣的数据结构提升性能。

05 为什么Redis6.0之后又改用多线程?

Redis的多线程主要是处理数据的读写、协议解析。执⾏命令还是采⽤单线程顺序执⾏。

主要是因为redis的性能瓶颈在于⽹络IO⽽⾮CPU,使⽤多线程进⾏⼀些周边预处理,提升了IO的读写效率,从⽽提⾼了整体的吞吐。antirez 在 RedisConf 2019 分享时提到,Redis 6 引⼊的多线程 IO 对性能提升⾄少⼀倍以上。

06 热点key问题怎么解决?

一些重要节日或者一些流量明星事件,还比如秒杀、双十一等促销活动,突然有几十万请求去访问redis上的某个特定key, 这样会导致流量过于集中,可能导致redis服务器宕机引发雪崩。

怎么提前发现hotKey?

  • 比如双十一,618等线上促销活动这些提前已知的事情,可以提前评估出可能的热 key 来。
  • 但是对于一些突发事件或者流量,无法提前评估,可以通过 Spark,Storm对应流任务进行实时分析,及时发现新发布的热点 key。而对于之前已发出的事情,逐步发酵成为热 key 的,则可以通过 Hadoop 对批处理任务离线计算,找出最近历史数据中的高频热 key。

解决方案:

  • 将热点key分散到不同缓存节点,请求时可以负载均衡,避免一个缓存节点过载。
  • 二级缓存,提交加载热key到内存,如果redis宕机,走内存查询。

07 Redis过期删除key的策略有哪些?

有3种过期删除策略。惰性删除、定期删除、定时删除。

  • 惰性删除。使⽤key时才进⾏检查,如果已经过期,则删除。缺点:过期的key如果没有被访问到,⼀直⽆法
  • 删除,⼀直占⽤内存,造成空间浪费。
  • 定期删除。每隔⼀段时间做⼀次检查,删除过期的key,每次只是随机取⼀些key去检查。
  • 定时删除。为每个key设置过期时间,同时创建⼀个定时器。⼀旦到期,⽴即执⾏删除。缺点:如果过期键⽐
  • 多时,占⽤CPU多,对服务的性能有很⼤影响。

08 Redis的内存空间不足,淘汰机制?

  • volatile-lru:从已设置过期时间的key中,移出最近最少使⽤的key进⾏淘汰
  • allkeys-lru:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最近最少使⽤的key(这个是最常⽤的)
  • volatile-ttl:从已设置过期时间的key中,移出将要过期的key
  • volatile-random:从已设置过期时间的key中,随机选择key淘汰
  • allkeys-random:从key中随机选择key进⾏淘汰
  • no-eviction:禁⽌淘汰数据。当内存达到阈值的时候,新写⼊操作报错
  • volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使⽤的数据淘汰(LFU(LeastFrequently Used)算法,也就是最频繁被访问的数据将来最有可能被访问到)
  • allkeys-lfu:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最不经常使⽤的key。

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

缓存击穿缓存击穿的概念是单个key过期时导致所有请求直接打到db上,这个和热key的问题比较类似,只是说的点在于过期导致请求全部打到DB。解决方案:

  • 互斥锁(分布式锁),比如请求查询A, 发现缓存中没有,对A这个key加锁,同时去数据库查询数据,写入缓存,再返回给用户,这样后面的请求就可以从缓存中拿到了。
  • 缓存预热,系统上线后,将相关可预期(例如排行榜) 热点数据直接加载到缓存。
  • 热点数据永不过期。

缓存穿透缓存穿透是指查询不存在的数据,每次都会打到数据库。解决方案:

  • 参数校验,接口层可以做参数校验,对一些无效的参数直接拦截。
  • 缓存空值,从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒。这样可以防止攻击用户反复用同一个id暴力攻击。
  • 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。

缓存雪崩当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上,这样可能导致整个系统的崩溃,称为雪崩。雪崩和击穿不太一样的是,他是说大量缓存同时过期,请求全部打到数据库。解决方案:

  • 随机过期时间,针对不同key设置不同的过期时间,避免同时过期。
  • 限流和熔断降级,如果redis宕机,可以进行限流和降级处理,避免同一时刻大量请求都打到DB。
  • 多级缓存,缓存可以抵挡掉一部分请求。

10 Redis持久化方式有哪些?有什么区别?

RDB:

1、快照RDB。将某个时间点上的数据库状态保存到 RDB⽂件 中,RDB⽂件是⼀个压缩的⼆进制⽂件,保存在磁盘上。当Redis崩溃时,可⽤于恢复数据。通过 SAVE 或 BGSAVE 来⽣成RDB⽂件。

SAVE:会阻塞redis进程,直到RDB⽂件创建完毕,在进程阻塞期间,redis不能处理任何命令请求。

BGSAVE:会fork出⼀个⼦进程,然后由⼦进程去负责⽣成RDB⽂件,⽗进程还可以继续处理命令请求,不会阻塞进程。

RDB优点:

(1)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说Amazon的S3云服务上去,在国内可以是阿里云的ODPS分布式存储上,以预定好的备份策略来定期备份redis中的数据

RDB也可以做冷备,生成多个文件,每个文件都代表了某一个时刻的完整的数据快照

AOF也可以做冷备,只有一个文件,但是你可以,每隔一定时间,去copy一份这个文件出来

RDB做冷备,优势在哪儿呢?由redis去控制固定时长生成快照文件的事情,比较方便; AOF,还需要自己写一些脚本去做这个事情,各种定时

RDB数据做冷备,在最坏的情况下,提供数据恢复的时候,速度比AOF快

(2)RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可

RDB,每次写,都是直接写redis内存,只是在一定的时候,才会将数据写入磁盘中

AOF,每次都是要写文件的,虽然可以快速写入os cache中,但是还是有一定的时间开销的,速度肯定比RDB略慢一些

(3)相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速

RDB缺点:

(1)如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据

这个问题,也是rdb最大的缺点,就是不适合做第一优先的恢复方案,如果你依赖RDB做第一优先恢复方案,会导致数据丢失的比较多

(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒

一般不要让RDB的间隔太长,否则每次生成的RDB文件太大了,对redis本身的性能可能会有影响的

AOF:

只追加⽂件AOF。以⽇志的形式记录每个写操作(⾮读操作)。当不同节点同步数据时,读取⽇志⽂件的内容将写指令从前到后执⾏⼀次,即可完成数据恢复。

AOF优点:

(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据

每隔1秒,就执行一次fsync操作,保证os cache中的数据写入磁盘中

redis进程挂了,最多丢掉1秒钟的数据

(2)AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复

(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。

(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据

AOF缺点:

(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大

(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的

如果你要保证一条数据都不丢,也是可以的,AOF的fsync设置成没写入一条数据,fsync一次,那就完蛋了,redis的QPS大降

(3)以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。

(4)唯一的比较大的缺点,其实就是做数据恢复的时候,会比较慢,还有做冷备,定期的备份,不太方便,可能要自己手写复杂的脚本去做,做冷备不太合适

RDB和AOF到底该如何选择

(1)不要仅仅使用RDB,因为那样会导致你丢失很多数据

(2)也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug

(3)综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复。

11 Redis怎么实现高可用?

主从模式

主从模式最大的优点是部署简单,最少两个节点便可以构成主从模式,并且可以通过读写分离避免读和写同时不可用。不过,一旦 Master 节点出现故障,主从节点就无法自动切换,直接导致 SLA 下降。所以,主从模式一般适合业务发展初期,并发量低,运维成本低的情况。主从模式核心就是主从同步。主从同步的原理如下:

1、slave启动后,向master发送sync命令

2、master收到sync之后,执⾏bgsave保存快照,⽣成RDB全⽂件

3、master把slave的写命令记录到缓存

4、bgsave执⾏完毕之后,发送RDB⽂件到slave,slave执⾏

5、master发送缓冲区的写命令给slave,slave接收命令并执⾏,完成复制初始化。

6、此后,master每次执⾏⼀个写命令都会同步发送给slave,保持master与slave之间数据的⼀致性

优点:

  • master能⾃动将数据同步到slave,可以进⾏读写分离,分担master的读压⼒
  • master、slave之间的同步是以⾮阻塞的⽅式进⾏的,同步期间,客户端仍然可以提交查询或更新请求

缺点:

  • 不具备⾃动容错与恢复功能,master 节点宕机后,需要⼿动指定新的 master
  • master宕机,如果宕机前数据没有同步完,则切换IP后会存在数据不⼀致的问题
  • 难以⽀持在线扩容,Redis的容受限于单机配置

哨兵模式

图片

哨兵模式基于主从复制模式,增加了哨兵来监控与⾃动处理故障。

优点:

哨兵模式基于主从复制模式,所以主从复制模式有的优点,哨兵模式也有

master 挂掉可以⾃动进⾏切换,系统可⽤性更⾼

缺点:

Redis的容受限于单机配置

需要额外的资源来启动sentinel进程

Redis Cluster模式

实现原理:

⼀个redis集群由多个节点node组成,⽽多个node之间通过 cluster meet 命令来进⾏连接,组成⼀个集群。数据存储通过分⽚的形式,整个集群分成了 16384 个slot,每个节点负责⼀部分槽位。整个槽位的信息会同步到所有节点中。

key与slot的映射关系:

健值对 key,进⾏ CRC16 计算,计算出⼀个 16 bit 的值

将 16 bit 的值对 16384 取模,得到 0 ~ 16383 的数表示 key 对应的哈希槽

优点:

  • ⽆中⼼架构,数据按照slot分布在多个节点
  • 集群中的每个节点都是平等的,每个节点都保存各⾃的数据和整个集群的状态。每个节点都和其他所有节点连接,⽽且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意⼀个节点,就可以获取到其他节点的数据。
  • 可线性扩展到1000多个节点,节点可动态添加或删除
  • 能够实现⾃动故障转移,节点之间通过 gossip协议 交换状态信息,⽤投票机制完成slave到master的⻆⾊转换

缺点:

  • 数据通过异步复制,不保证数据的强⼀致性
  • slave充当 “冷备”,不对外提供读、写服务,只作为故障转移使⽤。
  • 批操作限制,⽬前只⽀持具有相同slot值的key执⾏批操作,对mset、mget、sunion等操作⽀持不友好
  • key事务操作⽀持有限,只⽀持多key在同⼀节点的事务操作,多key分布在不同节点时⽆法使⽤事务功能
  • 不⽀持多数据库空间,⼀台redis可以⽀持16个db,集群模式下只能使⽤⼀个,即db0。
  • Redis Cluster模式不建议使⽤pipeline和multi-keys操作,减少max redirect产⽣的场景。

12 Redis如何做扩容?

为了避免数据迁移失效,通常使⽤ ⼀致性哈希 实现动态扩容缩容,有效减少需要迁移的Key数。但是Cluster 模式,采⽤固定Slot槽位⽅式(16384个),对每个key计算CRC16值,然后对16384取模,然后根据slot值找到⽬标机器,扩容时,我们只需要迁移⼀部分的slot到新节点即可。

13 Redis事务机制了解吗?

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

具体过程:

  • 服务端收到客户端请求,事务以 MULTI 开始
  • 如果正处于事务状态时,则会把后续命令放⼊队列同时返回给客户端 QUEUED ,反之则直接执⾏这个命令
  • 当收到客户端的 EXEC 命令时,才会将队列⾥的命令取出、顺序执⾏,执⾏完将当前状态从事务状态改为⾮事务状态
  • 如果收到 DISCARD 命令,放弃执⾏队列中的命令,可以理解为Mysql的回滚操作,并且将当前的状态从事务状态改为⾮事务状态

WATCH 监视某个key,该命令只能在MULTI命令之前执⾏。如果监视的key被其他客户端修改,EXEC将会放

弃执⾏队列中的所有命令。 UNWATCH 取消监视之前通过WATCH 命令监视的key。通过执⾏EXEC 、

DISCARD 两个命令之前监视的key也会被取消监视。

关于Redis常见面试题,还有哪些,欢迎在评论区分享你的想法,我会第一时间回复。-End-原创作者|救火队队长关于我:我是救火队队长,9年后端开发经验,在阿里工作。负责过订单交易、商品、资金账户等业务系统。擅长分布式、微服务、高并发和架构设计。最近在梳理一线大厂工作中用到的技术经验,帮助你快速提升技术硬核能力,让你少走弯路。

📢📢 欢迎关注下方公众号回复【666】,领取AI领域前沿资料、技术资料、大厂面试资料,成为offer收割机~