redis面试问题15

redis面试问题

缓存穿透
对数据库访问不存在的字段
解决方案一:使用redis将空值存储起来,缺点消耗内存,导致数据不一致
解决方案二:设置布隆过滤器,拒绝访问不存在的数据。

缓存击穿
给某一个Key设置了过期时间,当key过期时,恰好这时间点对key有大量的并发请求,这些请求处理的时间非常长,导致DB被压垮。
解决方案一:互斥锁,强一致,性能差 ,
所有setnex设置互斥锁
应用于金钱等重要数据
解决方案二:逻辑过期,高可用,性能优越,不能保证数据的绝对一致,
设置key的时候,设置一个过期时间段存入缓存 ,但不对key设置过期时间,查询的时候,从redis取出数据判断时间是否过期,过期则开通另一个线程进行同步,当前线程正常返回数据
应用于用户体验好的场景

缓存雪崩
指同一时间段大量的缓存key同时失效或Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

解决方案,给不同的Key的ttl添加随机值解决大量Key同时失效
利用Redis集群提高服务的可用性 哨兵模式,集群模式
给缓存业务添加降级限流策略(降级作为系统的保底策略,适用于穿透,击穿,雪崩) ngxin或spring cloud gateway
给业务添加多级缓存 Guava或Caffeine

双写一致性
要求数据为强一致性的方案
当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致
读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设置超时时间
写操作:延迟双删(根据数据库的主从特点,先删缓存,然后删数据库,然后延时删除缓存,结果可能存在脏数据)
或使用分布式锁,保持一致,
实际根据缓存中读多写少的特点,使用redisson中的读写锁,共享锁readLock读时所有线程都可以读,排他锁writeLock禁止其他线程读写。

(延时一致)能够接收延迟和数据的最终一致性的方案,采用异步通知
1.通过MQ中间件,更新数据后通知缓存删除。
2.基于Canal的异步通知 Canal监听mysql的binlog ,二进制日志BINLOG记录所有的DDL语句和DML语句,但不包括数据查询SELECT,SHOW语句。

持久化
数据的持久化使用的方式1.RDB,2AOF
1.RDB:全称Redis Database Backup file(Redis数据备份文件),也叫Redis数据快照,将内存中所有数据都记录在磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
Redis内部有自动储发的RDB机制,可以在redis.conf文件中找到

RDB执行原理
bgsave会fork主进程得到子进程,子进程共享主进程的内存数据,完成fork后读取内存数据写入RDB文件。fork采用的是copy-on-write技术:
fork复制页表,页表记录虚拟地址与物理地址的映射关系
1当主进程执行读操作时,访问共享内存。
2当主进程执行写操作时,拷贝一份数据,执行写操作。

AOF全称为Append Only File(追加文件),记录每一个redis处理命令
开启AOF功能 appendonly yes
AOF命令记录的频率通过redis.conf文件写
appendfsync always 同步刷盘,可靠性高,几乎不丢数据,缺点性能影响大
appendfsync everysec 每秒刷盘 性能适中 ,最多丢失1秒数据 。默认方案
appendfsync no 操作系统控制 性能最好 可靠性较差,可能丢失大量数据。

AOF记录的对同一个key的多次写操作中最后一个有效,通过bgrewriteaof命令,让AOF文件执行重写功能

Redis会在触发阈值自动重写AOF文件,域置配置
AOF文件比原文件增加超过多少百分比
auto-aof-rewrite-percentage 100
AOF文件体积最小多大才触发重写
auto-aof-rewrite-min-size 64mb

	RDB 		      	 AOF

持久化方式 定时快照 记录每一次执行的命令
数据完整性 不完整,两份备份间会丢失 相对完整,刷盘策略
文件大小 压缩文件,TJ小 记录命令,文件大
宕机恢复速度 快 慢
数据恢复优先级 低,数据完整性差 高,数据完整性高
系统资源占用 高,大量CPU和内存消耗 低,磁盘IO资源,但数据重写需要大量CPU和内存消耗
使用场景 容忍数分钟数据丢失,快速启动 数据安全要求高
实际开发中结合两者使用。

数据过期策略,
数据的有效时间过去后,从内存中将数据删除
实际上惰性删除和定期删除配合使用
堕性删除
设置的key过期后,需要该key时才检查其是否过期,过期就删除否则就返回。
优点:对CPU友好,不检查不用的Key
缺点:堆积一堆不用的key在内存中
定期删除
每隔一段时间,对数据库中的某些key进行检查,删除过期的key。
两种模式 slow,fast
slow是定时任务,执行频率默认10hz,每次不超过25ms,通过修改配置文件redis.conf的hz选项
fast模式执行频率不固定,两次间隔不低于2ms,每次耗时不超过1ms
限制删除操作能够减少对CPU线程的影响,定期删除也能释放过期key内存。缺点难以确定删除操作执行的时长和频率。

