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