Redis 面试是否可以给个职位?

243 阅读6分钟

欢迎关注WX公众号:“程序猿补课班”,分享Java相关技术知识,学习经验,面试经验等。小伙伴快来补课吧!

正文开始 面试官:看你简历上用到了Redis,你们为啥用Redis?

面试者mini王:

为啥用 图片为啥用,经理让用就用呗。

NO NO,,, 系统中会存在一些缓存数据,而且缓解数据库的压力,所以用到了redis中间件。

面试官:那Redis 支持哪几种数据类型?

面试者mini王:

这so easy图片

String、List、Set、Sorted Set、hash

面试官:单线程的redis为什么这么快呢?

面试者mini王:

(一)纯内存操作

(二)单线程操作,避免了频繁的上下文切换

(三)采用了非阻塞I/O多路复用机制

面试官:什么是I/O多路复用呢?

面试者mini王:

嗯 果然会问。。还好有准备 嘿嘿

I/O 多路复用模型是利用select、poll、epoll可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll是只轮询那些真正发出了事件的流),依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

面试官:redis持久化的几种方式有哪些?

面试者mini王:

Redis 提供两种持久化机制 RDB(默认) 和 AOF 机制.

RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。

AOF持久化,则是将Redis执行的每次写命令记录到单独的日志文件中,当重启Redis会重新将持久化的日志中文件恢复数据。

面试官:来说说缓存击穿、缓存穿透、缓存雪崩有什么区别吧

面试者mini王:

缓存击穿是指缓存中没有但数据库中有的数据,这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

为了防止接下来问怎么解决呢 我就直接回答解决方案了图片 聪明的我。。。


解决方案是:

设置热点数据永远不过期。或者加互斥锁

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方案:

接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;

从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。

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

解决方案:

缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。

一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。

给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

图片

面试官:过期键的删除策略有哪些呢?

面试者mini王:

其实Redis采用的是定期删除+惰性删除策略。

还会附带设置内存淘汰策略

noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。

allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 Key。(推荐使用,目前项目在用这种)(最近最久使用算法)

allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 Key。(应该也没人用吧,你不删最少使用 Key,去随机删)

volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 Key。这种情况一般是把 Redis 既当缓存,又做持久化存储的时候才用。(不推荐)

volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 Key。(依然不推荐)

volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。(不推荐)

面试官:Redis 和数据库双写一致性问题怎么处理呢?

面试者mini王:可以保证最终一致性

采用延时双删策略。

(1)先淘汰缓存

(2)再写数据库

(3)休眠1秒,再次淘汰缓存

面试官:那如果删缓存失败了怎么办?

面试者mini王:

提供一个补偿措施即可,例如利用消息队列

面试官:你使用过Redis分布式锁么?

面试者mini王:先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。(注意这里是可以同时把setnx和expire合成一条指令来用的!)

还有zookeeper的分布式锁的大致思想为:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。完成业务流程后,删除对应的子节点释放锁。

面试官:Redis如何实现延时队列

面试者mini王:最简单的方式,定时扫表,或者使用Redis的zset、list的特性,我们可以利用redis来实现一个延迟队列RedisDelayQueue

使用RabbitMq或者其他MQ改造实现延迟队列。

如有错漏之处,敬请指正