Redis的面试题

Redis是一种高性能的键值对数据库,采用内存存储数据并支持持久化。其单线程模型避免了线程切换开销,提供多种数据结构如String、List、Set等,常用于缓存、计数器、队列等场景。持久化包括RDB快照和AOF日志,以应对数据丢失。Redis通过主从复制、哨兵模式和集群实现高可用性,解决并发和数据一致性的挑战。
摘要由CSDN通过智能技术生成

目录

讲一下你理解的Redis,为什么Redis很快?

Redis为什么是单线程的?

Redis的5种数据存储结构+使用场景

Redis如何存储一个java对象如何实现【实现序列化接口】?

你们项目是怎么用Redis的?

redis为什么进行持久化?

Redis如何解决高并发?

怎么防止Redis宕机数据丢失问题?

Redis持久化机制是什么?有几种方式?

RDB和AOF的差别?【结合使用,各有所长】

Redis内存满了不够了怎么办?

你们Redis用在哪些业务上?用的什么存储结构?

Redis怎么实现栈和队列?

为什么要对Rdis实现淘汰策略?

Redis的key加一个过期时间,原生的操作命令是什么?

Redis事务和Mysql事务的区别?

使用Redis如何实现消息广播?

为什么要使用Redis做缓存?

缓存的执行流程?

你们怎么保证Redis和Mysql的数据一致性?

SpringCache常用注解

了解Redis缓存击穿,穿透,雪崩吗?怎么处理?

你们Redis用来做什么?使用的什么结构?

你们项目是如何做服务降级的?

基于Redis实现的分布式锁?

Redis如何实现分布式锁,用什么命令?

项目中怎么使用分布式锁的?

Redission的看门狗原理?

接口幂等一般怎么设计?(使用到了Redis)

信号量的作用?如果不用信号量,用什么?(加锁,存储到Redis,库存必须大于0)

秒杀为什么要Redis的存储结构hash?不用其他的存储方式?

Redis的设计模式【单节点模式、主从模式、哨兵模式、Clusting模式】

一、单节点模式

二、主从模式【主节点挂掉需要手动升级】

三、哨兵模式

四、 Clusting集群模式

什么情况下Redis集群不可用?

Redis存储结构底层有没有了解?什么是SDS



---

讲一下你理解的Redis,为什么Redis很快?

Redis:是一种高性能的,开源的,C语言编写的Nosql【非关系型数据库的泛指(没有以关系模型创建的数据库)】--不保证数据的ACID特性【事务一旦提交,都不会进行回滚】

采用键值对存储数据在内存或磁盘中,可以对关系型数据库起到补充作用,同时支持持久化[可以将数据保存在可掉电设备中],可以将数据同步保存到磁盘

说Redis很快是相对于关系型数据库如mysql来说的,主要有以下因素

第一,数据结构简单,所以速度快【采用键值对的方式】

第二,直接在内存中读写数据,所以速度快

第三,采用多路IO复用模型,减少网络IO的时间消耗,避免大量的无用操作,所以速度快

第四,单线程避免了线程切换和上下文切换产生的消耗,所以速度快

Mysql:关系型数据库--保证数据的ACID特性【事务的四大特性】

【以关系模型创建的数据库--(行和列组成的二维表)】,简单理解:有二维表的数据库。【数据保存在磁盘中-持久化(可以保存在可掉电设备当中)】

Redis为什么是单线程的?

1因为Redis的性能很高,官方网站也有,普通笔记本轻松处理每秒几十万的请求。【这也可以解释为什么不需要进行加锁。因为读取很快。每条能处理每秒几十万的请求】

2不需要各种锁的性能消耗

Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。这些操作可能就需要加非常多的锁,导致性能很低。

Redis的5种数据存储结构+使用场景

Redis是典型的key-value类型数据库,key为字符类型,value形式包括String,List,Set,ZSet,Hash。

Redis 在互联网产品中使用的场景实在是太多太多,这里分别对 Redis 几种数据类型做了整理:

1)String字符串:缓存(存储图片验证码和手机验证码)、计数器等。

2)Hash散列表:秒杀活动(可以存储单个对象也可以存储一个集合对象),用户信息、用户主页访问量、组合查询等。Map<String,Map<String,List<Hash>>>

3)List列表:做队列,秒杀(排队,FIFO)。

4)Set集合:抽奖小程序(不能重复参与抽奖),点赞和收藏(不能重复进行点赞)。【不能存储重复的数据,底层存储使用的是map的key进行存储数据】

5)ZSet有序集合:排行榜(可以根据某个字段进行排序)。

Redis如何存储一个java对象如何实现【实现序列化接口】?

