Redis常见面试题

怎么理解Redis中事务?

redis中的事务是弱事务。

使用multi命令开启事务,使用exec提交事务,redis不支持事务回滚。

为什么要使用pipeline

这玩意是管道的意思,就是说将一组redis命令通过管道发送给redis服务端,执行完成后再一起返回。相较于一条一条的发送执行返回结果,提高了效率。

Redis的过期策略以及内存淘汰机制?

redis的过期策略采用的是定期删除 + 惰性删除。

redis会每100ms进行一次扫描,看看是否有过期的key,有过期key则删除。需要说明的是,redis不是每隔100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。 于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

内存淘汰策略:就是redis在内存快满的时候,根据一定的策略主动删除一些键值对,以释放内存空间并保持系统的稳定性。

1.noeviction(不淘汰策略): 当内存不足以容纳新写入数据时,redis将新写入的命令返回错误。这个策略确保数据的完整性,但会导致写入操作失败。

2.allkeys-lru(最近最少使用): 尝试删除最少使用的键(LRU),使得新添加的数据有空间存放。

3.volatile-lru(最近最少使用): 从设置了过期时间的键中选择最少使用的键进行删除。该策略优先删除最久未被访问的键,保留最常用的键。

4.allkeys-random: 回收随机的键使得新添加的数据有空间存放。

5.volatile-random(随机删除): 从设置了过期时间的key中随机选择一个进行删除

6.volatile-ttl(根据过期时间优先): 从设置了过期时间的key中选择剩余时间最短的key进行删除。该策略优先删除剩余时间较短的key,以尽量保留剩余时间更长的key.

什么是缓存穿透?如何避免?

缓存穿透:指查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到 DB 去查询,可能导致 DB 挂掉。

解决方案:1.查询返回的数据为空,仍把这个空结果进行缓存,但过期时间会比较短;2.布隆过滤器:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对 DB 的查询。

什么是缓存雪崩?如何避免?

缓存雪崩:设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到 DB,DB 瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多 key,击穿是某一个key 缓存。

解决方案:将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

Redis如何解决key冲突?

遇到hash冲突采用链表进行处理

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

rdb文件比较小,保存的是一个内存快照,但是容易丢失数据。

aof文件比较大,持久化的速度比较慢。但是不容易丢失数据。

如何保证缓存与数据库双写时的数据一致性

第一种方案:采用延时双删策略

具体的步骤就是:

先删除缓存;

再写数据库;

休眠500毫秒(但是休眠多长时间不好把控);

再次删除缓存。

第二种方案:异步更新缓存(基于订阅binlog的同步机制)

技术整体思路:

MySQL binlog增量订阅消费+消息队列+增量数据更新到redis

Cache Aside Pattern(旁路缓存模式):对于写请求,先更新数据库,再删除缓存。

Redis集群方案什么情况下会导致整个集群不可用?

1.当访问一个 Master 和 Slave 节点都挂了的槽的时候,会报槽无法获取。

2.当集群 Master 节点个数小于 3 个的时候,或者集群可用节点个数为偶数的时候,基于 fail 的这种选举机制的自动主从切换过程可能会不能正常工作,一个是标记 fail 的过程,一个是选举新的 master 的过程,都有可能异常。

什么是缓存击穿?如何避免?

缓存击穿:数据库中有,缓存中没有。缓存击穿实际就是一个并发问题,一般来说查询数据,先查询缓存,有直接返回,没有再查询数据库并放到缓存中之后返回,但这种场景在并发情况下就会有问题,假设同时又100个请求执行上面

逻辑的代码,则可能会出现多个请求都查询数据库,因为大家同时执行,都查到了缓存中没有数据。

解决方案:加锁。如果是单机部署,则可以使用JVM级别的锁,如lock、synchronized。如果是集群部署,则需要使用分布式锁,如基于redis、zookeeper、mysql等实现的分布式锁。

五种基本数据类型的使用场景

https://blog.csdn.net/qq_32534855/article/details/105515146

redis的持久化方式

rdb持久化:在指定的时间间隔内将内存中的数据集快照写入磁盘(以二进制序列化的形式),每次都是从redis中生成一个快照进行数据的全量备份。速度比较快。但是可能会丢失指定时间间隔内的数据。
aof持久化机制:对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放aof日志中的写入指令来重新构建整个数据集。效率不如rdb快,但是最多丢失1s内的数据。

基于Redis、ZooKeeper、数据库实现分布式锁的优缺点

使用分布式锁的目的,是为了保证同一时间只有一个 JVM 进程可以对共享资源进行操作。

