前言
共20
题。
项目中为什么用Redis?
-
操作速度快:数据都保存在内存中;
-
数据类型丰富 :支持
string
,list
,set
,Zset
,hash
等数据类型; -
使用场景丰富 :缓存,消息队列,按
key
设置过期时间,过期后自动删除。
Redis的基础数据类型有哪些?
Redis
最常见的数据类型有5
种,分别是String
、List
、Hash
、Set
、ZSet
-
String:字符串类型,场景:计数、缓存文本内容等;
-
List:底层是链表,增删容易随机访问困难。场景:消息队列;
-
Hash :类似于
Java
中的HashMap
,存储对象。场景:系统中对象数据的存储; -
Set:无序集合;
-
ZSet:有序集合,且集合中每个元素关联一个分数,可以根据分数进行排序。
Redis为什么这么快?
-
纯内存操作 :
Redis
的绝大部分请求是纯粹的内存操作,非常快速; -
单线程 :
Redis
的核心部分是单线程运行的,避免了不必要的上下文切换,也不存在线程切换导致的CPU
消耗; -
使用I/O多路复用模型 :利用单个线程来同时监听多个
Socket
,并在某个Socket
可读、可写时得到通知,从而避免无效的等待,充分利用CPU
资源。 -
数据类型 :
redis
内置了多种优化过的数据类型(5
种基本数据类型+5
种复杂数据类型 ),这些数据类型的性能非常高。
Redis的过期删除策略有哪些?
Redis
的过期删除策略有:
-
惰性删除 :只会在取出
key
的时候才对数据进行过期检查,过期了就删除; -
定期删除 :每隔一段时间抽取一批
key
执行删除过期key
操作。
两者相比,定期删除 对内存更加友好,惰性删除 对CPU
更加友好。
Redis
采用的是定期删除 +惰性/懒汉式删除。
Redis的内存淘汰策略有哪些?
内存淘汰策略指的是:当Redis
的内存已经存满,又有新的数据需要保存时的处理方案。
Redis
的内存淘汰策略有:
- 默认策略:直接报错;
- 随机淘汰策略;
- 淘汰最少使用策略。
Redis持久化RDB和AOF的区别?
-
RDB 采用的是定期更新的方式,磁盘上保存的就是
Redis
的内存快照。文件较小,数据恢复速度较快,但存在丢失数据的风险; -
AOF 磁盘保存的是所有执行的指令,在下次
Redis
重启时,只需要将指令重写一遍即可。相对完整但文件较大,数据恢复的速度较慢。
实践中可以同时开启
RDB
和AOF
持久化机制。Redis
重启时先使用AOF
日志进行恢复,然后再使用RDB
快照进行备份。定期进行RDB
快照的备份,以便在需要时进行全量数据的恢复,提高数据的可靠性、恢复能力以及持久化能力。
RDB期间可以同时处理写请求吗?
可以,bgsave
快照备份时不耽误写,但save
不行。
-
具体来说,就是
Redis
在持久化时会产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求; -
当主线程执行写指令修改数据的时候,这个数据就会复制一份副本,然后修改副本中的数据,
RDB
结束后,主进程读取这个副本数据写到RDB
文件; -
这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
Redis集群有哪些方案?
Redis集群主要有三种方案,分别是主从 、哨兵 和分片集群。
-
主从 集群主要用来解决
Redis
的并发问题,实现读写分离。一个主节点负责写,多个从节点负责读,主节点的数据会实时同步给从节点; -
哨兵 集群主要用来解决
Redis
的高可用问题。哨兵会监控集群中节点状态,并在主节点出现问题时重新选主,但他不保存数据; -
分片 集群主要用来解决
Redis
的海量数据存储和高并发写的问题--哈希槽。要求有多个主节点,然后写入的数据会经过计算落到其中一个上。
如何保证Redis数据与MySQL一致?
常见的有三种:
-
同步双写 :即在程序更新完
MySQL
之后后立即同步更新redis
; -
异步监听 :即通过
Canal
监听MySQL
的binlog
日志变化,然后再通过程序将变化的数据更新数据到Redis
; -
MQ异步 :即程序在更新完
MySQL
后,发送一条消息到MQ
中,然后再通过一个程序监听MQ
,获取到消息,然后更新Redis
。
什么是缓存预热?
缓存预热指的是:提前将数据放进Redis
中--先查Redis
再查MySQL
,避免高并发访问时,对数据库造成的压力。
缓存预热解决方案主要有下面几个:
-
数据量不大的时候,工程启动的时候进行加载缓存动作;
-
数据量大的时候,设置一个定时任务脚本,进行缓存的刷新;
-
数据量太大的时候,优先保证热点数据进行提前加载到缓存。
什么是缓存穿透,怎么解决?
缓存穿透指的是:当查询redis
中未存在的数据时就会去MySQL
中查询,然后大量请求进入MySQL
就会导致MySQL
承受不了压力而宕机。常用的解决方案有:
-
对传入参数进行判断是否合法;
-
对数据库未查询到的
id
信息也存入redis
,这样下次查询就会从redis
中获取; -
使用布隆过滤器 :以较小内存为代价的,用于检测大量元素是否存在的算法,核心原理是二进制数组 + 哈希运算,可以通过
Redisson
、Guava
、Hutool
来实现。
什么是缓存击穿,怎么解决?
缓存击穿指的是:当redis
中一个热点数据的过期时间到了,然后还有大量请求来访问这个热点数据,但redis
已经对该数据做了过期处理,这个时候就会访问MySQL
当大量请求进入MySQL
,就会导致MySQL
承受不了压力而宕机。
常用的解决方案有:
-
不对热点数据设置过期时间;
-
布隆过滤器。
什么是缓存雪崩,怎么解决?
当redis
中的大量数据都是同一过期时间,当这些数据同时过期,这时候然后大量请求过来在redis
中没有拿到数据,这些请求就会去MySQL
中获取数据,导致MySQL
承受不了压力而宕机。
解决方案:给这些数据设置随机过期时间或者不进行过期处理。
用过Redis的事务吗?
没有用过,他本身没有事务概念但一些命令组合起来可以起到事务的效果。
什么类型的数据适合往redis里放?
- 热点数据:也即需频繁访问的数据;
- 会话数据:存储用户会话信息如登录状态;
- 消息队列:存储消息队列中的消息。
redis除了5种基本数据类型,还有哪些类型?
除了5
种基本数据类型,redis
还有5
种特殊数据类型:
- GEO地理位置类型,用于存储地理位置信息并进行相关操作,如添加地理位置的坐标、获取地理位置的坐标、计算两个位置之间的距离等。
- HyperLogLog类型 用于基数统计,基数指的是去重后元素出现的个数,
HyperLogLog
类型的优点在于输入元素的数量或体积很大时,计算基数所需的空间总是固定且很小; - Bitmap :位图,是由
0
和1
状态表示的二进制位的bit
数组,用于处理大量数据的布尔值状态。可以用作布隆过滤器的数据类型。 - bitfield类型:可以一次性对多个比特域进行操作。
- Stream类型 :
Stream
类型是redis5.0
新增加的数据结构,主要用于消息队列。Stream
类型提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每个客户端的访问位置,保证消息不丢失。
你们的redis是什么版本?
实际开发常用版本7
。
布隆过滤器会不会出现判断不准确的情况?
布隆过滤器可能会误判,原因在于它使用了哈希算法,Hash
算法存在着一定的碰撞几率。Hash碰撞的含义是不同的输入值经过hash得到相同的hash结果。
当一个不存在于redis
的数据经过布隆过滤器时,先根据哈希算法计算出其在数组上的位置,此时该哈希槽可能因为其他数据计算出相同位置,该位置数据状态已经变成1
(1
表示数据存在,0
表示数据不存在),因此布隆过滤器认为该数据存在,这就产生了误判。
但是,如果布隆过滤器判断这个元素不在redis
时,它就一定不在redis
中,因此非常适合解决缓存穿透的问题。
关于io多路复用,redis在windows和linux上的性能表现会不会不同?
redis
在linux
上的性能表现高于windows
,主要的区别是操作系统内核的不同。
redis
在linux
上通过单线程epoll
非阻塞同步模型 + 自己开发的一个事件框架实现了io
多路复用模型,windows
上则没有epoll
。
为什么使用redis存储消息队列的消息?
因为redis
直接操作内存非常快速,且可以设置key
的过期时间,还有专门存储消息队列的数据类型Stream
,Stream
类型能够实现消息的持久化和主备复制,可以让任何客户端访问任何时刻的数据,并且能记住每个客户端的访问位置,保证消息不丢失