1.将对象序列化(对象实现序列化接口)后保存到Redis

2.将对象用FastJSON转为JSON字符串【JSON.stringify()】后存储

Redis中要存储java对象,对象就要实现序列化接口implements Serializable,序列化就是将对象进行流化(将对象转换陈二进制数据),然后进行存储。

反序列化将存储的对象进行取出。

因为:Redis是采用key和value键值对的方式进行存储的,key和value都支持二进制安全的字符串。

你们项目是怎么用Redis的?

使用的是Springboot整合的redis,我们项目中主要使用Redis来存储注册时候的图形验证码和手机验证码,还有使用redis存储黑名单列表,还有用Redis的Hash存储结构来存储秒杀活动和秒杀课程,主要是因为Redis是采用键值对的方式将数据存储在内存当中,我们对数据进行查询的时候直接从内存当中获取,减少去数据库进行查询,从而降低数据库的压力,并且提高了查询效率。

redis为什么进行持久化?

因为Redis是存储数据是采用键值对的方式进行存储到内存当中,这样读取数据的速度非常快, 但是一旦服务器宕机,内存中的数据将全部丢失,

因此需要将缓存中数据进行持久化, 通常持久化的方式有两种, AOF日志和RDB快照

Redis如何解决高并发?

Redis采用主从集群的方式,实现读写分离,主节点(主服务器负责写入数据),并将数据同步给其他从节点,从节点负责读取,从而解决高并发。

怎么防止Redis宕机数据丢失问题?

通过对Redis持久化机制,把内存中的数据和命令备份到磁盘中,当Redis发生宕机,重启服务器的时候,会从磁盘重新加载备份的数据,从而解决数据丢失问题

Redis持久化机制是什么?有几种方式?

Redis持久化机制就是将内存中的数据 备份到磁盘的过程,就叫作持久化,【数据可保存在可掉电设备当中】

Redis持久化机制主要有两种方式,

RDB快照【Redis DataBase】和AOF日志【Append Only File】

RDB快照【Redis DataBase--记录数据快照】:在指定的时间间隔内将内存中的数据集**快照【不稳定】写入到磁盘中。

AOF日志【Append Only File--记录写命令的】:将所有对数据库进行写入的命令(及其参数)记录到AOF文件中。将Reids的操作日志以 追加的方式写入文件。

以 日志 的形式记录服务器所处理的每一次写、删除的操作,不会记录查询的操作,以文本的形式记录,当服务器重启的时候会重新执行这些命令来恢复原始的数据【采用系统执行命令成功才会被记录到日志中。可以避免记录错误命令的情况。】

RDB和AOF的差别?【结合使用,各有所长】

1 AOF数据更加安全【三种同步策略,每秒同步,每修改同步,不同步】,保存在磁盘中,而RDB不能保证数据库数据百分百不丢失,因为它是每隔一定时间保存一次(即满足save机制才进行持久化)。

2 AOF文件比RDB文件大,启动恢复速度慢,体积相对较小,启动恢复速度快**。**

3 数据量大的时候,AOF启动效率更低

AOF比RDB更新效率高,优先使用AOF还原数据,AOF比RDB更安全也更大,RDB性能比AOF号,如果两者都配了,优先加载AOF

Redis内存满了不够了怎么办?

Redis采用键值对的方式将数据存储在内存中.

方式一:增加电脑的物理内存【Redis可以使用电脑物理最大内存,当然我们通常会通过设置在redis.windows.conf 中 maxmemory**参数限制Redis内存的使用】**

方式二:使用淘汰策略,删掉一些老旧数据【下面有】

Volatile:不稳定的 --可以理解为有设置过期时间的。

lru【least recently used】:最近最少使用的。

ttl【time to live】:生存时间,还剩多长时间

allkeys:所有的redis键

volatile-lru :从已设置过期时间的数据集中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集中任意选择数据淘汰

allkeys-lru:从 数据集中 挑选最近最少使用的数据淘汰

allkeys-random:从数据集中任意选择数据淘汰

no-enviction:不能淘汰数据

方式三:Redis使用集群,多个Redis进行存储数据。【还可以解决高并发问题】

扩展:Redis缓存每命中一次Redis中设置过期时间的数据时,就会给命中的数据增加一定的ttl【过期时间】。一段时间后, 热数据的ttl都会较大, 不会自动失效, 而冷数据基本上过了设定的ttl就马上失效了

你们Redis用在哪些业务上?用的什么存储结构?

