Redis与缓存 面试大纲(持续更新)
2021-12-29 17:40:00 5 举报
AI智能生成
登录查看完整内容
Redis与缓存 面试大纲
作者其他创作
大纲/内容
SDS
String
双向链表 + 压缩列表
List
哈希表 + 压缩列表
Hash
跳表 + 压缩列表
Sorted Set
整数数据 + 哈希表
Set
Redis 本质就是一个 key-value 缓存数据库,其中 value 有不同的数结构
顺序读写 查找复杂度:O(N)
整数数组
双向链表
查找复杂度:O(1)
哈希表
头尾查找复杂度 O(1),其他 O(N)
压缩列表
查找复杂度 O(logN)
跳表在链表的基础上,增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位
跳表
集合数据操作效率
全局哈希表
rehash 法:两个全局 hash 表
hash 冲突链过长?
拉链法
hash 冲突?
键和值用什么结构组织?
02 | 数据结构:快速的Redis有哪些慢操作?
数据结构
Redis 为什么用单线程?
哈希表,跳表
高效数据结构
纯内存操作
IO 多路复用
单线程 Redis 为什么那么快?
03 | 高性能IO模型:为什么单线程Redis能那么快?
为什么单线程Redis能那么快?
检查开销
不阻塞写操作
为什么使用写后日志
可能会阻塞主线程可以通过配置写回磁盘的策略减少主线程阻塞
由主线程写回磁盘
回写策略
日志丢失
风险
写后日志
AOF重写减少日志大小
和 AOF 日志由主线程写回不同,重写过程是由后台线程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
AOF 重写会阻塞吗?
日志文件太大了怎么办?
04 | AOF日志:宕机了,Redis如何避免数据丢失?
AOF
AOF 日志通过重放命令恢复数据,较为缓慢
在主线程中执行,会导致阻塞;
save
创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
bgsave
全量快照
对哪些数据进行快照?
写时复制技术
可以
快照时数据能修改吗?
内存快照恢复数据
05 | 内存快照:宕机后,Redis如何实现快速恢复?
RDB
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
混合使用 AOF 日志和内存快照
Redis 持久化
主从库间如何进行第一次同步?
主从网络断开后采取增量复制
主从库间网络断了怎么办?
主从复制模式,主库宕机,无法写入数据,不能做自动切换,需要手动切换,故障解决慢
缺点:
主从复制
选举
选主
通知
哨兵的作用
解决: 哨兵集群
哨兵集群投票
单个哨兵会误判
筛选+打分 选举新的主库
哨兵投票选举 leader
由哪个哨兵执行主从切换?
确定主库宕机后
缺点:哨兵机制有效的解决了 主从模式下的自动选举和替换主库的问题,但是比较费内存,如果需要Redis 内存比较大,只能一直加内存,但是内存大都会影响 fork 生成 RDB 的时间
原主库假故障导致的脑裂
为什么脑裂会导致数据丢失?
脑裂问题
哨兵机制
实施简单,直接
优点
大内存时, fork 会阻塞主线程
硬件成本,资源浪费
缺点
纵向扩展
不用担心单个实例的硬件和成本限制
扩容方便
数据切片后,在多个实例之间如何分布?
客户端怎么确定想要访问的数据在哪个实例上?
分布式管理
横向扩展
Redis 大数量量
hash 槽
数据切片和实例的对应分布关系?
对 key 进行 CRC16 运算计算hash 槽,每个客户端存储这 redis server hash 槽的对应关系
客户端如何定位数据?
server 重定向
把删除的数据转移到其他的节点上,重新分配hash 槽
删除
redis server 增减
Redis Cluster
数据中有 bigkey,导致某个实例的数据量增加;
Slot 手工分配不均,导致某个或某些实例上有大量数据
使用了 Hash Tag 手动分片,导致数据集中到某些实例上
原因
数据量倾斜
热点数据
数据访问倾斜
分类
37 | 数据分布优化:如何应对数据倾斜?
数据倾斜
切片机群可能造成的问题
切片集群
09 | 切片集群:数据增多了,是该加内存还是加实例?
Redis 集群
Redis 高可用
慢查询
过期 key 操作
Redis 操作层面
日志回写策略
文件系统:AOF 模式
操作系统:swap
操作系统:内存大页
系统层面
两个方面排查
Redis 突然变慢怎么办?
常用就是 LRU
Redis 8 中缓存淘汰策略
子主题
Redis 缓存满了怎么办?
启用 Redis 自动内存碎片清理,比如 内存 75% 触发
内存碎片
惰性删除
删除数据后,为什么内存占用率还是很高?
Redis 核心技术与实战
zset
热门借阅数据
资源综合统计分析
选课系统-课程信息存缓存
公告栏
会话缓存
set
Sorted Set(Zset)
排行榜,计数器
队列
发布-订阅
业务场景
rehash
渐进式 hash
双全局 hash
链表过长导致性能下降
发生冲突:采用拉链法
全局 hash 表
高性能
高并发
因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。原文地址:https://redis.io/topics/faq。
基于内存实现
我们要明确的是:Redis 的单线程指的是 Redis 的网络 IO 以及键值对指令读写是由一个线程来执行的。 对于 Redis 的持久化、集群数据同步、异步删除等都是其他线程执行。
单线程模型,避免的不必要的上下文切换和竞争
Redis 采用 I/O 多路复用技术,并发处理连接。采用了 epoll + 自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 IO 上浪费一点时间。
多路指的是多个 socket 连接,复用指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。epoll 是最新的也是目前最好的多路复用技术。它的基本原理是,内核不是监视应用程序本身的连接,而是监视应用程序的文件描述符。
简单来说:Redis 单线程情况下,内核会一直监听 socket 上的连接请求或者数据请求,一旦有请求到达就交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的事件处理器。所以 Redis 一直在处理事件,提升 Redis 的响应性能。
使用 IO 多路复用,非阻塞 IO
1.动态字符串:SDS
2.双向链表
hash 表
跳跃表
高效的数据结构
Redis 为什么这么快?
如何解决?
缓存与数据库双写不一致
大量缓存同一时间失效
在原有的缓存失效时间上加上或者减去一个随机值(1-5分钟)
使用队列,让访问数据库的请求顺序访问数据库
限流降级
集群
缓存雪崩
查询一个并不存在的数据
2. 把查询不存在的key也缓存起来,并设置一个较短的过期时间
缓存穿透
某个 key 缓存失效的一瞬间涌进来大量请求
加锁(分布式锁或者sychronized锁)
定时任务,缓存快失效时,进行提前更新
-----------------------
不过期
4 种解决方案
如何让解决?
缓存击穿
优缺点
redis和memcached有什么区别?
一文搞懂 Redis 常见面试题
1. 多个 socket2. IO 多路复用程序3. 文件事件分派器4. 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
文件事件处理器程序的组成:
一句话解释:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力
什么是 IO 多路复用
逻辑控制流的重叠单核 CPU 无法同时处理,需要 CPU 分时复用模拟并发控制逻辑。这样会带来以下缺点:1. 线程/进程切换成本。2. CPU 在不同上下文切换成本。3. 多线程资源竞争导致并发问题。有没有一种可以在单线程/进程中处理多个事件流的方法呢?一种答案就是IO多路复用。因此IO多路复用解决的本质问题是在用更少的资源完成更多的事。
IO多路复用在Linux下包括了三种,select、poll、epoll,抽象来看,他们功能是类似的,但具体细节各有不同:首先都会对一组文件描述符进行相关事件的注册,然后阻塞等待某些事件的发生或等待超时。
常见软件的IO多路复用方案Redis: Linux下 epoll(level-triggered),没有epoll用selectNginx: Linux下 epoll(edge-triggered),没有epoll用select
epoll优于select&poll在下面几点: epoll1. 在需要同时监听的文件描述符数量增加时,select&poll是O(N)的复杂度,epoll是O(1),在N很小的情况下,差距不会特别大,但如果N很大的前提下,一次O(N)的循环可要比O(1)慢很多,所以高性能的网络服务器都会选择epoll进行IO多路复用。2. epoll内部用一个文件描述符挂载需要监听的文件描述符,这个epoll的文件描述符可以在多个线程/进程共享,所以epoll的使用场景要比select&poll要多。
能详细解释下 IO 多路复用吗?
Redis 内部使用 文件事件处理器 处理数据,它是单线程的,所以叫做单线程模型。它采用 IO 多路复用机制监听多个 socket 命令,并把它们压如队列中,使用 事件分配器把队列中的一个个 task 交给不同的事件处理器执行。
redis的线程模型是什么?
1. 纯内存操作。2. 核心是基于非阻塞的 IO 多路复用机制。3. C 语言实现,语言更接近操作系统,执行速度相对会更快。4. 单线程反而避免了多线程的频繁上下文切换问题,预防了多线程可能产生的竞争问题。
为什么redis是单线程的但是还可以支撑高并发
sort set 统一检索首页借阅量排行应用,做 top 10 之类的应用
什么是跳表:
跳表区间查找效率高
跳表实现简单,不易出错
Redis 为什么使用跳表而不是红黑树
Zset 底层原理(字节面试):跳表( O(log2n))
一共五种
B树:插入,查找效率高,但浪费内存
查找判断式:
bitmap
概率算法:HyperLogLog
基数统计式:
如何统计一天内网站的访问用户数量?
redis的数据类型,以及每种数据类型的使用场景
对内存友好,对 CPU 不友好
定时删除
对 CPU 友好,对内存不友好
定期删除的流程
上面两种删除策略的折中方案
定期删除
常见删除策略
Redis的过期键删除策略有哪些?
redis采用的是定期删除+惰性删除策略
配置font color=\"#f15a23\
解决
有可能会导致内存越来越高,但可用key没有多少
redis的过期策略以及内存淘汰机制
每次取key时判断过期时间
Redis key 的过期策略
尽量使用 hash 这个数据结构,占用内存少,效率高
Redis 如何做内存优化?
写操作会报错,读操作不收影响
没有配置缓存淘汰机制下
内存不足时再写会删除旧的内存数据
配置了缓存淘汰机制
Redis 的内存用完了会发生什么?
可以配置淘汰策略为 LRU 即最近最少使用的数据淘汰掉。
Redis数据淘汰策略
Mysql 里有2000w数据,Redis 中只能存 20w 数据,如何保证 Redis 中的数据都是热点数据?
采用 scan
单线程造成阻塞
keys
结合 三级等保查询在线用户举例说明
假如 Redis 中有一亿个key,其中有10w个key是以某个固定字符串开头的,如何将它们全部找出来?
Redis 中有大量的 key 在同一时间过期,会发生什么?
使用 list 作为队列, rpush 生产消息,lpop 消费消息。当lpop 没有消息的时候,要适当sleep一会再重试。或者还可以使用 blpop ,会阻塞等到消息的到来。
可以, pub/sub 订阅发布模式
如何实现一次生产多次消费?
Redis 做过异步队列吗?怎么使用的?rpush,bpop
先拿 setnx 来争抢锁,抢到锁后就用 expire 设置过期时间,防止死锁。Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。
那如果 setnx 上锁之后,在 expire 之前程序崩溃没有添加过期时间怎么办?
这时候,沉吟思考片刻
Redission
Redis 的 set 命令有非常复杂的参数,可以把 setnx 和 expire 结合起来,做成一个原子操作!
使用过 Redis 分布式锁吗?它是怎么回事?
架构简单,部署方便,性能高。
优点:
Redis 宕机数据会丢失,Redis 不可用。
1.Redis 单副本
高可用性,可在master 出现故障时,自动切换到slave
读写分离:master 写,slave 负责读,有效应该对大并发量的读写操作
master 写能力和存储能力受到单机限制
故障恢复比较复杂,需要自己实现 Redis HA (Redis 主从高可用),自动切换主从后,还需要业务方修改配置。
双机主备架构
1. slave 连接master,发送 同步(SYNC) 命令,请求同步数据2. master收到 同步 命令,开始生成RDB文件,并使用缓冲区记录之后执行的所有写命令3.master RDB完成后,像 slave 发送RDB文件,并在发送期间继续记录写命令4. slave 接收到 RDB 后,丢弃所有旧数据,载入收到的快照5. master 发送RDB完成后,开始向slave 发送缓冲区的的写命令6. slave 完成RDB的载入,开始接受命令请求,执行来自master 缓冲区的写命令
一般发生在 Slave 节点初始化时,具体步骤如下:
全量复制:
1. master 每执行一次写命令,都会向slave发送该命令,slave 接收并执行此命令
一般发生在master和slave正常工作时,具体步骤如下:
增量复制
redis主从复制过程?
2. Redis 主从模式适用于做普通的缓存
部署架构包含两部分:Redis Sentinel集群和 Redis 数据集群。其中 Redis Sentinel 集群可以实现,故障发现,故障自动转移,配置中心(zookeeper),和客户端通知功能。Sentinel 监控 Redis 节点是通过 ping命令,超过一定时间未响应就开始选举
哨兵:就是运行在特殊模式下的Redis服务器,在启动Redis时,可以通过 --sentinel 命令启动哨兵
哨兵的作用就是对Redis的系统的运行情况的监控(使用流言协议:Gossip),它是一个独立进程。它的功能有2个:1、 监控master数据库和slave数据库是否运行正常;2、 master出现故障后,经过选举,自动将slave转化为master;整个过程不需要人工干预
哨兵:
哨兵机制是Redis社区提出的原生高可用解决方案。
解决了Redis 主从模式下主从节点的高可用切换
方便实现 Redis 数据节点的线性扩展,突破Redis 单线程瓶颈,大容量,高性能。
部署相对 Redis 主从模式更加复杂。
资源要求高,Redis Sentinel 中的 slave 节点作为备份节点不提供服务。
不能解决读写分离问题,实现起来相对复杂。
3. Redis Sentinel (哨兵) - 适用于高并发
------------即使有了哨兵机制的主从复制,但是每个节点都要保证整个集群中的所有数据,容易形成木桶效应,可以使用 Redis Cluster --
当遇到单机内存,流量,并发等瓶颈的时候,Redis Cluster 能起到负载均衡的目的。
Redis Cluster 集群最少配置9个节点,3主6从,其中master节点提供读写操作,slave 节点不提供请求,只为故障转移时使用。投票机制完成 master 到 slave 的切换。
key的有效部分使用CRC16算法计算出哈希值,再将哈希值对16384(2的32次方)取余,得到插槽值。
Redis Cluster 把所有物理节点映射到 0-16383(2的32次方) 的插槽上。当我们执行set abc 123命令时,redis是如何将数据保存到集群中的呢?执行步骤:1、 接收命令set abc 1232、 通过key(abc)计算出插槽值,然后根据插槽值找到对应的节点。(abc的插槽值为:7638)3、 从 7638 开始遇到的第一个redis节点作为数据节点,执行命令
1. 在配置文件中新增一个 Redis Cluster 节点;2.给新增加的节点分配插槽。
新增 Redis Cluster 节点:
1、 将这个节点上的所有插槽转移到其他节点上;2、 使用redis-trib.rb删除节点
删除 Redis Cluster 节点:
1. 宕机节点数据丢失2.如果宕机节点有 slave 节点,会进行提升
所有master投票:如果半数master节点与master 节点通信超时,则认为当前master节点不可用。
如何判断一个master 是否不可用?redis cluster 选主过程?
Redis Cluster 其中一个节点宕机:
网上说的 3 主3从是错的
1. 某个master节点及其所有slave节点全部挂掉,集群进入fail 状态
2. 集群中超过半数 master 挂掉,无论是否有slave,集群进入 fail 状态
3. 如果集群任意master挂掉,并且该master 没有slave节点,集群进入fail状态
Redis cluster 集群状态进入 fail 的条件?
Redis cluster 去中心化,任意一个master节点都能连接
Redis Cluster 是社区提出的 Redis 分布式集群解决方案。
比如在分布式节点中,要将数据存储到不同的节点,需要进行hash取模,但是当节点动态改变时,就需要重新hash了
普通hash的缺点?
一致性hash 算法就是把redis ip 对 2的32次方取模,放在一个hash环中
先使用CRC对key进行运算,再对 2的32次方取模
当有数据key来时,会使用hash算法计算key对应的 hash环位置,从此位置顺时针查找到的第一个节点就是需要存放的数据节点
redis 一致性hash算法采用 hash 环实现
虚拟节点
hash 环有时候会有数据倾斜的问题,即大部分数据都落在同一个节点,如何解决?
redis cluster 一致性hash算法?
redis一致性hash算法?(hash 环)
redis-cluster 数据是怎么保持一致?
在主从(或者哨兵模式)下,master 和 slave 节点由于网络分区暂时无法通信,此时slave提升为新的 master 节点,但老的master 节点还在写数据。过了一会网络分区恢复,旧master节点别降级为slave,导致数据丢失。
1. 设置master连接的最少slave数量
2. 设置 slave 连接到 master 的最大延迟时间。(增大延迟时间,不要让 slave 因为网络分区等原因误认为 master 挂了)
什么是redis的集群脑裂?(slave 提升为 master 后,master 又恢复,造成两者数据不一致)
可扩展
高可用
Redis Client 实现复杂,需要对插槽信息及时更新,目前 使用 JedisCluster 较多。
新增删除Redis Cluster 节点比较复杂。
支持哨兵和Redis Cluster 的主从切换后,客户端自动更新链接信息
Redis 客户端- Lettuce (来特思)
是老牌的Redis的Java实现客户端,提供了比较全面的Redis命令的支持。
Jedis
实现了分布式和可扩展的Java数据结构。促使使用者对Redis的关注分离,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列。
高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。
Lettuce
Redis常用的客户端有哪些?
4. Redis Cluster(集群)- 分布式
5. Redis 自研高可用
Redis 常见更高可用方式
持久化
扩容
自己设计一个缓存中间件?
【原创】分布式之redis复习精讲
Redis
为什么不适用 c 的string,而要单独开发一个数据结构1. 空间换时间,提高效率
2.在Redis 中 key-value 键值对中含有字符串值的都是由SDS实现
struct sdshdr{ int free; // buf[]数组未使用字节的数量 int len; // buf[]数组所保存的字符串的长度 char buf[]; // 保存字符串的数组}
c 中获取字符串长度要从头遍历
有三个属性: len,free,buf[]
效率高
c字符串长度固定,经常改变的话涉及到内存重分配,效率低
数据溢出
空间预分配
惰性释放
内存重分配
3. SDS 结构
SDS (Simple dynamic string)
了解redis的String数据结构底层实现嘛?
看完这20道Redis面试题,直接通关
流程
快照
大量数据时比 AOF 启动效率更高
bgsave 生成 RDB 快照期间,还能处理读写命令,是通过多进程 COW(Copy On Write)技术实现的
通过 bgsave 命令 fork 子进程来做持久化,性能更好
只有一个 dump.rdb 文件,方便持久化和恢复
有可能会丢失数据,因为RDB 是隔一段时间进行持久化。RDB 快照生成频率不好把控
在实际写数据之前,将修改的数据写到日志文件中,故障恢复得以保证。比如 MySQL Innodb 存储引擎 中的 redo log(重做日志)便是记录修改的数据日志,在实际修改数据前先记录修改日志在执行修改数据。Redis 的 AOF 文件并没有选择 写前日志。
先执行「写」指令请求,将数据写入内存,再记录日志。
1.写后日志避免了额外的检查开销,不需要对执行的命令进行语法检查
2.写后记录日志不会阻塞当前的 【写】指令执行
每个 写 指令都要刷盘,性能最差,安全性最高
always
每秒刷盘:允许一点数据丢失
everysec
由操作系统控制:高性能
no
刷盘策略
每次执行内存写命令都要执行写后日志写入磁盘,多降低 Redis 的写入性能。为了解决这个问题,常用的手段就是,把写后日志写到日志缓冲区,在适当时机刷回磁盘。刷盘的时候可以使用操作系统的 fsync 和 fdatasync 这两个同步函数
AOF 日志记录的是写后日志
记录所有命令,保存为 AOF 文件
数据安全,每次命令都能记录
AOF 日志文件过大,使用 bgrewriteaof 命令进行 AOF 文件重写,合并命令,进行瘦身
bgrewriteaof 不会阻塞主线程
把原 AOF 文件重写生成另一个文件,并没有在原来的 AOF 文件上重写
AOF文件比RDB文件要大,恢复速度慢
数据集大的时候,比 rdb 启动效率低
很少使用 RDB 恢复数据,因为会丢失大量数据。但是重放 AOF 性能又慢得多为了兼顾两者,Redis4.0 退出了 混合日志模型
混合日志模型的 AOF 日志记录的不再是全量日志,而是自上次 RDB 持久化时间点之后的日志。这样 AOF 日志文件就会变得很小。
在 Redis 重启后,可以先加载 RDB 文件,再使用 AOF 文件进行重放
原理
重启 Redis
Redis 4.0 混合日志模型
Redis 的持久化机制是什么?优缺点?
Redis与缓存
0 条评论
回复 删除
下一页