redis面试问题总结

1、redis数据结构及应用场景
string:缓存、分布式锁、常规计数、共享session
list:消息队列、
hash:缓存对象、购物车
set:聚合计算例如 点赞、关注、抽奖活动
zset:排序场景 例如排行榜 、姓名排序
2、redis是单线程吗
redis在执行命令时是单线程操作,redis使用事件驱动模型和IO多路复用技术,可以同时处理多个连接和请求。(linux的io多路复用机制指的是一个线程处理多个io流,即select\epoll机制,内核一直监听套接字的请求,一旦有相关请求,就交给redis处理,从而实现redis线程处理多个io流的效果,为了在请求到达时通知redis线程,select\epoll提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数,相关事件被放到一个事件队列,redis单线程对该事件队列不断处理,避免一直轮询是否有请求发生造成cpu资源浪费,因为redis一直在处理事件队列,所以能及时响应请求)。
3、redis单线程为什么还那么快
redis基于内存操作
采用单线程避免不必要的上下文切换,不用考虑锁问题
采用多路复用技术,非阻塞io,redis可以在单线程中监听 多个socket的请求
4、Redis 6.0 之前为什么使用单线程?
因为 Redis 的数据结构和算法都是单线程最优的,多线程并不会提高性能,反而会引入额外的锁、线程管理和上下文切换的开销,导致性能反而下降。
另外,Redis 作为一个内存数据库,其数据访问都是非常快的,瓶颈一般出现在网络 IO 和持久化操作上,这些都是可以通过异步 IO、多路复用等技术来解决的,
而无需引入多线程。
5、Redis6.0为什么要引入多线程呢?
对于大多数公司来说,单线程的Redis达到80,000到100,000 QPS已经足够使用了。但随着现在业务的越来越复杂,需要更大的QPS;
从Redis自身角度来说,因为读写网络的read/write系统调用占用了Redis执行期间大部分CPU时间,瓶颈主要在于网络的 IO 消耗,redis支持多线程主要就是两个原因:
可以充分利用服务器 CPU 资源,目前主线程只能利用一个核
多线程任务可以分摊 Redis 同步 IO 读写负荷
6、redis如何保证数据不丢失
(1)持久化
rdb 是将redis缓存中的数据定期保存到磁盘上
aof 是将redis执行的命令记录到日志文件中
(2)主从复制
redis支持主从复制,可以将主节点的数据复制到从节点,从而实现数据的备份和容灾,如果主节点发生故障,从节点还可提供服务。
(3)集群模式
redis支持集群模式,可以将数据分散存储在多个节点中提高数据的可靠性和可用性。
(4)内存快照 (5)数据备份
7、aof日志如何实现的
aof日志是一种文本文件,它记录了redis数据库中所有的写操作,每当redis执行一条写操作时,就会追加到aof日志文件尾部。因此 aof日志文件中 包含了所有redis的写操作。
8、aof写回策略
always 同步回写 每个写命令执行完,立马同步的将日志写回磁盘中
everysec 每秒写回 每个写命令执行完,只是先把日志写到aof文件缓存中,每个一秒把缓存内容写入 磁盘
no 由操作系统控制写回 只是先写入aof文件的内存缓冲区
9、aof日志过大会发生触发重写机制,重写的过程如何
把主线程的内从拷贝一份给fork出来的子进程,这里包含了redis中最新的数据,子进程将其中的数据进行重写,主线程维护一个aof缓存区,如果此时有写操作,则会写入到aof缓冲区和aof日志文件中,保证数据完整性。主线程在重写时维护一个aof重写缓冲区,将重写过程中的写操作记入其中,保证重写后的aof日志也能记录在重写过程中产生的新数据。用新的aof文件替换老的aof文件。
10、rdb快照如何实现的
通过两个命令来生成 RDB 文件,分别是 save 和 bgsave。
save : 在主线程中执行,会导致阻塞,直到RDB文件创建完毕
bgsave : fork一个子进程专门用于写入 RDB 文件,避免了主线程的阻塞(默认配置)
Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。