使用的是Springboot整合的redis,我们项目中主要使用Redis来存储注册时候的图形验证码和手机验证码,还有使用redis存储黑名单列表,还有用Redis的Hash存储结构来存储秒杀活动和秒杀课程,主要是因为Redis是采用键值对的方式将数据存储在内存当中,我们对数据进行查询的时候直接从内存当中获取,减少去数据库进行查询,从而降低数据库的压力,并且提高了查询效率。

Redis怎么实现栈和队列?

Redis是使用list可以实现栈和队列,list集合可以看成是一个左右排列的队列(列表)

list控制同一边进,同一边出就是栈【先进后出FILO】==实现栈

list控制一边进,另一边出就是队列【先进先出FIFO】==实现队列

为什么要对Rdis实现淘汰策略?

Redis是将数据存储到内存当中的,Redis虽然快,但是内存成本还是比较高的,而且基于内存Redis不适合存储太大量的数据。Redis可以使用1电脑物理最大内存,当然我们通常会通过设置maxmemory**参数限制Redis内存的使用, 为了让有限的内存空间存储更多的有效数据,2我们可以设置淘汰策略,让Redis自动淘汰那些老旧的,或者不怎么被使用的数据**,3我们可以使用Redis集群

Redis的key加一个过期时间,原生的操作命令是什么?

redis的数据结构

不是原生的opsForValue().set (键,值,时间,单位)

redisTemplate.opsForValue().set(SeckillKey, reduceStoreCount, redisEndTime, TimeUnit.MILLISECONDS);

**设置10秒过期**

expire key 10

**设置redis永不过期**

**PERSIST** 命令用于移除给定 key 的过期时间,**使得 key 永不过期**。

**TTL** 命令以秒为单位返回 key 的剩余过期时间。

Redis事务和Mysql事务的区别?

事务的四大特性(ACID):原子性Atomicity 一致性Consistency 隔离性Isolation 持久性Durability

原子性:事务是操作数据库的最小执行单元,只允许出现两种状态,只能同时成功,或者同时失败。

持久性:一旦提交事务【不能回滚】,将数据进行持久化到磁盘中,保证数据不会丢失

隔离性:【事务之间互不影响】两个事务修改同一个数据,必须按顺序执行,并且前一个事务如果未完成,那么中间状态对另一个事务不可见

一致性:【事务执行前后都必须保证数据的总和是一致的】要求任何写到数据库的数据都必须满足预先定义的规则,它基于其他三个特性实现的【【转账的前后金额是一致的,少100,那边就会多100】 】

Mysql的事务是基于日志(undolog和redolog日志),记录修改数据前后的状态来实现的,

而Redis的事务是基于队列实现的【Redis中事务不会回滚,就算后面的代码错误,前面的不会因此回滚】

Mysql中的事务满足原子性:即一组操作要么同时成功,要么同时失败,

Redis中的事务不满足原子性,即一组操作中某些命令执行失败了,其他操作不会回滚

因此对于比较重要的数据,应该存放在mysql中

使用Redis如何实现消息广播?

里面有代码。

spring boot redis 广播消息_FlyingKiss007的博客-CSDN博客_redis 广播消息

理论:

Redis是使用发布和订阅来实现广播的

订阅者通过 SUBSCRIBE channel命令订阅某个频道 , 发布者通过 PUBLISH channel message向该频道发布消息,该频道的所有订阅者都可以收到消息。

为什么要使用Redis做缓存?

主要是读取数据快。Redis是将数据存储到缓存当中,客户端可以直接从缓存中获取数据,避免去数据库中进行获取数据,提高了查询性能**。

我们一般会将经常查询的热点数据,不会经常改变的热点数据,保存到缓存中,提高响应速度,从而提高用户的体验度。

缓存的执行流程?

1.客户端发起查询请求

2.判断缓存中是否有数据

如果有,直接返回

如果没有,就从数据库查询,再把数据同步到缓存

3.返回数据给客户端

你们怎么保证Redis和Mysql的数据一致性?

如果是对数据进行查询,首先会去缓存中进行查询,如果有就直接返回数据给客户端,如果没有我们就会去数据库进行查询,然后将数据返回给客户端,并且将数据同步到缓存中。

如果是对数据库进行增删改操作时,会在执行完增删改过后,将Redis中的缓存数据进行删除,然后下一次查询数据就去数据库进行查询,将最新的数据同步到缓存中。但是有一个极端问题就是在增删改成功过后,准备去删除Redis中的缓存数据代码之间,如果有查询请求依然会查询到Redis中的老数据,但是这种情况非常极端,而且我们的业务也能容忍这种短暂的脏数据【无效的数据--这些数据没有很大的影响--比如点赞数,浏览量】。

