Redis整理

1.哪些场景使用redis?(结合项目回答)

缓存、分布式锁、消息队列和延迟队列等。

2.缓存穿透定义与解决?

缓存穿透:查询一个不存在的数据,mysql查询不到数据也不会写入到缓存,就会导致每次请求都查询数据库。

解决方法一:缓存空数据,查到数据为空也进行缓存,可以设置几十秒的过期时间,优点是简单,缺点是消耗内存,可能产生数据不一致问题。

解决方法二:添加布隆过滤器,在进行缓存预热时,预热布隆过滤器,发送请求时先查询布隆过滤器,若为空,则直接返回,否则再进行后续查询。优点是使用bitmap实现,内存占用较少,没有使用多余key,缺点则是实现复杂,会有一定的误判率。

3.缓存击穿定义与解决?

缓存击穿:给一个热点key设置了过期时间,当其失效时,恰好有大量的并发请求过来,这些请求很可能把数据库压垮。

解决方式一:添加互斥锁,其他未获取到互斥锁的线程只能等待,保证了数据的强一致性,但是性能较差。

解决方法二:设置逻辑过期时间,线程1发现逻辑时间过期,获取互斥锁开启新线程进行缓存重建,其他线程获取互斥锁失败,不用等待,直接返回原数据,高可用,性能高,但不能保证数据绝对一致。

4.缓存雪崩定义与解决?

缓存雪崩:指在同一时间大量的缓存key同时失效或者redis服务宕机,导致大量请求到达数据库。

解决方式:给不同的key的TTL添加随机值,利用redis集群提高服务的可用性(哨兵模式,集群模式),给缓存业务添加降级限流策略,给业务添加多级缓存(Guava或者Caffine)。

5.Redis和MySql的双写一致性?

双写一致性:当修改了数据库的数据也要同时更新缓存的数据,两者要保持一致。

读操作:缓存命中,直接返回。缓存未命中,查询数据库,写入缓存,设置过期时间。

写操作:延迟双删。

强一致的场景:可以使用Redisson的读写锁来保证数据的同步

高可用的场景:可以使用异步的方式,比如MQ,更新数据之后,通知缓存删除。或者Canal中间件,不需要修改业务代码,伪装mysql的一个从节点,canal通过读取binlog数据更新缓存。

6.Redis如何实现持久化?

RDBAOF
持久化方式定时对整个内存做快照记录每一次执行的命令
数据完整性不完整,两次备份之间会丢失相对完整,取决于刷盘策略
文件大小会有压缩,文件体积小记录命令,文件体积很大
宕机恢复速度很快  慢
数据恢复优先级低,因为数据完整性不如AOF高,因为数据完整性更高
系统资源占用高,大量CPU和内存消耗低,主要是磁盘IO资源,但AOF重写时会占用大量资源
使用场景可以容忍数分钟的数据丢失,追求更快的启动速度对数据安全性要求较高常见

redis4.0提出了混合持久化,即混合使用AOF日志和内存快照;当开启混合持久化时,在重写AOF日志时,fork出来的重写子进程会先将与主线程共享的内存数据以RDB方式写入到AOF文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以AOF方式写入到AOF文件,写入完成后通知主进程将新的含有RDB格式和AOF格式的AOF文件替换旧的AOF文件。也就是说,AOF文件的前半部分是RDB格式的全量数据,后半部分是AOF格式的增量数据;

  • 混合持久化的优点:(1)结合了RDB和AOF持久化的优点,开头为RDB的格式,使得Redis可以更快的启动,同时结合AOF的优点,降低了大量数据丢失的风险;
  • 混合持久化缺点:(1)AOF文件中添加了RDB格式的内容,使得AOF文件的可读性变得很差;(2)兼容性差,如果开启混合持久化,那么此混合持久化AOF文件,就不能用在Redis4.0之前的版本了;

 7.Redis的数据过期策略?

  1. 惰性删除:使用key时才检查其是否过期,如果过期,就删掉它,反之,返回该key。长期不删除占用内存空间。
  2. 定期删除:隔一段时间,对一些key进行检查,删除里面过期的key(从一定量的数据库中取出一定量的随机key进行检查,并删除其中的过期key)。有SLOW(定时任务)和FAST(执行频率不固定)两种模式。难以确定删除操作执行的时长和频率。
  3. 实际执行时往往是两种策略配合使用。

8.Redis的数据淘汰策略

有8种数据淘汰策略,大致可分为面向全部key的和面向设置了过期时间key的。其中LRU(Least Recently Used)和LFU(Least Frequently Used)两种是重点。前者使用当前时间减去最后一次访问时间,值越大,淘汰优先级越高。后者会计算每个key的访问频率,越小的淘汰优先级越高。

9.Redis的分布式锁策略?

