详细分析Redis的持久化操作——RDB与AOF
一、前言
由于疫情的原因,学校还没有开学,这也就让我有了很多的时间。趁着时间比较多,我终于可以开始学习那些之前一直想学的技术了。最近这几天开始学习Redis
,买了本《Redis实战》
,看到了第四章,前三章都是讲一些Redis
的基本使用以及命令,第四章才开始涉及到原理相关的内容。《Redis实战》
的第四章涉及到了Redis
的持久化、主从复制以及事务等内容,我个人认为这些应该属于Redis
中比较重要的部分,也是面试的常考内容。这篇博客就来记录一下Redis
的持久化机制。
二、正文
2.1 为什么需要持久化
学习过Redis
的应该都知道,Redis
与MySQL
等关系型数据库不同,它的数据不是存储在硬盘中,而是存放在内存,所以Redis
的速度非常快。而这也就会造成一个问题:电脑如果宕机,或者由于某些原因需要重启,此时内存中的数据就会丢失。Redis
既然把数据存放在内存,自然也就无法避免这个问题。所以,为了在电脑重启后,能够恢复原来的数据,Redis
就需要提供持久化的机制,将Redis
数据库存储在内存中的数据,在磁盘中进行备份,也就是持久化。而当Redis
重启后,去磁盘中将持久化的数据重新读取到内存,便能避免数据的丢失。
2.2 Redis的持久化方式
Redis
提供了两种持久化的方式,分别是:
- 快照持久化;
- AOF持久化;
下面我就来详细地介绍这两种持久化的方式。
2.3 快照持久化(RDB)
快照持久化也就做RDB
持久化。快照持久化的实现方式简单来说就是:Redis将当前内存中存储的数据写入到一个文件中,将这个文件作为Redis当前的一个快照,保存在磁盘中。当Redis重启时,将这个快照文件中存储的内容加载进内存,即可恢复Redis之前的状态。默认情况下,Redis
将快照保存在一个叫做dump.rdb
的文件中,我们也可以在配置文件中,通过dbfilename
选项来设置快照文件的名称;默认情况下快照文件就保存在Redis
的安装目录下,我们可以在配置文件中,通过dir
选项来配置快照文件的存储路径(其实也是AOF的路径)。
2.4 执行快照持久化的方式
执行快照持久化有两种方式:
2.4.1 使用配置文件
第一种方式就是在Redis
的配置文件中(windows
下这个文件叫redis.windows-service.conf
)加上save
配置项,比如像下面这样:
save 60 100:在配置文件中加上这一条的意思是,Redis会每60秒检查一次,若在这60秒中,Redis数据库执行了100次以上的写操作,那Redis就会生成一个快照文件,替换原来的快照文件;若不满足这个条件,则不生成快照,继续等待60秒;
我们可以根据自己的需求,调整每次等待的时间,以及对写操作次数的要求。而且,我们可以在配置文件中,添加多个save
选项,比如一个save 60 100
,一个save 5 10
,则Redis
每5
秒以及每100
秒都会判断一次。需要注意的是,我们不应该让生成快照太过频繁,因为这是一个比较消耗资源的工作,会降低Redis
的响应速度。
2.4.2 使用指令
执行快照持久化的第二个方法就是使用Redis
指令,Redis
提供了两个指令来请求服务器进行快照持久化,这两个指令分别是SAVE和BGSAVE。
(a)BGSAVE指令
BGSAVE
的执行流程如下:
Redis
调用系统的fork()
,创建出一个子进程;- 子进程将当前
Redis
中的数据,写入到一个临时文件中;同时父进程不受影响,继续执行客户端的请求; - 子进程将所有的数据写入到了临时文件后,于是使用这个文件替换原来的快照文件(默认是
dump.rdb
);
值得一提的是,通过配置文件执行快照持久化的方式,实际上就是Redis
在判断满足条件时,调用BGSAVE
指令来实现的。
(b)SAVE指令
SAVE
指令生成快照的方式与BGSAVE
不同,Redis
执行SAVE
指令时,不会创建一个子进程,异步的生成快照文件,而是直接使用Redis
当前进程。执行SAVE
指令在创建快照的过程中,Redis
服务器会阻塞所有的Redis
客户端,直到快照生成完毕,并更新到磁盘之后,才会继续执行客户端发来的增删改查的指令。
当然,这个指令一般很少使用,因为会阻塞客户端,造成停顿。但是实际上,这个指令的执行效率一般比BGSAVE
更高,因为不需要创建子进程,而且在这个过程中,其他操作被阻塞,Redis
服务器一心一意地生成快照。在《Redis实战》
中,作者提到了使用SAVE
指令的一个案例:
当前服务器的Redis数据库中保存了大量数据,使用BGSAVE指令生成快照会非常的耗时 ,而且由于所剩内存不多,甚至无法创建子进程,于是作者编写了一个shell脚本,这个脚本的内容就是让服务器每天凌晨3点,执行SAVE命令,生成快照,这样就不需要创建子进程,而且由于是凌晨三点,用户较少,SAVE的阻塞机制也不会有太大的影响。
2.5 快照持久化的优缺点
(1)优点:
快照的
rdb
文件是一个经过压缩的紧凑文件,它保存了Redis
在某个时间点上的数据集,这个文件非常适合用来备份。我们可以存储Redis
服务器在不同时间点上的rbd
文件,比如说一小时存储一次,一个月存储一次,这样就可以在遇到问题或有特殊需求时,将Redis
恢复到某一个时间点;RDB非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的服务器上;
RDB 可以最大化 Redis 的性能:父进程在保存
RDB
文件时唯一要做的就是fork
出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘I/O
操作,所以不会影响父进程处理客户端的请求;RDB
在恢复大数据集时的速度比AOF
的恢复速度要快。
(2)缺点:
- 当我们的服务器发生异常,导致停机时,那我们将会丢失最后一次创建快照后,所作的所有写操作,因为这些操作发生在内存中,还没来得及同步到磁盘。比如我们在配置文件中配置每
5
分钟生成一次快照,那当系统发生故障导致宕机时,我们将会丢失好几分钟内的操作; - 每次执行
BGSAVE
创建快照,都需要先创建出一个子进程,再由子进程执行后续操作,当内存中数据较大时,创建一个子进程将会非常耗时,造成服务器等待数毫秒,甚至达到一秒,影响用户体验。而且从这一点也可以说明,我们不能通过提高生成快照的频率,来解决第一个缺点;
2.6 AOF持久化
AOF
全称为只追加文件(append-only file),它的实现方式简单来说就是:AOF持久化机制,会将Redis执行的所有写指令,追加到到AOF的末尾,当服务器发生宕机,或者由于某些原因需要重启时,在重启后,读取AOF文件,重新执行其中记录的写操作,以此达到恢复数据的目的。
AOF
持久化机制默认是关闭的,我们可以在配置文件中,配置appendonly yes来开启。同时我们也可以通过配置appendfsync,控制写操作追加到AOF
中的频率,它有如下三种选项:
- always:
Redis
每次执行写指令,都会立即将这个写指令同步到AOF
中;使用这个选项时,Redis
发生异常,则最多只会丢失一次写操作(也就是在同步的过程中宕机,没同步完成),但是这也会导致Redis
的响应速度变慢,因为此选项会造成频繁的IO
操作; - everysec(默认):每秒同步一次,使用此选项,速度足够快,而且发生宕机时也只会丢失
1s
内的写操作; - no:让操作系统来决定什么时候进行同步,这个选项速度更快,但是不安全,宕机时丢失数据的多少是不确定的;
推荐(也是默认),使用第二个选项everysec
,每秒进行一次同步,因为这个选项兼顾了速度与安全性,而第一个选项太慢,第三个选项无法保证安全性。
2.7 AOF的重写机制
AOF
持久化的执行机制就是,不断地将写指令追加到AOF
的末尾,这样就会导致AOF
越来越大。为了解决AOF
越来越大的问题,Redis
实现了一种优化机制——AOF重写。当Redis
检查到AOF
已经很大时,就会触发重写机制,优化其中的内容,将它优化为能够得到相同结果的最小的指令集合。
比如说,我们在Redis
中使用SET
指令创建了一个String
类型的数据,最后使用DEL
指令将它删除了。如果开启了AOF
持久化,那么则AOF
中,将会记录这条SET
和DEL
指令。但是,在执行重写的过程中,这个String最后被删除了,那么Redis
就不会将这两条指令加入新的AOF
中,因为已经被删除的数据,不需要恢复。再比如说,我们使用Redis
维护了一个计数器cnt
,我们使用了100
次INCR
指令,让cnt
自增到了100
,而Redis
重写AOF
时,可以将这100
条incr
修改为一条SET
指令,直接将cnt
设置为100
,而不是保留100
条INCR
。
经过了重写后,AOF
的大小将会大大减小,而且也去除了不必要的操作,优化了恢复数据的指令集。而AOF
重写的过程与生成一个快照文件类似,如下:
Redis
执行fock()
,创建一个子进程用来执行后续操作,而父进程继续处理发送到Redis
的执行请求;- 子进程重写旧
AOF
文件,将重写后的内容写入到一个临时文件; - 如果这个过程中,有新的写指令到达,那么
Redis
会将这些写指令依旧追加到旧的AOF
中,同时也会将这些指令加入到内存的一个缓冲区中。这样做的目的是,如果服务器发生异常,AOF
重写失败,这些指令依然能够保存在旧AOF
,不会丢失; - 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有写指令追加到新
AOF
文件的末尾; - 使用新
AOF
替换旧的AOF
,这之后执行的所有写指令都将追加到新的AOF
中;
2.8 AOF的错误处理
AOF
文件是有可能发生错误的,比如上面提过,如果当前Redis
正在向AOF
中追加一个写指令,但是此时服务器宕机,那么这个存入AOF
中的这个写指令就是不完整的,也就是AOF
出现了错误。如果停机造成了 AOF
文件出错(corrupt), 那么 Redis
在重启时会拒绝载入这个 AOF
文件, 从而确保数据的一致性不会被破坏。
那么,当AOF
发生了错误,应该如何处理呢?我们可以使用如下命令:
redis-check-aof --fix:redis-check-aof用来检测AOF是否存在错误,如果指定了--fix参数,那么Redis在检测到AOF的错误后,会对AOF进行修复。
redis-check-aof
修复AOF
的方式非常简单:扫描AOF文件,寻找其中不正确或不完整的指令,当发现第一个出错的指令后,就将这个指令以及这之后的所有指令删除。为什么需要删除出错指令之后的所有指令呢?因为当一条指令出错,很有可能影响到后续的操作,导致后续操作的都是脏数据,而Redis
无法检测哪些指令是受到影响的,所以为了保险起见,就将后续指令全部删除。不过不用担心,因为在大多数情况下,出错的都是AOF
最末尾的指令。
2.9 AOF的优缺点
(1)优点:
- 使用
AOF
持久化会让Redis
变得非常耐久,意思就是说,当发生异常导致需要重启服务器时,只会丢失很少的一部分数据,因为AOF
持久化默认1s
同步一次,也就是说,Redis
最多只会丢失1s
中所做的修改; Redis
可以在AOF
文件体积变得过大时,自动地在后台对AOF
进行重写: 重写后的新AOF
文件包含了恢复当前数据集所需的最小命令集合。AOF
文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以Redis
协议的格式保存, 因此AOF
文件的内容非常容易被人读懂, 对文件进行分析(parse
)也很轻松。AOF
文件是一个只进行追加操作的日志文件(append only log
), 因此对AOF
文件的写入不需要进行seek
, 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等),redis-check-aof
工具也可以轻易地修复这种问题。
(2)缺点:
- 对于相同的数据集来说,
AOF
文件的体积通常要大于快照RDB
文件的体积大,因为RDB
只存储数据,而AOF
中的写指令,既包含指令,也包含数据; - 如果
AOF
体积太大,那么恢复数据将要花费较长的时间,因为需要重做指令;
2.10 选择快照还是AOF?
说到这里,可能就有人要问了,在实际生产中,我们应该使用快照持久化还是AOF
持久化呢?
1、如果希望自己的数据库有很高的安全性,则应该两者同时使用,AOF
用作精确记录,而快照用作数据备份,前面也说过,快照非常适合用来做数据备份,因为它只存储数据库中的数据,并且经过了压缩,而且它恢复Redis
数据的速度一般要快于AOF
;
2、如果可以容忍一段时间内的数据丢失,则可以考虑只使用快照持久化,减小服务器的开销;
值得一提的是,如果我们同时开启了快照持久化和AOF
持久化,Redis
在重启后,会优先选择AOF
来恢复数据,因为一般情况下,AOF
能够更加完整地恢复数据。
三、总结
快照持久化和AOF
持久化各有优劣,在实际生产环境中,我们一般是两者配合使用,快照持久化消耗较低,而且适合用于备份,但是会丢失一段时间的数据;AOF
持久化更加地耐久,可靠性更高,但是开销可能相对较高。以上就对Redis
的持久化机制做了一个比较详细的介绍,相信看完只后,对Redis
会有一个更加深入的理解。
四、参考
- 《Redis实战》
- Redis官方文档——持久化
详细分析Redis的持久化操作——RDB与AOF的更多相关文章
- Redis:持久化之RDB和AOF
Redis:持久化之RDB和AOF RDB(Redis DataBase) 在指定的时间间隔内将内存中的数据集快照写入硬盘 也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里. R ...
- 分布式缓存Redis的持久化方式RDB和AOF
一.前言 Redis支持两种方式的持久化,RDB和AOF.RDB会根据指定的规则“定时”将内存中的数据存储到硬盘上,AOF会在每次执行命令后将命令本身记录下来.两种持久化方式可以单独使用其中一种,但更 ...
- Redis持久化操作RDB和AOF 对比于HDFS的SecondaryNode
写在前面的话 最近学习比较多流行的大数据框架和完成两个大数据项目后,又突然学起了Redis.之所以之前的框架不学习记录呢,是因为之前的学习都是为了完成参加服创比赛的项目所以时间较紧,现在基本架构和编码 ...
- Redis系列(三):Redis的持久化机制(RDB、AOF)
本篇博客是Redis系列的第3篇,主要讲解下Redis的2种持久化机制:RDB和AOF. 本系列的前2篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安装. Redis系列(二): ...
- redis的持久化方式RDB和AOF的区别
1.前言 最近在项目中使用到Redis做缓存,方便多个业务进程之间共享数据.由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能, ...
- 11、Redis的持久化(RDB、AOF)
写在前面的话:读书破万卷,编码如有神 --------------------------------------------------------------------------------- ...
- redis的持久化(RDB与AOF)
1.为什么redis要实现持久化? 避免因宕机.断电等场景导致进程退出后数据丢失,如果redis的数据都只存放于内存,那么进程退出后数据就丢失了.持久化机制可以持久化内存数据到硬盘,重启redis后基 ...
- Redis数据持久化(RDB、AOF)
1. 简介 Redis作为内存型数据库,数据都保存在内存中,如果重启或意外宕机后,数据会全部丢失.因此,Redis提供了完善的持久化机制,将内存中的数据持久化到磁盘上,避免了完整性和安全性的问题, ...
- Redis 之持久化(rdb、aof)
Redis的持久化有2种方式 1快照 2是日志 测试aof:
随机推荐
- nginx IF 指令
变量名可以使用"="或"!="运算符 ~ 符号表示区分大小写字母的匹配 "~*"符号表示不区分大小写字母的匹配 "!"和 ...
- javax.el.PropertyNotFoundException: 类型[cn.cqsw.pojo.Course]上找不到属性[CourseId]
今天在JSP利用EL表达式取值报了 "javax.el.PropertyNotFoundException” 1 Caused by: org.apache.jasper.JasperExc ...
- js之for与forEach循环的区别
回武汉打卡第四天,武汉加油,逆战必胜!今天咱们探讨一下for循环和forEach()循环的区别. 首先,for循环在最开始执行循环的时候,会建立一个循环变量i,之后每次循环都是操作这个变量,也就是说它 ...
- 用全站 CDN 部署 Discourse 论坛
Discourse 介绍 Discourse 是一款由 Stack Overflow 的联合创始人--Jeff Atwood,基于 Ruby on Rails 开发的开源论坛.相较于传统论坛,Disc ...
- [一、Jmeter5安装及环境配置]
前言:Jmeter基于Jave底层开发,需要配置Java运行时环境 第一步:首先从Jmeter的官网下载Jmeter,Oracle官网下载Jave; Apache JMeter 5.2.1(需要Jav ...
- 第一次将本地项目push到github
问题:github有一个空项目,将本地项目上传到github空项目时,报错如下 $ git push --set-upstream git@github.com:dslu7733/promise.gi ...
- HTML+CSS:css定位详解之相对定位、绝对定位和固定定位
相对定位 如果想为元素设置层模型中的相对定位,需要设置position:relative;,它还是会占用该元素在文档中初始的页面空间,通过left.right.top.bottom属性确定元素在正常文 ...
- html 中video标签视频不自动播放的问题
有个需求,客户想做个打开官网自动播放一段视频,楼主使用了video标签,即下面的代码::于是我在video标签上添加了属性 autoplay=“autoplay” loop=“loop”然而通过地址栏 ...
- 1006 Sign In and Sign Out (25 分)
At the beginning of every day, the first person who signs in the computer room will unlock the door, ...
- Linux 定时实行一次任务命令
当我们想在指定的时间自动执行 一次 任务的时候,可以使用at命令 启动服务 使用时首先检查atq的服务是否启动 service atd status # 检查atd的状态 service atd st ...