Redis:是一种高性能的,开源的,C语言编写的Nosql【非关系型数据库的泛指(没有以关系模型创建的数据库)】--不保证数据的ACID特性【事务一旦提交,都不会进行回滚】
采用键值对存储数据在内存或磁盘中,可以对关系型数据库起到补充作用,同时支持持久化[可以将数据保存在可掉电设备中],可以将数据同步保存到磁盘
说Redis很快是相对于关系型数据库如mysql来说的,主要有以下因素
-
第一,数据结构简单,所以速度快【采用键值对的方式】
-
第二,直接在内存中读写数据,所以速度快
-
第三,采用多路IO复用模型,减少网络IO的时间消耗,避免大量的无用操作,所以速度快
-
第四,单线程避免了线程切换和上下文切换产生的消耗,所以速度快
Mysql:关系型数据库--保证数据的ACID特性【事务的四大特性】
【以关系模型创建的数据库--(行和列组成的二维表)】,简单理解:有二维表的数据库。【数据保存在磁盘中-持久化(可以保存在可掉电设备当中)】
2Redis的5种数据存储结构+使用场景Redis是典型的key-value类型数据库,key为字符类型,value形式包括String,List,Set,ZSet,Hash。
Redis 在互联网产品中使用的场景实在是太多太多,这里分别对 Redis 几种数据类型做了整理:
1)String字符串:缓存(存储图片验证码和手机验证码)、计数器等。
2)Hash散列表:秒杀活动(可以存储单个对象也可以存储一个集合对象),用户信息、用户主页访问量、组合查询等。Map
3)List列表:做队列,秒杀(排队,FIFO)。
4)Set集合:抽奖小程序(不能重复参与抽奖),点赞和收藏(不能重复进行点赞)。【不能存储重复的数据,底层存储使用的是map的key进行存储数据】
5)ZSet有序集合:排行榜(可以根据某个字段进行排序)。
3你们项目是怎么用Redis的?使用的是Springboot整合的redis,我们项目中主要使用Redis来存储注册时候的图形验证码和手机验证码,还有使用redis存储黑名单列表,还有用Redis的Hash存储结构来存储秒杀活动和秒杀课程,主要是因为Redis是采用键值对的方式将数据存储在内存当中,我们对数据进行查询的时候直接从内存当中获取,减少去数据库进行查询,从而降低数据库的压力,并且提高了查询效率。
4redis为什么进行持久化?redis作为缓存时, 把后端数据库中的数据存储在内存中, 这样读取数据的速度非常快, 但是一旦服务器宕机,内存中的数据将全部丢失,
因此需要将缓存中数据进行持久化, 通常持久化的方式有两种, AOF日志和RDB快照
5Redis如何解决高并发?Redis采用主从集群的方式,实现读写分离,主节点(主服务器负责写入数据),并将数据同步给其他从节点,从节点负责读取,从而解决高并发。
6怎么防止Redis宕机数据丢失问题?通过对Redis持久化机制,把内存中的数据和命令备份到磁盘中,当Redis发生宕机,重启服务器的时候,会从磁盘重新加载备份的数据,从而解决数据丢失问题
7Redis持久化机制是什么?有几种方式?Redis持久化机制就是将内存中的数据 备份到磁盘的过程,就叫作持久化,【数据可保存在可掉电设备当中】
Redis持久化机制主要有两种方式,
RDB快照【Redis DataBase】和AOF日志【Append Only File】
RDB快照【Redis DataBase--记录数据快照】:在指定的时间间隔内将内存中的数据集**快照【不稳定】写入到磁盘中。
AOF日志【Append Only File--记录写命令的】:将所有对数据库进行写入的命令(及其参数)记录到AOF文件中。将Reids的操作日志以 追加的方式写入文件。
以 日志 的形式记录服务器所处理的每一次写、删除的操作,不会记录查询的操作,以文本的形式记录,当服务器重启的时候会重新执行这些命令来恢复原始的数据【采用系统执行命令成功才会被记录到日志中。可以避免记录错误命令的情况。】
8RDB和AOF的差别?【结合使用,各有所长】1 AOF数据更加安全【三种同步策略,每秒同步,每修改同步,不同步】,保存在磁盘中,而RDB不能保证数据库数据百分百不丢失,因为它是每隔一定时间保存一次(即满足save机制才进行持久化)。
2 AOF文件比RDB文件大,启动恢复速度慢,体积相对较小,启动恢复速度快**。**
3 数据量大的时候,AOF启动效率更低
AOF比RDB更新效率高,优先使用AOF还原数据,AOF比RDB更安全也更大,RDB性能比AOF号,如果两者都配了,优先加载AOF
10Redis内存满了不够了怎么办?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进行存储数据。【还可以解决高并发问题】
11你们Redis用在哪些业务上?用的什么存储结构?使用的是Springboot整合的redis,我们项目中主要使用Redis来存储注册时候的图形验证码和手机验证码,还有使用redis存储黑名单列表,还有用Redis的Hash存储结构来存储秒杀活动和秒杀课程,主要是因为Redis是采用键值对的方式将数据存储在内存当中,我们对数据进行查询的时候直接从内存当中获取,减少去数据库进行查询,从而降低数据库的压力,并且提高了查询效率。
12Redis怎么实现栈和队列?Redis是使用list可以实现栈和队列,list集合可以看成是一个左右排列的队列(列表)
list控制同一边进,同一边出就是栈【先进后出FILO】==实现栈
list控制一边进,另一边出就是队列【先进先出FIFO】==实现队列
13为什么要对Rdis实现淘汰策略?Redis是将数据存储到内存当中的,Redis虽然快,但是内存成本还是比较高的,而且基于内存Redis不适合存储太大量的数据。Redis可以使用1电脑物理最大内存,当然我们通常会通过设置maxmemory**参数限制Redis内存的使用, 为了让有限的内存空间存储更多的有效数据,2我们可以设置淘汰策略,让Redis自动淘汰那些老旧的,或者不怎么被使用的数据**,3我们可以使用Redis集群
14Redis事务和Mysql事务的区别?事务的四大特性(ACID):原子性Atomicity 一致性Consistency 隔离性Isolation 持久性Durability
原子性:事务是操作数据库的最小执行单元,只允许出现两种状态,只能同时成功,或者同时失败。
持久性:一旦提交事务【不能回滚】,将数据进行持久化到磁盘中,保证数据不会丢失
隔离性:【事务之间互不影响】两个事务修改同一个数据,必须按顺序执行,并且前一个事务如果未完成,那么中间状态对另一个事务不可见
一致性:【事务执行前后都必须保证数据的总和是一致的】要求任何写到数据库的数据都必须满足预先定义的规则,它基于其他三个特性实现的【【转账的前后金额是一致的,少100,那边就会多100】 】
Mysql的事务是基于日志(undolog和redolog日志),记录修改数据前后的状态来实现的,
而Redis的事务是基于队列实现的【Redis中事务不会回滚**,就算后面的代码错误,前面的不会因此回滚】
Mysql中的事务满足原子性:即一组操作要么同时成功,要么同时失败,
Redis中的事务不满足原子性,即一组操作中某些命令执行失败了,其他操作不会回滚
因此对于比较重要的数据,应该存放在mysql中
15使用Redis如何实现消息广播?Redis是使用发布和订阅来实现广播的
订阅者通过 SUBSCRIBE channel命令订阅某个频道 , 发布者通过 PUBLISH channel message向该频道发布消息,该频道的所有订阅者都可以收到消息
16为什么要使用Redis做缓存?主要是读取数据快。Redis是将数据存储到缓存当中,客户端可以直接从缓存中获取数据,避免去数据库中进行获取数据,提高了查询性能**。
我们一般会将经常查询的热点数据,不会经常改变的热点数据,保存到缓存中,提高响应速度,从而提高用户的体验度。
17缓存的执行流程?1.客户端发起查询请求
2.判断缓存中是否有数据
-
如果有,直接返回
-
如果没有,就从数据库查询,再把数据同步到缓存
3.返回数据给客户端
18你们怎么保证Redis和Mysql的数据一致性?如果是对数据进行查询,首先会去缓存中进行查询,如果有就直接返回数据给客户端,如果没有我们就会去数据库进行查询,然后将数据返回给客户端,并且将数据同步到缓存中。
如果是对数据库进行增删改操作时,会在执行完增删改过后,将Redis中的缓存数据进行删除,然后下一次查询数据就去数据库进行查询,将最新的数据同步到缓存中。但是有一个极端问题就是在增删改成功过后,准备去删除Redis中的缓存数据代码之间,如果有查询请求依然会查询到Redis中的老数据,但是这种情况非常极端,而且我们的业务也能容忍这种短暂的脏数据【无效的数据--这些数据没有很大的影响--比如点赞数,浏览量】。
如何解决这个问题呢?保证增删改方法和删除Redis中缓存数据方法的原子性即可,将两行代码变成一行代码,要么都成功,要么都失败。还有就是通过延迟双删,和使用阿里的canal组件监听Mysql事务日志自动同步Redis等
延迟双删:指的是在删除缓存前,其他事务更新缓存的操作已经执行完成。
redis缓存为什么要延时双删_文盲青年的博客-CSDN博客_redis缓存双删
19SpringCache常用注解cache:缓存,evict:驱逐(删除)
springcache是基于注解的缓存技术。基于Redis的。
@EnableCaching:打在主启动类上,开启缓存功能
@Cacheable:【先查询缓存中是否有,有就直接返回,没有就去数据库进行查询,并同步到缓存中】
@CacheEvict:【执行目标方法过后,并删除缓存】
@CachePut:更新缓存(先调用目标方法修改数据库的数据,并更新缓存。)
@Caching:【组合多个注解进行使用】
@CacheConfig:【抽取类中的所有@CachePut@Cacheable@CacheEvict的公共配置】
20了解Redis缓存击穿,穿透,雪崩吗?怎么处理?详解请点击下面链接(看了必懂,)
https://blog.csdn.net/m0_64210833/article/details/126238375
缓存击穿:
指的是Redis中一个热点Key,在高并发的情况下,这个redis的缓存时间失效,
导致redis中这个热点key中大量的请求打到数据库上,导致数据库压力过大导致数据库崩了。
-
解决方案:加互斥锁,只能允许一个线程访问数据库,然后其他线程就可以在缓存中拿
缓存穿透:
用户访问的数据在Redis缓存中和数据库中都没有这样的数据,然后用户不断地使用脚本发送这个请求【数据库中的id是自增长从0开始的,没有负数】,这种数据直接穿透缓存,打到数据库上,导致数据库挂掉。
-
解决方案:布隆过滤器来判断数据库中有没有这个key
缓存雪崩:
就是大量的redis同一时间大面积的失效,大量的请求直接打到数据库上【导致数据库压力飙升】,这种现象就是缓存雪崩
-
解决方案:为key设置不同的过期时间
-
登录信息login,使用的是String结构存储
-
手机验证码code,使用的是String结构
-
课程分类course_type ,使用的是String结构
-
秒杀活动存储,使用的是Hash结构
-
数据字典等项目也是使用redis存储
-
权限数据也是使用redis存储
比如在秒杀业务中,需要实时从redis中查询库存,通过设置hystrix的最大信号量,以此来防止redis雪崩。当并发过高,请求数超过最大信号量,触发降级,直接向客户端返回兜底数据:”活动太火爆啦,请骚后重试“
23基于Redis实现的分布式锁?实现分布式锁的三种方式+CAP理论(Interview)_GuGuBirdXXXX的博客-CSDN博客
24Redis如何实现分布式锁,用什么命令?可以使用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) //释放锁 } }25项目中怎么使用分布式锁的?
自己封装Redis的分布式锁是很麻烦的,我们可以使用Redissoin来实现分布式锁,Redissoin已经封装好了Redis实现分布式锁的步骤。
26Redission的看门狗原理?Redisson对基于Redis实现分布式锁进行了封装,对于锁超时问题 【Redission在设置的过期时间以内还没有执行完对共享资源的操作,锁就过期了】,它提供了看门狗进行锁时间的续期,底层使用了定时任务每10s检查一下(Redission默认过期时间为30s),如果业务还未执行完成,未释放锁,就进行超时时间续期。
27接口幂等一般怎么设计?(使用到了Redis)接口的幂等性怎么设计?_Mark66890620的博客-CSDN博客_接口的幂等性怎么设计
接口幂等就是相同的条件参数调用同一个方法只会对数据库执行一次操作。
对于查删天然就是幂等的,对于添加我们为了防止重复进行添加,就需要使用一个唯一的标识,来进行判断是否重复进行了添加,比如说我们项目中使用了防重token就是为了避免用户在下单页面点击两次下单,我们将token存储在Redis当中,当一次下单成功的时候,我们就会删除Redis,如果再次下单,Redis中没有token就会下单失败。还有就是通过订单号进行判断订单状态是否被修改,如果修改了,就不会进行重复修改了。为了防止并发操作,可以把判断逻辑放到synchronized代码块中。
28信号量的作用?如果不用信号量,用什么?(加锁,存储到Redis,库存必须大于0)我们项目中使用Redission的semaphore信号量用做库存,信号量可以保证库存的原子性,对库存进行加或减,不会出现负数。
将信号量存储到Redission当中就是为了避免每次都去数据库进行查询,导致数据库压力过大,存储到Redission当中,当用户点击秒杀的时候,会从Redission中进行查询是否还有库存,如果有的话就会扣减库存,创建订单号,写入Redission返回订单号给前端,前端拿着订单号确认订单。
29秒杀为什么要Redis的存储结构hash?不用其他的存储方式?在查询的时候需要查询单个商品和商品集合的,还有可能需要对商品进行修改,使用hash的好处就是直接通过key去获取单个或者集合。
其他的存储结构,查询单个都不是很方便,需要进行遍历查询,非常损耗性能,这时候使用hash直接使用key就可以进行获取。
查询单个商品使用get【redisTemplate.opsForHash().get】,
查询集合列表使用values【redisTemplate.opsForHash().values】。