如何解决这个问题呢?保证增删改方法和删除Redis中缓存数据方法的原子性即可,将两行代码变成一行代码,要么都成功,要么都失败。还有就是通过延迟双删,和使用阿里的canal组件监听Mysql事务日志自动同步Redis等

延迟双删:指的是在删除缓存前,其他事务更新缓存的操作已经执行完成。

自己的想法:要保证增删改数据库数据要和Redis的一致性,从而可以在增删改方法和删除redis缓存方法入手,保证原子性即可,就是删除这段时间,其他线程不能进行增删改,就是采用加锁的方式【锁住增删改方法和删除redis缓存的方法---效率很低,但是能够保证数据一致性。】

redis缓存为什么要延时双删_文盲青年的博客-CSDN博客_redis缓存双删

SpringCache常用注解

cache:缓存,evict:驱逐(删除)

springcache是基于注解的缓存技术。基于Redis的。

@EnableCaching:打在主启动类上,开启缓存功能

@Cacheable:【先查询缓存中是否有,有就直接返回,没有就去数据库进行查询,并同步到缓存中】

@CacheEvict:【执行目标方法过后,并删除缓存】

@CachePut:更新缓存(先调用目标方法修改数据库的数据,并更新缓存。)

@Caching:【组合多个注解进行使用】

@CacheConfig:【抽取类中的所有@CachePut@Cacheable@CacheEvict的公共配置】

了解Redis缓存击穿,穿透,雪崩吗?怎么处理?

详解请点击下面链接(看了必懂,)

https://blog.csdn.net/m0_64210833/article/details/126238375

缓存击穿:

指的是Redis中一个热点Key,在高并发的情况下,这个redis的缓存时间失效,

导致redis中这个热点key中大量的请求打到数据库上,导致数据库压力过大导致数据库崩了。

解决方案:加互斥锁,只能允许一个线程访问数据库,然后其他线程就可以在缓存中拿

缓存穿透:

用户访问的数据在Redis缓存中和数据库中都没有这样的数据,然后用户不断地使用脚本发送这个请求【数据库中的id是自增长从0开始的,没有负数】,这种数据直接穿透缓存,打到数据库上,导致数据库挂掉。

解决方案:布隆过滤器来判断数据库中有没有这个key

缓存雪崩:

就是大量的redis同一时间大面积的失效,大量的请求直接打到数据库上【导致数据库压力飙升】,这种现象就是缓存雪崩

解决方案:为key设置不同的过期时间

你们Redis用来做什么?使用的什么结构?

登录信息login,使用的是String结构存储

手机验证码code,使用的是String结构

课程分类course_type ,使用的是String结构

秒杀活动存储,使用的是Hash结构

数据字典等项目也是使用redis存储

权限数据也是使用redis存储

使用Zset进行排队

你们项目是如何做服务降级的?

比如在秒杀业务中,需要实时从redis中查询库存,通过设置hystrix的最大信号量,以此来防止redis雪崩。当并发过高,请求数超过最大信号量,触发降级,直接向客户端返回兜底数据:”活动太火爆啦,请骚后重试“

基于Redis实现的分布式锁?

实现分布式锁的三种方式+CAP理论(Interview)_GuGuBirdXXXX的博客-CSDN博客

Redis如何实现分布式锁,用什么命令?

可以使用setnx来加锁 ,但是需要设置锁的自动删除来防止死锁,所以要结合expire使用.为了保证setnx和expire两个命令的原子性,可以使用set命令组合。

// 返回值为1表示获取锁成功,返回值为0表示获取锁失败,已经有线程获取到锁了。

if(jedis.setnx(lock_stock,1) == 1){//获取锁

expire(lock_stock,5) //设置锁超时

try {

业务代码

} finally {

jedis.del(lock_stock) //释放锁

}

}

// 用来解决原子性问题,在设置锁过期时间之前出现异常,导致没有设置锁过期时间,出现死锁。

if(set(lock_stock,1,"NX","EX",5) == 1){//获取锁并设置超时

try {

业务代码

} finally {

del(lock_stock) //释放锁

}

}

项目中怎么使用分布式锁的?

自己封装Redis的分布式锁是很麻烦的,我们可以使用Redissoin来实现分布式锁,Redissoin已经封装好了Redis实现分布式锁的步骤。

使用场景:比如说订单支付成功和订单超时取消不能同时执行,必须等待前者或后者执行完成才能执行,就可以使用Redission的分布式锁。【再比如吃饭和拉便便的两个业务方法,只能一个先一个后,不然就会出现冲突,出现bug。】

Redission的看门狗原理?

