序言
在之前的文章种主要介绍了redis的基础部分。在memcache和redis对比中,redis提供可靠的数据持久化方案,而memcache没有数据持久化方案。在这篇文章种我将详细介绍redis所提供的持久化方案:RDB持久化和AOF持久化以及redis新特性混合持久化。
redis的持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复。理解掌握持久化机制对于我们学习redis非常重要。
RDB持久化
RDB持久化方式是通过快照(snapshotting)完成的,当符合一定条件时,redis会自动将内存中所有数据以二进制方式生成一份副本并存储在硬盘上。当redis重启时,在AOF持久化未开启的,redis会读取RDB持久化生成的二进制文件(默认名称dump.rdb
,可通过设置dbfilename
修改)进行数据恢复,对于持久化信息可以用过命令info Persistence
查看。
触发机制(分为:手动命令触发和自动触发)
手动触发RDB生成快照分别对应save和bgsave命令
(1)save
:该命令是强制redis执行快照,这时候redis处于阻塞状态,不会响应任何其他客户端发来的请求,直到RDB快照文件执行完毕,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用(谨慎使用)
(2)bgsave
:bgsave命令可以理解为background save即:“后台保存”。当执行bgsave命令时,redis会fork出一个子进程来执行快照生成操作。需要注意的redis是在fork子进程这个简短的时间redis是阻塞的(此段时间不会响应客户端请求),当子进程创建完成以后redis才可以响应客户端请求。(注:
rdb自动触发其实也是使用bgsave来完成的)。下面的图主要是bgsave工作过程:
(1)执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接返回。
(2)父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位为微秒
(3)父进程fork完成后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。
(4)子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后 对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
(5)进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence下的rdb_*相关选项。
自动触发RDB的生成快照
(1)使用save相关配置,如“save m n”。表示m秒内数据集存在n次修改 时,自动触发bgsave
//在redis.conf中配置
save 900 1
save 300 10
save 60 10000
(2)shutdown
命令触发就是redis在关闭前处于安全角度将所有数据全部保存下来,以便下次启动会恢复
(3)客户端执行数据库清空命令flushall
时候,触发快照保存rdb文件
(4)主从复制
时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照保存rdb文件
故障恢复
当redis意外崩溃或者关闭再次启动时,此时AOF持久化未开启时(默认未开启),将使用RDB快照文件恢复数据:
(1)首先我们关闭redis,然后在配置文件中添加log文件的地址:
(2)我们再启动redis,启动完成后,我可以查看log文件,可以看到加载了rdb文件:
RDB持久化的配置
#save 900 1 900秒内至少有1个key被改变则做一次快照
#save 300 10 300秒内至少有300个key被改变则做一次快照
#save 60 10000 60秒内至少有10000个key被改变则做一次快照
#关闭该规则使用svae “”
save m n
#rdb持久化存储数据库文件名,默认为dump.rdb
dbfilename dump.rdb
#yes代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no表明忽略错误继续写文件
stop-write-on-bgsave-error yes
#在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动
rdbchecksum yes
#数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限
dir /usr/local/bin
#是否开启RDB文件压缩,该功能可以节约磁盘空间
rdbcompression yes
AOF持久化
AOF(append only file)持久化,以独立日志的方式记录每次写命令, 重启时再重新执行AOF文件中的命令达到恢复数据的目的。它可以将Redis执行的每一条写命令追加到磁盘文件(appendonly.aof)中,在redis启动时候优先选择从AOF文件恢复数据。由于每一次的写操作,redis都会记录到文件中,所以开启AOF持久化会对性能有一定的影响,但是大部分情况下这个影响是可以接受的,我们可以使用读写速率高的硬盘提高AOF性能。与RDB持久化相比,AOF持久化数据丢失更少,其消耗内存更少(RDB方式执行bgsve会有内存拷贝)。AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。
开启AOF
在默认的配置文件中,redis是关闭了AOF持久化,开启AOF通过配置appendonly为yes开启,我们修改配置文件或者在命令行直接使用config set修改,在用config rewrite同步到配置文件。(通过客户端修改好处是不用重启redis,AOF持久化直接生效
)
[root@izbp19p16mcz7awt4d8kahz bin]# redis-cli
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "no"
127.0.0.1:6379> config set appendonly yes
OK
127.0.0.1:6379> config rewrite
OK
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "yes"
AOF持久化过程
主要分为以下几个阶段:
(1)文件写入(append)
:redis将每一条写命令添加至缓冲区aof_buf,采用缓冲区暂存一部分命令随后根据策略一次性写入磁盘,这样可以减少磁盘的I/O次数,提高了性能
(2)文件同步(sync)
:当写命令写入aof_buf缓冲区后,redis会将缓冲区的命令写入到文件,redis提供了三种同步策略,由配置参数appendfsync决定,下面是每个策略所对应的含义:
//表示每次有写操作都调用fsync方法强制内核将数据写入到aof文件。这种情况下由于每次写命令都写到了文件中, 虽然数据比较安全,但是因为每次写操作都会同步到AOF文件中,所以在性能上会有影响,同时由于频繁的IO操作,硬盘的使用寿命会降低(速度慢)
# appendfsync always
//使用fsync每秒一次从内核刷新到磁盘,这种方式兼顾了性能和数据安全,所以redis默认推荐使用该配置。
# appendfsync everysec
//不同步,这时操作系统自己同步,在linux操作系统中大约每30秒刷一次缓冲。这种情况下,缓冲区数据同步不可控,并且在大量的写操作下,aof_buf缓冲区会堆积会越来越严重,一旦redis出现故障,数据丢失严重
# appendfsync no
(3)文件重写(rewrite)
:随着AOF文件会越来越大,需要定期对AOF文件进行重写,达到压缩的目的,redis将使用bgrewriteaof
对AOF文件进行重写。
文件重写
(1)为什么重写?
举一个例子:先后执行了set k1 v1 set k2 v2 set k3 v3
此时AOF文件会记录三条命令,这显然不合理,因为前面的set命令都是多余的,下面是一些列举一些重写策略
:
(1)重复或无效的命令不写入文件
(2)过期的数据不再写入文件
(3)多条命令合并写入(比如上面的例子set k1 v1 set k2 v2 set k3 v3)
(2)重写的触发条件(AOF文件重写触发条件可分为手动触发和自动触发
)
-
手动触发:客户端执行
bgrewriteaof
命令。 -
自动触发:自动触发通过以下两个配置协作生效:
(1)AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,这里默认配置64mb auto-aof-rewrite-min-size 64mb (2)当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写 auto-aof-rewrite-percentage 100
-
redis在开启AOF的情况下,会维持以下三个变量:
aof_current_size:记录当前AOF文件大小的变量 aof_rewrite_perc:记录最后一次AOF重写之后,AOF文件大小的变量 aof_rewrite_base_size:增长百分比变量
-
如果下面条件全部满足的话,就触发自动的AOF重写操作:
(1)没有BGSAVE命令(RDB持久化)/AOF持久化在执行; (2)没有BGREWRITEAOF在进行; (3)当前AOF文件大小要大于server.aof_rewrite_min_size设置的值; (4)当前AOF文件大小和最后一次重写后的大小之间的比率等于或者大于指定的增长百分比(auto-aof-rewrite-percentage参数)
(3)重写的过程(图和解析)
数据恢复(相比rdb优先使用AOF进行恢复)
当AOF开启时候,redis数据恢复优先选用AOF进行数据恢复,下面我们关闭redis再重启,看日志文件:
AOF配置参数
#AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写
auto-aof-rewrite-min-size 64mb
#当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写
auto-aof-rewrite-percentage 100
#表示每次有写操作都调用fsync方法强制内核将数据写入到aof文件。这种情况下由于每次写命令都写到了文件中, 虽然数据比较安全,但是因为每次写操作都会同步到AOF文件中,所以在性能上会有影响,同时由于频繁的IO操作,硬盘的使用寿命会降低(速度慢)
appendfsync always
#使用fsync每秒一次从内核刷新到磁盘,这种方式兼顾了性能和数据安全,所以redis默认推荐使用该配置。
appendfsync everysec
#不同步,这时操作系统自己同步,在linux操作系统中大约每30秒刷一次缓冲。这种情况下,缓冲区数据同步不可控,并且在大量的写操作下,aof_buf缓冲区会堆积会越来越严重,一旦redis出现故障,数据丢失严重
appendfsync no
#当redis突然运行崩溃时,会出现aof文件被截断的情况,Redis可以在发生这种情况时退出并加载错误,以下选项控制此行为
#如果aof-load-truncated设置为yes,则加载截断的AOF文件,Redis服务器启动发出日志以通知用户该事件
#如果该选项设置为no,则服务将中止并显示错误并停止启动。当该选项设置为no时,用户需要在重启之前使用“redis-check-aof”实用程序修复AOF文件在进行启动
aof-load-truncated yes
#yes开启AOF,no关闭AOF
appendonly no
#指定AOF文件名
appendfilename appendonly.aof
#RDB文件和AOF文件存放目录
dir /usr/local/bin
RDB-AOF混合持久化
前面已经详细介绍了AOF持久化以及RDB持久化,这里介绍的混合持久化就是同时结合RDB持久化以及AOF持久化混合写入AOF文件
。这样做的好处是可以结合 rdb 和 aof 的优点, 快速加载同时避免丢失过多的数据
,缺点是 aof 里面的 rdb 部分就是压缩格式不再是 aof 格式
,可读性差。
开启混合持久化
通过aof-use-rdb-preamble
配置参数控制,yes则表示开启,no表示禁用,默认是开启的,可通过config set
修改
混合持久化过程
混合持久化同样也是通过bgrewriteaof
完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件
,然后在将重写缓冲区的增量命令以AOF方式写入到文件
,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件
。(新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据)
数据恢复
当我们开启了混合持久化时,启动redis依然优先加载aof文件,aof文件加载可能有两种情况如下:
(1)aof文件开头是rdb的格式, 先加载 rdb内容再加载剩余的 aof
(2)aof文件开头不是rdb的格式,直接以aof格式加载整个文件
优缺点
RDB
:
优点:
(1)RDB 是一个非常紧凑(compact)的文件,体积小,因此在传输速度上比较快,因此适合灾难恢复
(2)RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作
(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快
缺点:
(1)RDB是一个快照过程,无法完整的保存所以数据,尤其在数据量比较大时候,一旦出现故障丢失的数据将更多
(2)当redis中数据集比较大时候,RDB由于RDB方式需要对数据进行完成拷贝并生成快照文件,fork的子进程会耗CPU,并且数据越大,RDB快照生成会越耗时
(3)RDB文件是特定的格式,阅读性差,由于格式固定,可能存在不兼容情况
AOF
:
优点:
(1)数据更完整,秒级数据丢失(取决于设置fsync策略)
(2)兼容性较高,由于是基于redis通讯协议而形成的命令追加方式,无论何种版本的redis都兼容,再者aof文件是明文的,可阅读性较好
缺点:
(1)数据文件体积较大,即使有重写机制,但是在相同的数据集情况下,AOF文件通常比RDB文件大
(2)相对RDB方式,AOF速度慢于RDB,并且在数据量大时候,恢复速度AOF速度也是慢于RDB
(3)由于频繁地将命令同步到文件中,AOF持久化对性能的影响相对RDB较大,但是对于我们来说是可以接受的
混合持久化
:
优点:
(1)混合持久化结合了RDB持久化 和 AOF 持久化的优点, 由于绝大部分都是RDB格式,加载速度快,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。
缺点:
(1)兼容性差,一旦开启了混合持久化,在4.0之前版本都不识别该aof文件,同时由于前部分是RDB格式,阅读性较差