数据淘汰策略
缓存过多,内存是有限的,内存被占满了
数据淘汰策略,Redis中内存不够用时,向Redis添加新的key,Redis会按照某种规则将内存中的数据删除掉。
LRU(Least Recently Used)最近最少使用,当前时间减去最后一次访问时间,越久每使用的淘汰
LFU(Least Frequently Used)最少频率使用。统计key的使用频率,频率最小的被淘汰。
noeviction: 不淘汰任何key,内存满时不允许写入新数据,默认的策略
volatile-ttl: 对设置TTL的key,比较key的剩余TTL,TTL越小越先被淘汰
allkeys-random:对全体key,随机淘汰
volatile-random:对设置TTL的key,随机淘汰
allkeys-lru: 对全体key,基于LRU算法淘汰
volatile-lru: 对设置TTL的key,基于LRU算法淘汰
allkeys-lfu: 对全体key,基于LFU算法淘汰
volatile-lfu 对设置TTL的key,基于LFU算法淘汰。

如果没有明显的冷热数据区分,建议使用allkeys-lfu,充分利用LRU算法的优势,最常访问的数据留在缓存中
如果业务中数据的访问频率差不多,没有明显冷热数据区分,建议使用allkeys-random,随机选择淘汰
如果业务有置顶的需求,使用volatile-lru,置顶数据不设置过期时间,淘汰设置过期时间的数据。
如果业务中有短时高频访问的数据,使用allkeys-lfu或volatile-lfu策略。

volatile-lru:是常用的(结合业务场景。)

redis分布式锁
redis分布式锁,如何实现
分布式锁使用场景,集群情况下的定时任务,抢单,幂等情况。
集群情况中不能使用互斥锁解决抢单的超卖问题,互斥锁synchronized是部署在本地的限制一个GDM下的线程,不能限制负载均衡的多个服务器中的线程。
分布式锁能够限制负载均衡的多个服务器下的线程,避免超卖。

分布式锁:
原有锁,一个线程占据了资源后其他线程禁止使用,同时为了避免服务宕机等情况导致业务一直执行而锁不能释放,设计过期时间,到期后自动释放资源。如果释放资源后,业务还没有执行完成,使用自动续期来保障业务的完成。这就是分布式锁的优点,避免资源被占用,自动检测线程是否要续期。

线程一加锁后,获得Watch dog监控线程每隔一段时间增加时间直到业务完成,释放锁的时候Watch dog也就离开,其他线程在一段时间内会while循环获取锁,过期后会放弃获取锁,在高并发环境中其他线程不需要等待获取锁,效率更高。redisson命令中设置过期时间就没有Watch dog,默认会Watch dog(基于lua脚本完成,保障原子性)。

可重入
redisson实现的分布式锁,在同一个线程中是可重入的,应用于一些复杂的业务场景避免死锁。因为redisson利用hash结构记录线程id和重入次数。

主从一致性
当redis在某个实例创建锁了,但是宕机导致主节点挂了,将让某个子节点成为新主节点,这导致新的线程申请锁时有共有一把锁的概率,容易产生脏数据。
redis解决方法是使用RedLock(红锁),在多个rediss实例上创建锁(n/2+1),避免在一个rediss实例上创建锁。但是实现复杂,性能差,运维繁琐。主从不一致的情况少,一般不考虑。

因为redis根据AP思想,保障数据的最终一致性,如果要保障强一致性推荐使用zookeeperCP思想。

主从复制
单节点Redis的并发能力低,搭建主从集群,主节点master负责数据的写操作,从节点slave/replica负责读操作,主节点更新数据时将数据同步给所有的从节点,保障数据一致。但不能保障高可靠性,主节点宕机导致无法执行写操作。

主从全量同步操作
第一次同步通过Replication Id同步,以后同步通过offset进行偏量同步。
主master请求数据同步。根据replid对所有slave判断是同一个数据集。是的话返回master版本信息replid,offset,生成RDB文件传给slave,同时记录使用repl_baklog记录RDB期间的所有命令,发送repl_baklog到slave。slave第一次接收master同步时清空本地数据加载新RDB文件,执行repl_baklog命令,再次同步时根据offset只执行要更新的操作。

主从增量同步操作
从节点发送replid,offset请求同步,master判断是否是第一次同步,不是的话,根据offset偏移量将offset值后的数据发送给从节点。

Replication Id:简称replid,数据集的标识,每个master都有唯一的replid,slave会继承master节点的replid.
offset:偏移量,随着记录repl_baklog中的数据增多而变大,slave同步时会记录同步的offset,slave的offset小于master的offset,说明slave数据落后master,需要更新。