Redisson对基于Redis实现分布式锁进行了封装,对于锁超时问题 【Redission在设置的过期时间以内还没有执行完对共享资源的操作,锁就过期了】,它提供了看门狗进行锁时间的续期,底层使用了定时任务每10s检查一下(Redission默认过期时间为30s),如果业务还未执行完成,未释放锁,就进行超时时间续期。

接口幂等一般怎么设计?(使用到了Redis)

接口的幂等性怎么设计?_Mark66890620的博客-CSDN博客_接口的幂等性怎么设计

接口幂等就是相同的条件参数调用同一个方法只会对数据库执行一次操作。

对于查删天然就是幂等的,对于添加我们为了防止重复进行添加,就需要使用一个唯一的标识,来进行判断是否重复进行了添加,比如说我们项目中使用了防重token就是为了避免用户在下单页面点击两次下单,我们将token存储在Redis当中,当一次下单成功的时候,我们就会删除Redis,如果再次下单,Redis中没有token就会下单失败。

还有就是通过订单号【唯一标识】进行判断订单状态是否被修改,如果修改了,就不会进行重复修改了。为了防止并发操作,可以把判断逻辑放到synchronized代码块中。

信号量的作用?如果不用信号量,用什么?(加锁,存储到Redis,库存必须大于0)

我们项目中使用Redission的semaphore信号量用做库存,信号量可以保证库存的原子性,对库存进行加或减,不会出现负数。

将信号量存储到Redission当中就是为了避免每次都去数据库进行查询,导致数据库压力过大,存储到Redission当中,当用户点击秒杀的时候,会从Redission中进行查询是否还有库存,如果有的话就会扣减库存,创建订单号,写入Redission返回订单号给前端,前端拿着订单号确认订单。

秒杀为什么要Redis的存储结构hash?不用其他的存储方式?

在查询的时候需要查询单个商品和商品集合的,还有可能需要对商品进行修改,使用hash的好处就是直接通过key去获取单个或者集合。

其他的存储结构,查询单个都不是很方便,需要进行遍历查询,非常损耗性能,这时候使用hash直接使用key就可以进行获取。

查询单个商品使用get【redisTemplate.opsForHash().get】,

查询集合列表使用values【redisTemplate.opsForHash().values】。

Redis的设计模式【单节点模式、主从模式、哨兵模式、Clusting模式】

Redis四种部署模式(原理、优缺点及解决方案)_少年做自己的英雄的博客-CSDN博客_redis部署模式

一、单节点模式

总结归纳:只有一个主节点Master,简单但是会出现单点故障且不能高可用。

二、主从模式【主节点挂掉需要手动升级】

采用主从模式,提高了Redis的整体的可用性,当主节点(Master)挂掉,不会自动的将从节点(slave)升级成主节点进行继续提供服务。

主节点主要用于写操作,从节点只能用于读操作。当主节点挂掉之后,就不能对外界提供写操作了,就只能对外界提供读取的操作。需要运维进行一个及时的一个维护。【这时候就出现了哨兵模式】

解决了:主从模式解决了Redis的读取的压力,但不能解决写的压力,不能解决单点故障。

三、哨兵模式

哨兵模式的出现用于解决主从模式中无法自动升级主节点的问题,一个哨兵是一个节点,用于监控主从节点的健康,当主节点挂掉的时候,自动选择一个最优从节点升级为主节点【选举】。

但哨兵如果挂了怎么办?于是哨兵一般都会是一个集群,是集群高可用的心脏,一般由3-5个节点组成,即使个别节点挂了,集群还可以正常运行。

四、 Clusting集群模式

集群方案真正实现了Redis高可用。集群由多个Redis主从组成,每一个主从代表一个节点,每个节点负责一部分数据,他们之间通过一种特殊的二进制协议交互集群信息。从而解决了Redis写的压力。

什么情况下Redis集群不可用?

Redis Cluster有一个容错机制,如果半数以上的主节点与故障节点通信都超时了,就会认为该节点故障了,自动触发故障转移操作,故障节点对应的从节点升级为主节点。

但是如果某个主节点挂了,又没有从节点可以使用,那么整个Redis集群就不可用了、

Redis存储结构底层有没有了解?什么是SDS

简单动态字符串,是Redis自己封装的字符串结构。它记录了字节数组buf,字节数组中用到的字节数len,以及未使用的字节数free。

为了解决二进制安全问题,定义了len来表示已有字符串长度

为了防止缓冲区溢出,在分配内存的时候做了预留空间free

内存惰性释放,多余的内存加入free做预留,优化了内存频繁分配

针对不同的String长度定制了不同的SDS结构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值