redis的持久化存储策略
redis是一个高性能的缓存数据库,既然是缓存,它的数据就是存储在内存中的,如果说服务器断电了, 或者重启了,或者redis宕机了,他的数据就一定会丢失,所以为了解决这个问题,在丢失数据之前就将数据给持久化保存到磁盘,这种持久化技术,就是RDB和AOF
什么是RDB
redis Database 的简写,是将redis内存中的数据保存为一个快照文件,类似Jmap的dump堆转储功能,但rdb是时点性的,只能存储某一时刻的快照,不能实时存储,如果单单使用rdb,它的数据就一定会丢失;
RDB优点
- 以快照的方式存储,所以恢复速度相对较快,
- 不支持拉链式的快照,也就是说,生成的快照文件永远只有一个;
RDB缺点
- 因为是时点性的,在持久化时将数据保存到磁盘需要一定的时间,在这段时间内可能会有其他的写操作,所以容易丢失数据
持久化触发方式
RDB的持久化触发方式有2种,分别为手动触发和自动触发,手动触发只需要登陆redis后输入相应的命令即刻,自动触发需要配置持久化的规则;
1、手动触发RDB
手动触发RDB持久化方式的命令有2种,分别是阻塞和异步:
save
:执行save命令后redis进入阻塞状态,在RDB生成快照期间,redis不能执行其他命令,直到RDB完成方可解除阻塞状态;bgsave
:执行bgsave命令后,redis会以异步的方式进行持久化操作,以fork的方式创建一个子进程(注意是进程,不是线程);RDB持久化操作由子进程负责,完成后自动结束子进程;在异步持久化期间,redis可以正常执行命令;不会有任何影响;阻塞只发生在fork阶段,一般时间很短
注意事项
- 在命令行登录redis后输入
save
或者bgsave
即可持久化存储; - 基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。
- 执行执行
flushall
命令,也会产生dump.rdb快照文件,但里面是空的.
2、自动触发RDB
先进入redis目录,打开redis.conf配置文件,找到以下几项配置:
rdbcompression yes
:默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。rdbchecksum yes
:默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
dbfilename dump.rdb
: 设置快照的文件名,默认是 dump.rdbdir /usr/local/redis/rdb
: 设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。
自动触发RDB的持久化条件
save ""
:如果不想要使用RDB,可以使用此配置关闭 RDB功能save 900 1
: 900 秒内如果至少有 1 个 key 的值变化,则进行持久化保存save 300 10
: 300 秒内如果至少有 10 个 key 的值变化,则进行持久化保存save 60 10000
:60 秒内如果至少有 10000 个 key 的值变化,则进行持久化保存
bgsave底层原理
前置知识 - linux的fork函数、copy on write(流程图)
在了解异步RDB原理之前,我们需要先了解fork是个什么玩意;
调用fork函数后,linux会创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
在克隆时,需要满足2个条件,
- 速度要快
- 占用内存空间要小
为了满足以上2点要求,linux使用了copy on write机制(写入时复制),也就是说,虽然是克隆了2一个子进程出来,但是父子进程种变量的内存指针还是指向同一个内存空间,比如一开始都父子进程的变量A的值都是123
,但我修改子进程变量A的值时,改为456
,那么操作系统会先在内存写入新的值456
,然后在将子进程的变量A指向新的内存值456
;
克隆后的进程为子进程,常规情况下,子进程和主进程之间的数据完全隔离;互不影响;子进程的修改不会破坏父进程,父进程的修改也不会破坏子进程;
bgsave原理(流程图)
在输入bgsave
命令后,redis在内部做了以下几件事
- 通过fork函数创建一个子进程;此方法会产生阻塞,但时间很短;
- redis的增删改查由父进程负责;
- 持久化RDB由子进程负责;
- 持久化完成后,子进程自动结束;
AOF
append only file的简写,意思是只会向文件追加,指的是客户端对redis的增、删、改操作,会以追加的形式将操作语句保存到文件中;
AOF优点
- 恢复时丢失数据少
- RDB和AOF可同时开启;在4.0以前恢复时只用aof恢复;4.0以后使用混合型的持久化机制,下文会介绍
AOF缺点
- 速度较慢,每次写操作都会写磁盘;
rewrite机制(重写)
为什么需要rewrite
我们都知道磁盘空间是有限的,但是redis的增删改的命令却是无穷无尽的,为了保证磁盘不被占满,就需要引入rewrite机制;在命令行输入以下指令即可触发rewrite重写AOF文件;
BGREWRITEAOF
rewrite原理
rewrite机制是自动触发的,需要设定一个阈值,也就是你的aof文件大小的阈值,比如我设置大小为64M时,当aof文件大小达到64M就会自动触发rewrite机制,会对aod文件做些优化,去掉一些过程重复的命令;比如我连续执行了下面的命令
set name yexindong
set name zhangsan
set name lisi
那其实,name
最终的结果是lisi
,也就是第三个命令,第一个和第二个执不执行都不会影响最终的结果,所以当aof文件叨叨64M时,rewrite原理触发,就会将下面的语句删除
set name yexindong
set name zhangsan
最后只保留set name lisi
的语句;去掉中间没用的语句,优化就完成了;经过这一次瘦身,aof文件就会变得更小了;
AOF使用
同样的,AOF也需要在配置文件中进行相关配置;
appendonly no
: 默认值为no,也就是说redis 默认使用的是rdb方式持久化,如果想要开启 AOF 持久化方式,需要将 appendonly 修改为 yes。
appendfilename "appendonly.aof"
:AOF文件名称,配置后,就会将写指令追加到这个文件内dir /usr/local/redis/rdb
: AOF文件的保存目录,与RDB一致appendfsync
:aof持久化策略的配置;no
:表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全;always
:表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低;everysec
:(默认的)表示每秒执行一次fsync,可能会导致丢失这1s数据。通常选择 everysec ,兼顾安全性和效率。
no-appendfsync-on-rewrite
:在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。 设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。Linux的默认fsync策略是30秒。可能丢失30秒数据。默认值为no。auto-aof-rewrite-percentage
:默认值为100。这个值是个百分比的数值,aof自动重写配置,当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定大小的时候,Redis能够调用bgrewriteaof对日志文件进行重写(rewrite)。当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写(rewrite)过程。auto-aof-rewrite-min-size
:64mb。设置允许重写(rewrite)的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写(rewrite)。aof-load-truncated
:aof文件可能在尾部是不完整的,当redis启动的时候,aof文件的数据被载入内存。重启可能发生在redis所在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项,出现这种现象 redis宕机或者异常终止不会造成尾部不完整现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择的是yes,当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-check-aof修复AOF文件才可以。默认值为 yes。
aof使用注意事项
要使用AOF功能,在启动时不能直接运行redis-server
。一定要加配置文件运行./redis-server /etc/redis/redis.conf
,加了配置文件后AOF功能才会生效
AOF文件内容说明
首先我们执行下面这个命令,看看aof文件中都保存了哪些东西;
set k1 hello
然后通过命令打开aof文件 vim appendonly.aof
,可以看到以下内容
*2 // *开头表示是一个新命令,这个命令有2个元素组成
$6 // $开头表示下一行命令的字符长度
SELECT // 选择库的指令,redis有16个库:0~15之间
$1
0 // 和上面的命令组成为:SELECT 0,表示选择0号库
*3 // 下一个命令,这个命令有3个元素组成
$3 // 下一行的命令长度
set // set命令
$2
k1 // key 的名称
$5
hello // key的值,和上面2个命令组成:set k1 hello
Redis是如何进行持久化的(流程图)
在reids4.0的以后,提供了一种混合型的持久化机制,就是RDB + AOF的持久化方式;在配置文件中会有以下配置,设置为yes表示开启,设置为no表示禁用。默认为yes
aof-use-rdb-preamble yes
当开启混合持久化时,主进程先fork出子进程将现有内存副本全量以RDB方式写入aof文件中,然后将缓冲区中的增量命令以AOF方式写入aof文件中,写入完成后通知主进程更新相关信息,并将新的含有 RDB和AOF两种格式的aof文件替换旧的aof文件。
也就是说,RDB 和 AOF文件是在同一个文件里面的,在进行备份的时候,比如是2点整进行备份的,先将这个文件先删除掉,然后将当前的数据以RDB快照的方式保存到aof文件种,最后,以增量的方式将增、删、改命令追加到AOF文件中;这样就可以保证重启或者断电后,恢复数据会保持和断电前一致了;
简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。
这种方式优点我们很好理解,缺点就是不能兼容Redis4.0之前版本的备份文件了。
数据恢复
启动redis时,redis会自动加载rbd文件和 aof文件进行数据恢复;前提是得先开启相应的配置后才会恢复数据,配置如下
# 开启 AOF 持久化配置
appendonly yes
# 开启 RDB持久化配置
rdbcompression yes