使用redisson提供的分布式锁,底层使用的是setnx命令配合lua脚本(可以保证命令执行原子性)。代码层面:tryLock通过看门狗机制给持有锁的线程续期,默认每隔10秒续期一次。当持有锁的线程所在的服务器宕机。其他线程访问时会获取锁失败并进入while循环,设置了一定的循环次数避免死锁情况。redisson的分布式锁可以重入,多个锁重入需要先判断是否是在同一线程中,在redis中存储时采用的是hash结构,来存储线程的唯一标识和重入的次数。通过次数的加减来记录重入次数。无法解决主从数据一致的问题。可以加红锁,但是性能较低,非要保证数据的强一致性,建议使用zookeeper实现的分布式锁。

10.Redis集群有哪些方案?

方案总共有三种:主从复制、哨兵模式、分片集群。

主从同步

        单节点的Redis并发能力是有上限的,要进一步提高并发能力,就要搭建主从集群,实现读写分离。一般都是一主多从,主节点负责写数据,从节点负责读数据。

        主从同步的流程:

(1)全量同步

        1.从节点请求主节点同步数据(replication Id ,offset)

        2.主节点判断是否是第一次请求,是第一次就与从节点同步版本信息(通过Replication Id判断,Id不一致就说明是第一次同步)

        3.主节点执行bgSave生成RDB文件发送给从节点去执行。

        4.在RDB生成和发送的这段时间收到的更新请求,主节点会记录到日志中。

        5.把生成的日志文件也发送给从节点进行同步。

(2)增量同步

        1.从节点像主节点请求同步数据,通过replicationId判断是否是第一次同步,如果不是则获取从节点的offset值。

        2.主节点从命令日志中获取offset值之后的数据,然后发送给从节点进行同步。

哨兵模式

1.哨兵(sentinel)机制实现主从集群的自动故障恢复,满足高可用。

2.作用:

        (1):监控:sentinel会不断检查master和slave是否按预期工作。

具体流程:sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令,判断实例是否下线。

主观下线:如果某个sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。

客观下线:如果超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线(这里的数量最好设置成超过sentinel实例的一半)

哨兵选主规则:

  1. 首先判断主与从节点断开时间长短,如超过指定值就排除该从节点;
  2. 然后判断从节点的slave-priority值,越小优先级越高;
  3. 如果slave-priority值一样,则判断slave节点的offset值,越大优先级越高;(说明从主节点那里同步的数据最大,越接近主节点的数据)
  4. 最后是判断slave节点的运行id大小,越小优先级越高。(越小说明启动时间越早,记录的消息更多)

        (2):自动故障恢复:如果master故障,sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主。

        (3):通知:sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新消息推送给Redis的客户端。

3.集群脑裂

解释:由于redis master节点和redis slave节点和sentinel处于不同的网络分区,使得sentinel没有能够心跳感知到master,所以通过选举的方式提升了一个slave为master,这样就存在了两个master,就像大脑分裂了一样。这样会导致客户端还在old master那里写入数据,新节点无法同步数据,当网络恢复后,sentinel会将old master降为slave,这时再从新master同步数据,这会导致old master中的大量数据丢失。

解决方式:可以修改redis的配置,第一可以设置最小的slave节点格式,比如设置至少有一个slave节点才能同步数据,第二个可以设置主从数据复制和同步的延迟时间,达不到要求就拒绝请求,这样就可以避免大量的数据丢失。

分片集群

redis的分片集群有什么作用?

1.集群中有多个master,每个master保存不同数据;

2.每个master都可以有多个slave节点

3.每个master之间通过ping检测彼此健康状态

4.客户端请求可以访问集群任意节点,最终都会被转发到正确节点

redis分片集群中数据是怎么存储和读取的?

1.redis分片集群引入了哈希槽的概念,redis集群有16384个哈希槽。

2.将16384个插槽分配到不同的实例。

3.读写数据:根据key的有效部分计算哈希值,对16384取余(有效部分,如果key前面有大括号,那么大括号中的内容是有效部分,否则,key本身作为有效部分)余数作为插槽,寻找插槽所在的实例。

11.Redis是单线程的,为什么那么快?

1.Redis是纯内存操作,执行速度非常快;

2.采用单线程,避免不必要的上下文切换和竞争条件,避免了死锁问题,多线程还要考虑线程安全问题;

3.使用I/O多路复用模型,非阻塞IO;

能否解释一下IO多路复用模型?

Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,I/O多路复用模型主要就是实现了高效的网络请求。

1.I/O多路复用

是指利用单个线程来同时监听多个socket,并在某个socket可读,可写时得到通知,从而避免无效的等待,充分利用CPU资源。目前的I/O多路复用都是采用epoll模式实现,它会通知用户进程socket就绪的同时,把已就绪的socket写入用户空间,不需要挨个遍历socket来判断是否就绪,提升了性能。

2.Redis网络模型

就是使用I/O多路复用结合事件的处理器来应对多个Socket请求。包括连接应答处理器、命令回复处理器(Redis6.0之后,为了提升更好的性能,使用了多线程来处理回复事件)、命令请求处理器,在命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值