基于数据库实现分布式锁:

这种方式实现简单,易于控制,能轻松处理一些容易发生死锁或竞争问题。

但是由于数据库锁会引起严重的性能瓶颈,特别是当锁的数量比较大的时候,会导致系统性能的下降。

基于redis实现分布式锁:

这种方式使用redis提供了高效的获取锁和释放锁的操作,不需要像使用数据库那样频繁的读写数据库,使用起来非常高效。

redisson中有一个看门狗的机制,它会在你获取锁之后,每隔 10 秒帮你把 key 的超时时间设为 30s,就算一直持有锁也不会出现 key 过期了。“看门狗”的逻辑保证了没有死锁发生。

但是,redis获取锁的方式简单粗暴,如果获取不到锁,会不断尝试获取锁,比较消耗性能。redis提供的是基于内存的缓存机制,如果redis服务器负载过重或内存不足,可能会导致获取锁和释放锁的操作变得缓慢,从而影响系统的性能。redis比较适合高并发场景。

基于zookeeper实现分布式锁:

zookeeper天生定位就是分布式协调,强一致性。如果获取不到锁,可以添加一个监听器,不用一直轮询阻塞,性能消耗比较小。

这种方式可以很好的解决数据库锁引起的性能瓶颈问题,因为zookeeper提供了高效的死锁检测和解决机制。

但是zookeeper不适合做大规模的分布式系统,因为它需要维护大量的状态信息。

Cache Aside

首先,先说一下,这是一个老外提出的缓存更新套路,写了一本书《Cache Aside pattern》。其中就指出:
失效:应用程序先从 缓存 中获取数据。如果没有找到,则从数据库中读取数据,然后再放到缓存中。
命中:应用程序从 缓存中 获取到数据,直接返回。
更新:先把数据存到数据库中。成功后,再让缓存失效。
image

这件事情会发生,那么发生的概率多大呢?
发生上述情况有一个先天性条件:
1.读操作时,缓存中无数据,这样它才会去数据提供方取数据。
2.读操作进行的同时,存在一个写操作。
3.读操作在数据提供方中读取数据的时长大于写操作。这个就很难了。
4.在读写操作并发时,读取到的是旧日值,算是一半一半的概率吧。
就一条,读操作正常情况下,比写操作快很多,所以上述4条同时满足的概率是极低的
(PS:就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。

可是,大家想想,数据库的读操作的速度远快于写操作的(不然做读写分离干嘛,做读写分离的意义就是因为读操作比较快,耗资源少),因此步骤(3)耗时比步(2)更短,这一情形很难出现。
PS:如果真的出现写操作比读操作快的话,那么我们可以采用延迟双删的策略来解决,当然这只能是缓解。

Cache aside 机,制是一种 简单有效的缓存更新机制,应用非常广泛,所以叫做cache aside,缓存在边上。就是说以数据库为主,写完有空再处理边上的 缓存。

Read/Write Through Pattern [读写穿透]

在Cache Aside中,有概率虽然很低出现数据不一致的情况,我们也用了延迟双制,但还是比较复杂。但要想避免缓存不一致的出现也很简单即进行写入操作时,直接将结果写入缓存,而再从缓存同步写入到数据提供广写入数据提供方操作结束后,写入操作才被返回。
这就是Read/Write Through写入机制。
在这种机制下,调用方只需要和缓存打交道,而不需要关心缓存后方的数据提供方。而由缓存来保证自身数据和数据提供方的一致性。
结论:读操作只和缓存打交道,直接读取缓存的结果;写操作的话,调用方写入缓存,再由缓存同步写入数据提供方。(PS:说白了读写只和缓存打交道了


和Cache-Aside的区别?
在Cache Aside机制中,数据写入缓存的操作,是由调用方的查询结果触发的,
而在Read/write through 机制中,则需要缓存在启动时,自身完成将所有数据从数据提供方读入缓存的过程(在项目启动的时候,其实初始化什么也没有,也没有什么需要读取的,一会有修改,缓存就是新的数据,也不用读)。
比较一下Cache Aside和Read/write through机制。在Cache aside中,缓存只是一个辅助的存在,即使缓存不工作,调用方也可以通过数据提供方完成所有的读写操作,正如其名,缓存在边上,像胯子。
而在Read/write through中,缓存直接对接了调用方,屏蔽了数据提供方,这就意味着缓存系统不可或缺,要求缓存十分可靠

posted on 2024-09-12 11:14  ~码铃薯~  阅读(3)  评论(0编辑  收藏  举报

导航