哨兵模式
(特点监控,自动故障恢复,通知)
监控 不断监测主从节点的状态,
自动故障恢复 主节点出问题就将某个从节点提升为主节点,故障恢复后以新master为主
通知 哨兵充当Redis客户端的服务发现来源,当集群发生故障转移时,最新信息推给Redis的客户端。

服务状态监控
Sentinel基于心跳机制监测服务状态,每隔1秒向集群每个实例发送ping命令,
某个Sentinel节点发现实例规定时间内未响应,认为主观下线
超过指定数量(quorum)的Sentinel都认为此实例主观下线,该实例客观下线。quorum默认比Sentinel实例的平均值大。

哨兵选主规则
1首先判断主从节点断开时间的长短,超过指定值就排除
2判断从节点的slave-priority值,越小优先级越高
3如果slave-priority一样,判断offset值,选offset值最大的(最重要)
4offset值一样,选则slave运行id,id越小优先级越高。

哨兵模式脑裂问题:
当网络故障时,主节点与从节点在不同的网络分区分开了,哨兵投票将某个从节点升为主节点,导致出现多个主节点,原有的主节点还在执行客户端的操作,新节点不能同步数据。当网络恢复后,原主节点自动变成从节点,与主节点同步导致数据丢失。解决办法,设置配置参数min-replicas-to-write 1 主节点最少的slave节点为1个,避免单独的主节点写入数据。min-replicas-max-lag 5 数据复制和同步的延迟不能超过5s,没有满足此条件就拒绝客户端的请求,避免大量数据丢失。

redis是单点还是集群,哪种集群
主从(1主1从)+哨兵。单节点不超过10G内存,如果Redis内存不足则给不同服务分配独立的Redis主从节点。

分片集群结构
主从和哨兵可以解决高可用,高并发读的问题,但是不能解决,海量数据存储问题,高并发写的问题。所以使用分片集群结构

方法,1集群中有多个master,每个master保存不同数据,高并发写和存储海量数据
2每个master都可以有多个slave节点,高并发读
3master间通过ping监测彼此健康状态,投票将有问题的master变成slave,和哨兵模式一样使故障自动恢复
4客户端对集群任意的节点的请求,会被路由到正确节点去

分片集群中数据读写的流程
Redis分片集群引入哈希槽的概念,Redis集群有16384个哈希槽,每个key有效部分(有效部分为key前有大括号的,如果没有大括号,key就是有效部分)进行CRC16校验,对16384取模决定哪个槽,集群的每个节点负责一部分hash槽。读取数据时,根据key校验后得到哈希槽位置,读取数据。

其他面试问题
Redis是单线程,为什么还那么快
1主要原因Redis是纯内存操作,执行速度非常快,
2采用单线程,避免不必要的上下文切换,多线程还要考虑线程安全
3使用I/O多路复用模型,非阻塞IO

I/O多路复用模型
Redis的性能瓶颈是网络延迟而不是执行速度,I/O多路复用模型实现高效的网络请求
用户空间和内核空间
常见的IO模型,阻塞IO,非阻塞IO,IO多路复用
Redis网络模型

用户空间和内核空间。
Linus系统中进程使用的内存分为用户空间和内核空间
用户空间执行受限的命令,不能直接调用系统资源,必须通过内核提供的接口访问
内核空间可以执行特权命令,直接调用系统资源

Linux系统为了提高IO效率,用户空间和内核空间都加入缓冲区,写数据先把数据拷贝到内核缓冲区然后写入设备,读数据先把数据拷贝入内核缓冲区,然后拷贝到用户缓冲区。为了提高效率,就需要减少等待数据的时间和拷贝数据的次数。

IO多路复用
IO多路复用是redis采用的解决办法,利用单个线程epoll同时监听多个Socket,在某个Socket可读,可写时得到通知,避免无效的等待,充分利用cpu资源。
阶段1, 用户进程调用select,指定要监听的Socket集合
用户监听多个对应的Socket
任意一个数据就绪返回readable
此过程中用户进程阻塞
阶段2, 用户进程找到就续的数据
依次调用recvfrom读取数据
内核将数据拷贝到用户空间
用户进程处理数据
避免了无效的用户进程等待

监听Socket的方法有3种,select和poll,通知用户进程有Socket就绪,需要用户进程遍历寻找就续
epoll则会通知用户进程Socket就绪的时候,把Socket写入用户空间,被采用于redis中。
加粗样式
redis网络模型
IO多路复用+事件派发,连接应答处理器,命令回复处理器,命令请求处理器等待
IO操作影响网络性能,内存中的数据处理是高速的,Redis6.0版本后加入多线程处理读数据和写数据的操作,避免了并发中的数据等待。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值