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如何实现持久化?
| RDB | AOF | |
| 持久化方式 | 定时对整个内存做快照 | 记录每一次执行的命令 |
| 数据完整性 | 不完整,两次备份之间会丢失 | 相对完整,取决于刷盘策略 |
| 文件大小 | 会有压缩,文件体积小 | 记录命令,文件体积很大 |
| 宕机恢复速度 | 很快 | 慢 |
| 数据恢复优先级 | 低,因为数据完整性不如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的数据过期策略?
- 惰性删除:使用key时才检查其是否过期,如果过期,就删掉它,反之,返回该key。长期不删除占用内存空间。
- 定期删除:隔一段时间,对一些key进行检查,删除里面过期的key(从一定量的数据库中取出一定量的随机key进行检查,并删除其中的过期key)。有SLOW(定时任务)和FAST(执行频率不固定)两种模式。难以确定删除操作执行的时长和频率。
- 实际执行时往往是两种策略配合使用。
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实例的一半)
哨兵选主规则:
- 首先判断主与从节点断开时间长短,如超过指定值就排除该从节点;
- 然后判断从节点的slave-priority值,越小优先级越高;
- 如果slave-priority值一样,则判断slave节点的offset值,越大优先级越高;(说明从主节点那里同步的数据最大,越接近主节点的数据)
- 最后是判断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之后,为了提升更好的性能,使用了多线程来处理回复事件)、命令请求处理器,在命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程。
173万+

被折叠的 条评论
为什么被折叠?