bgsave中子进程是由主线程 fork 生成的,可以共享父进程内存里面的代码段和数据段数据,bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。
如果主线程要修改一块数据(例如图中的键值对 C), 那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。
做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。
11、rdb做快照时会阻塞线程吗
使用save会阻塞,bgsave命令创建一个子进程 在 创建子进程过程中会阻塞一段时间,,而且主线程的内存越大,阻塞时间越长。因此,在选择RDB快照方式时,需要根据具体情况权衡使用save命令还是bgsave命令。
12、rdb在执行快照时,数据能修改吗
save是同步阻塞,bgsave的时候可以修改,如果主线程执行写操作时,则被修改的数据会复制一份副本,然后bgsave子进程会把该副本数据写入rdb,在这个过程中,主线程仍然可以直接修改原来的数据。
13、混合持久化
重启Redis时,我们很少使用RDB来恢复内存状态,因为会丢失大量数据。我们通常使用AOF日志重放,但是重放AOF日志性能相对于RDB来说慢很多,
在Redis实例大的情况下,启动需要花费很长时间,Redis4.0之后提供了新的持久化机制,混合持久化
所以推出了混合持久化集成两者优点,在AOF重写日志时,fork出来的子进程会把当前主线程共享的内存数据以RDB方式写入到AOF文件,然后主线程处理的命令被记录到重写缓冲区中,重写缓冲区中的命令会以追加AOF的形式存在AOF日志中。使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
14、redis集群脑裂导致数据丢失怎么办
redis的集群脑裂指在主从集群中,同时拥有两个master主节点,他们都能接受写请求,而脑裂最直接影响就是客户端不知道往哪个master主节点写入数据,结果就是不同的客户端会往不同的主节点上写入数据,此时redis的集群脑裂就有可能导致数据丢失。
15、脑裂 的原因
网络问题:导致redis master节点跟redis slave节点和哨兵sentinel集群处于不同的网络分区,此时因为sentinel集群无法感知到master的 存在,所以将slave节点提升为master节点,此时就存在两个不同的master节点。
主机资源问题 redis master节点服务资源被其他程序大量占用,导致主库资源使用受限,短时间内无法响应心跳,于是sentinel集群重新选举新的master,当其他程序不再使用资源时 旧的master节点又恢复正常,此时就存在两个不同的master。
16、脑裂解决方案
min-slaves-to-write默认配置为0,这个配置表示master至少有N个slave节点才进行工作。当出现Redis集群脑裂时,其中一个出问题的master此时就少于N的slave连接,此master就拒绝写请求。
主库能进行数据同步的最少从库数量
min-slaves-max-lag默认配置为10,这个配置表示slave和master之间只能落后N ms的数据。超过了该值就拒绝写请求,就不会往master中写入数据
主从库间进行数据复制时,从库给主库发送ACK消息的最大延迟(单位s)
假设从库有K个,可将:
min-slaves-to-write设置为K/2+1(如果K等于1,就设为1)
min-slaves-max-lag设置为十几秒(例如10~20s)
这个配置下,如果有一半以上的从库和主库进行的ACK消息延迟超过十几s,我们就禁止主库接收客户端写请求。
这样一来,我们可以避免脑裂带来数据丢失的情况,而且,也不会因为只有少数几个从库因为网络阻塞连不上主库,就禁止主库接收请求了。
17、redis过期删除策略
定时删除 再设置的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。
惰性删除 使用个key时先判断是否过期,如果发现过期就会删除。
主动删除 默认每秒会随机检查设置了过期时间的key,如果发现过期就删除。
18、redis持久化时,对过期键如何 处理的
在执行save或bgsave时创建一个新的rdb文件,redis会对数据库中的键进行检查,过期键不写入rdb 如果服务器是主服务器,那么在载入RDB文件时,会对过期键进行过滤,也就是不会加载RDB中的过期键到主服务器中。
如果服务器是从服务器,那么在载入RDB文件时,不会对过期键过滤,先将RDB中的全部数据加载到从服务器中。然后再进行主从同步,删除过期键。
因为AOF采取的是追加写,所以如果过期键被删除的话,其实是向AOF文件中追加一条DEL命令,来显示的标记该key被删除了。AOF重写程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中。这样可以保证重写后的AOF文件中只包含有效的数据,减少文件大小和载入时间
19、Redis 主从模式中,对过期键会如何处理?
如果服务器在复制模式下运行,主从服务器对于过期键的处理有以下规则:
主服务器在删除一个过期键后,会显式地向所有从服务器发送DEL命令,告知从服务器删除这个过期键。
从服务器在执行客户端发送的读命令时,即使碰到过期键也不会将其删除。从服务器只有在接收到主服务器发来的DEL命令后,才会删除过期键。
通过由主服务器来控制从服务器统一地删除过期键,可以保证主从服务器数据的一致性。
20、redis内存淘汰策略
noeviction:不驱逐任何key lru lfu random ttl
21、如何避免缓存雪崩、缓存击穿、缓存穿透?
缓存穿透
缓存穿透是指用户请求的数据在缓存中不存在即没有命中,同时在数据库中也不存在,导致用户每次请求该数据都要去数据库中查询一遍,然后返回空。
缓存穿透常用的解决方案 布隆过滤器 空对象写到缓存中
缓存击穿
有一个key非常热门,是查询热点,结果某一时刻这个key在redis缓存中过期了,那么此时大量关于该key的请求过来,
并且这些请求在缓存中查不到就会全部打到数据库那边导致数据库被一瞬间压垮。
缓存击穿常用的解决方案 使用分布式锁控制线程 不设置时间

缓存雪崩
redis中许多key失效了(过期或者删除),此时又有大量并发请求打过来,redis中查不到就全跑到数据库那边去了,如此一来DB可能会被直接打垮。
缓存雪崩和缓存击穿挺像的,区别仅在于后者是某个热点key失效,而雪崩是很多key失效。
缓存雪崩常用的解决方案 key的失效时间分散 设置二级缓存
22、缓存更新策略
在这里插入图片描述
主动更新策略
cache aside pattern 由缓存的调用者,在更新数据库时同时更新缓存
read\write through pattern 缓存于数据库整合成一个服务,由服务来维护一致性,调用者调用该服务,无需关心缓存一致性问题
write behind caching pattern 调用者只操作缓存,由其他线程异步将缓存数据持久化到数据库,保证最终的一致性
延迟双删策略 是一种保证数据一致性的常用策略。在更新数据库后,先删除缓存,然后等待一段时间,再次删除缓存。这样做的目的是为了防止在数据库和缓存主从同步的过程中,有其他请求查询到旧的缓存数据,并写回到缓存中。
从数据一致性的角度 使用cache aside pattern,那么就要考虑
(1)删除缓存还是更新缓存
更新缓存 每次更新都更新缓存,无效写操作比较多
删除缓存 更新数据库删除缓存,查询时添加缓存 (常用)
(2)如何保证缓存和数据库的操作同时成功和失败
单体项目 缓存和书库库操作放入一个事务中
分布式 使用分布式方案
(3)先操作缓存还是先操作数据库
先删缓存, 再操作数据库
先操作书库库 再删缓存
如图比较
在这里插入图片描述
上述图是正常的
在这里插入图片描述
上述图中存在一致性问题
在这里插入图片描述
上述图是正常 的
在这里插入图片描述
上述图有一致性问题 但是发生的概率低 故使用先更新书库再删除缓存

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值