C# .NET CORE 面试题【Redis篇】
心之所向,勇往直前!
归纳遇到的Redis相关面试题,记录关键点信息方便查找文档资料。
正文
Redis是单线程还是多线程?
a. 工作线程:单线程,主要是指Redis读写键值对是由一个工作线程执行的
b. 整个程序:多线程,网络IO多路复用(一个线程监听多个套接字,触发事件,排入队列)
c. 注意:即使在7.0版本(2022年)以后采用了新的多线程模型,但仍然不是完全意义上的多线程模型,只是通过多路复用技术和少量的线程来提高性能。
Redis为什么这么快?
a. 基于内存操作数据
b. 单线程读写键值,避免了上下文创建的开销
c. 6.0版本之后采用多路IO复用来解决处理网络IO请求瓶颈的问题(Redis的瓶颈不在CPU而是网络带宽和内存)
d. Redis使用全局的Hash表实现Key的存储,检索时间复杂度为O(1)
e. 高效的底层数据结构(简单动态字符串SDS,双向链表,压缩列表,哈希表,跳表和整数数组)
3. Redis常见的数据类型有哪些?
a. Redis的核心对象是RedisObject,其中的Type表示数据的具体类型(String、List、Hash、Set、ZSet)
b.String是最常用最基本的类型,也可以是数字,最大容量是512M(6.0版本之后)
c. 扩展的类型有(Bitmaps、HyperLogLogs、GEO)
Redis和Memcache的区别?
a. Redis支持更多的数据类型
b. Redis支持RDB和AOF两种模式的数据持久化
c. Redis支持高可用的解决方案(主从、哨兵、Cluster)
Redis的应用场景有哪些?
a. 缓存数据
b. 热点数据(List)、访问统计(String)、排行榜(ZSet)、好友关注(ZSet)
c. 分布式锁(setnx)
Redis的能否持久化数据,具体用什么方式?
a. Redis有RDB和AOF两种持久化机制
b. RDB(全量快照):某个时间点执行备份,会Fork一个子进程执行操作,此时仍可以继续写入数据(写时复制)
AOF(追加日志):每次写完数据后会把操作指令写入日志文件,会Fork一个子进程执行操作
c. RDB的恢复方式比AOF快,因为RDB是直接加载到内存中,AOF需要每条命令逐一执行
d. Redis重启时会根据持久化的方式选择恢复数据
能详细说说RDB模式吗?
a. RDB模式下,Redis会将键值对数据写到dump.rdb文件中,以二进制的格式储存,默认使用RDB持久化
b. 支持自动和手动两种模式,使用手动的save模式时会阻塞主线程,bgsave和自动模式会Fork一个子进程来对数据集进行备份,使得主进程仍可以对数据进行修改。
写时复制:父子进程内存空间不同但是共享相同的内存数据,当父进程修改数据时会触发子进程去执行复制数据的工作,即分配物理地址
c. 在要恢复的数据量较大的时候性能比AOF好
d. 由于RDB不是秒级备份操作,出现宕机时会丢失数据
e. 命令:save 900 1,表示在900秒内有1个键值对发生变化时触发
能详细说说AOF模式吗?
a. AOF模式下,Redis会将每一次指令追加到缓冲区,然后写到文本文件中
b. 有三种模式可以选择:always(总是)、everysec(每秒)、no(操作系统来决定什么时候保存保存)
c. 比RDB可靠性高,但是在数据集比较大时恢复比较慢
d. Redis提供重写机制来避免AOF模式下日志文件过大的问题
Redis的各数据类型操作命令
Redis是怎样实现主从同步的?
a. slave在宕机重启后发送psync命令
b. master收到命令后执行bgsave,fork一个子进程生成RDB文件,如果此时主库产生了修改命令,则会将修改命令记录到缓冲区
c. master将RDB文件以及缓冲区命令先后发送给slave
d. 主从数据最终一致
如何解决Redis主从架构下,主库宕机导致从库丢失全部数据的问题?
发生这种情况的原因是主库没有持久化,当主库发生宕机时直接操作重启,导致从库重连时复制了主库的空rdb文件
a. 主库做持久化
b. 如果主库没有做持久化,则先连接从库执行save命令保存rdb复制到主库data目录后,再重启主库触发重连同步
说说Redis的重同步机制?
a. master和slave各自记录一个偏移量值offset,和服务器ID
b. master会把最近的写命令记录在缓冲区(1M),在slave重新连接时根据偏移量发送命令同步,如果offset不在缓冲区中,则会执行全量同步
c. 当slave的服务器ID和master的ID不一致时,也会执行全量同步
你能举例说说Redis的几种数据类型的应用场景吗?
string:缓存、计数器、分布式锁、分布式token
hash:用户信息记录
list:最新的热点数据,如新闻,通知
set:好友关系、标签、点赞、抽奖
zset:排行榜
什么是缓存穿透?
缓存穿透是用户请求了redis以及数据库都没有的数据,频繁的无效请求对数据库造成压力
a. 可以在接口层增加参数校验 + 登录授权校验(避免匿名攻击)
b. 可以将数据缓存下来并设置一个较短的过期时间,避免短时间内被重复请求数据库
c. 可以使用布隆过滤器(可以判断出值一定不存在)
什么是缓存击穿?
缓存击穿时在某一个时间点内,热key失效导致大量请求打到数据库造成压力
a. 可以设置热key永不过期
b. 使用互斥锁,抢到锁的用户才可以去访问数据库,然后重新再将值写到缓存中
什么是缓存雪崩?
缓存雪崩是某一时间内,大量的key同时失效,导致请求打到数据库造成压力
a. key的过期时间设置随机,避免短时间内大量key同时失效
b. 使用互斥锁,抢到锁的用户才可以去访问数据库,然后重新再将值写到缓存中
c. 设置双重缓存,缓存1过期后获取缓存2,缓存2的过期时间可相对设置长一些
d. 使用定时任务定时刷新缓存
什么是缓存预热?
在系统功能上线前,手动写入缓存,避免上线后用户直接访问到数据库
什么是布隆过滤器?
布隆过滤器可以看做是一个二进制数组,本质是二进制向量和随机函数的映射,当key使用一个或多个hash算法得出对应的数组下标,标记为1,因此可以判断出某个key一定不存在。
a. 布隆过滤器不可以删除元素(因为hash碰撞的原因,不同的key经过计算后可能得出相同的hash)
b. 容错率越小,需要的储存空间越大
c. 当插入的数量 > 容量时会触发扩容,默认为2倍
d. 应用场景:黑名单、爬虫URL去重、缓存穿透、
Redis的Key过期策略有哪些(Redis如何处理过期的Key)?
Key过期后不会被立马删除,过期策略仅针对有设置过期时间的Key,设置了过期时间的Key会存放在一个独立的字典中
a. 被动策略:在用户访问Key时,redis会检测一次过期时间,如果过期则删除key。(存在如果永远没有访问Key就会一直占用内存的问题)
b. 主动策略:每10s随机选择20个设置了过期时间的Key,删除过期Key,如果过期的Key占了25%以上,则会继续重复执行该策略
Redis的Key淘汰策略有哪些(Redis如何处理过期的Key)?
淘汰策略可以仅针对设置了过期时间的Key,也可以针对所有的Key
a. lru算法:随机取样(默认5个)最长时间没有使用(时间)的Key进行淘汰。具体机制为:使用一个hash表(查询)和双向链表(插入、删除)来维护数据,最新的数据会在头部,最久的在尾部被删除
b. lfu算法:随机取样(默认5个)最近最少使用(频率)的Key进行淘汰。具体机制为:维护两个双向链表记录访问频率、kv,找到相同频率的节点将kv写入节点的链表中,每次移除最尾部的Key
你参与的项目有应用过Redis的高可用方案吗?(主从同步)
a. 一主多从,主写从读,降低服务器读压力
b. 级联多从,每个slave也可以部署多个slave,这种方案可以避免master重启后runid变化导致所有主多从方案下所有slave同时全量同步造成服务器压力的问题
你是怎么解决主从同步延迟的(数据不一致)?
先确定是什么原因导致的延迟(网络原因、大量主从复制)
a. 如果是非核心业务不追求及时性,可忽略
b. 部分核心业务对数据时效有要求的,可选择读master,其他业务读slave
c. 如果是网络原因就提升网络、大量全量复制就确定是不是复制缓冲区不够
你参与的项目有应用过Redis的高可用方案吗?(哨兵模式)
a. 哨兵是特殊的redis节点
b. 哨兵每10s向master发送一次命令获取节点信息,记录slave节点
c. 哨兵间通过Pub/Sub消费订阅模式使用特定的__sentinel__:hello通道向主从节点发送消息,因此可以保持通信以及交换信息
d. 哨兵模式建议至少需要3个
e. 参考资料
哨兵模式是如何进行故障检测的?
a. 哨兵每10秒通过发送Ping命令检测主节点的健康状态,可配置down-after-miliseconds确定主管宕机的超时时间
b. PING
命令发送成功后,设置last_ping_time
为当前时间。如果收到回复,设置last_pong_time
为当前时间,确认节点正常运行
c. 如果只有1台哨兵则为主观宕机会直接选举slave为master,存在多台哨兵时需要达成客观宕机(即多台哨兵均认为master宕机,哨兵数量可配置,超过半数以上的哨兵数量)才会选举slave成为主节点
d. 哨兵选举后会发送slave of no one命令关闭slave复制功能,通知其他slave变更master节点,当旧的master重连后会自动变更为slave
哨兵模式在故障转移时是如何实现Leader选举的?
a. 当哨兵节点判断master宕机后,会把自身的纪元+1并发送命令Sentinel is-master-down-by-addr询问其他哨兵节点进行投票,最后对票数进行统计
b. 当票数 > 哨兵节点/2+1 && 票数 > 法定票数时节点可被选举为Leader
c. 选举失败时,将会重新进行选举
d. 选举过程中,redis服务将不可用
哨兵模式在故障转移时是如何实现Master选举的?
a. 由Leader执行故障转移,排除不符合条件的slave节点(优先级=0、5秒内未回复、主观宕机或与处于断线状态的从节点)
b. 节点选择层次为:优先级最大 > 复制偏移量最大 > RunId最小
c. 主节点选举完成后,哨兵Leader发送slaveof NO ONE指令将从节点升级为主节点,此时从节点会重置信息并开始执行持久化重写操作
d. 哨兵Leader在过程中每秒询问从节点,当接收到升级成功信号后,开始遍历所有从节点更改对应的Master信息为新升级的Master
如何解决脑裂问题?
脑裂是由于网络原因(哨兵和master可能不在同一个网络分区)导致哨兵无法感知master导致重新选举了master,此时原master仍然能保持写入,将会造成大量数据丢失
a. 配置min-replicas-to-write 1:连接master的最少slave数量
b. 配置min-replicas-max-lag 10:slave连接master最大延迟时间
c. 根据以上配置,如果出现故障且不满足要求,master会拒绝写入从而降低数据丢失造成的损失
删除Key会阻塞线程吗?
a. 短时间内操作删除大量Key会阻塞
b. 删除大Key会阻塞,具体根据Key的Value大小决定影响程度
如何避免删除大Key导致的阻塞?
a. 使用SCAN命令,分批获取数据删除
Hash:hscan + hdel
List:ltrim
Set:sscan + srem
ZSet:zscan + zsrem
b. unlink命令
如何使用Redis实现分布式锁?
a. set key value NX PX 10 :使用SetNx设置一个客户端特有值value(可以是客户端id或者uuid),10秒(一定时间)后自动过期,如果不存在该key则设置成功,否则失败
b. 业务逻辑完成后,执行删除:
get key:先获取key判断是否与当前客户端匹配
del key:删除key
c. 针对b的操作,使用lua脚本保证原子性
d. 针对过期时间是预估的,有可能业务未执行完锁已被释放,可以运行备用线程检测锁的时间,即将过期时对锁进行续时
你是如何保证Redis和数据的一致性的?
a. 延时双删
b. 订阅binlog
结语
本篇到此结束,如果有任何疑问或者指正,请发表在评论区。