Redis 持久化
Redis 是内存数据库,我们也知道内存中的数据在电脑关闭的时候会丢失,所以需要把数据保存到磁盘中,也叫做持久化,预防服务器进程的突然中断或退出。
Redis 提供了两种持久化方式,分别是 RDB 和 AOF。
RDB( Redis DataBase )
在指定的时间间隔内,将内存中的数据集快照写入磁盘。也就是行话讲的 Snapshot(快照),它恢复时,是将快照文件直接读取到内存里。
Redis 会单独创建(fork)出一个子进程进行持久化,会将数据先写入到临时文件中,待持久化过程都结束了,再用这个临时文件替换上次已经持久化好了的文件。整个的过程,主进程没用 IO 操作,确保了高性能。但是缺点是最后一次的持久化可能造成数据丢失,所以 RDB 适合对于数据的完整性不敏感,比 AOF 方式高效。
什么是 Fork:
Fork 的作用就是复制一个和当前一样的进程,新进程的所有数据数值和原进程一样。但是是一个全新的进程,并作为原进程的子进程运行。
RDB 默认保存的是后缀为 .rdb
文件。
配置文件
在 redis.conf
的配置信息大致如下
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
# ...
# ...
# ...
# save ""
save 900 1 # 如果 900s 内,如果至少执行了 1 次的修改操作,则及进行持久化操作
save 100 10 # 如果 100s 内,如果至少执行了 10 次的修改操作,则及进行持久化操作
save 60 10000 # 如果 60s 内,如果至少执行了 10000 次的修改操作,则及进行持久化操作
# ...
# ...
# ...
stop-writes-on-bgsave-error yes # 持久化如果出错,是否还需要继续工作!
# ...
# ...
# ...
rdbcompression yes # 是否压缩 rdb 文件,但是会消耗一些性能
# ...
# ...
# ...
rdbchecksum yes # 保存 rdb 文件的时候,进行错误的检查校验
# The filename where to dump the DB
dbfilename "dump6379.rdb" # 保存的 rdb 文件的名字
# ...
# ...
# ...
dir "./" # rdb 文件保存的目录!
save 900 1
- 如果 900s 内,如果至少执行了 1次的修改操作,则及进行持久化操作
save 100 10
- 如果 100s 内,如果至少执行了 10次的修改操作,则及进行持久化操作
save 60 10000
- 如果 60s 内,如果至少执行了 10000 次的修改操作,则及进行持久化操作
stop-writes-on-bgsave-error yes
- 持久化如果出错,是否还需要继续工作?
rdbcompression yes
- 是否压缩 rdb 文件,但是会消耗一些性能
rdbchecksum yes
- 保存 rdb 文件的时候,进行错误的检查校验
dbfilename dump6379.rdb
- 保存的 rdb 文件的名字
dir "./"
- 默认保存到启动的时候,指定的配置文件的目录下。
怎么玩
以上述的配置启动服务器,那么如何触发
被动触发:
-
save 的规则满足的情况下,会自动触发 rdb 规则
当在 100 s 内执行了 10 次修改的操作,会生成 dump 文件。如下在 100s 内执行 10 次修改操作,就执行了持久化
-
执行 flushall 命令,也会触发我们的rdb规则!
主动触发:
-
执行
save
或bgsave
命令,也会产生 rdb 文件- 注意:
- save时只管保存,其它不管,全部阻塞
- Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过
lastsave
命令获取最后一次成功执行快照的时间
- 注意:
-
shutdown
命令,也会产生 rdb 文件!
如何恢复?
把 rdb 文件放到启动 redis 的启动目录即可(具体是看自己的配置文件,我这里的配置 dir
指定的是当前目录,也就是配置文件存放的目录,并且文件名为 dump6379.rdb
,也就是把文件 dump6379.rdb
拷贝到配置文件的目录下,redis 会根据指定的配置文件,读取 rdb 文件恢复)。
可以通过命令 config get dir
获取到 rdb 文件需要保存或读取的目录
192.168.200.132:6379> config get dir
1) "dir"
2) "/opt/test"
RDB 文件出错怎么办?
如果 rdb 某些情况下,比如突然断电,文件出错该怎么办?Redis 提供了一个工具 redis-check-rdb <filename>
进行修复
[root@wzx test]# redis-check-rdb dump6379.rdb
[offset 0] Checking RDB file dump6379.rdb
[offset 26] AUX FIELD redis-ver = '5.0.4'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1597455491'
[offset 67] AUX FIELD used-mem = '853464'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 119] Checksum OK
[offset 119] \o/ RDB looks OK! \o/
[info] 2 keys read
[info] 0 expires
[info] 0 already expired
如何停止?
动态所有停止RDB保存规则的方法:redis-cli config set save ""
优点
-
适合大规模的数据恢复!
-
对数据的完整性要不高!
-
性能比 AOF 好
缺点
- 需要一定的时间间隔进程操作!如果 redis 意外宕机了,这个最后一次修改数据就没有的了!
- fork 的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
AOF( Append Only File )
AOF 是以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
并且 AOF 默认保存的是 appendonly.aof 文件
配置文件
在 redis.conf
的内容,大概如下
############################## APPEND ONLY MODE ###############################
# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
# ...
# ...
# ...
appendonly no # 默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分所有的情况下,
# ...
# ...
# ...
appendfilename "appendonly.aof" # 持久化的文件的名字
# ...
# ...
# ...
# appendfsync always # 每次修改都会 sync。消耗性能
appendfsync everysec # 每秒执行一次 sync,可能会丢失这1s的数据!
# appendfsync no # 不执行 sync,这个时候操作系统自己同步数据,速度最快!
# ...
# ...
# ...
no-appendfsync-on-rewrite no # 是否在后台写时同步单写,默认值no(表示需要同步)
# ...
# ...
# ...
auto-aof-rewrite-percentage 100 # aof文件增长比例,指当前aof文件比上次重写的增长比例大小。
auto-aof-rewrite-min-size 64mb # aof文件重写最小的文件大小
# ...
# ...
# ...
aof-load-truncated yes # 指redis在恢复时,会忽略最后一条可能存在问题的指令。
# ...
# ...
# ...
aof-use-rdb-preamble yes # 混合持久化 4.0 版本新增
appendonly no
- 默认是不开启 aof 模式的,默认是使用 rdb 方式持久化的,在大部分所有的情况下
appendfilename "appendonly.aof"
- 持久化的文件的名字
appendfsync everysec
- 每秒执行一次 sync,可能会丢失这1s的数据!
no-appendfsync-on-rewrite no
- 是否在后台写时同步单写,默认值no(表示需要同步)
auto-aof-rewrite-percentage 100
- aof文件增长比例,指当前aof文件比上次重写的增长比例大小。
auto-aof-rewrite-min-size 64mb
- aof文件重写最小的文件大小
aof-load-truncated yes
- 指redis在恢复时,会忽略最后一条可能存在问题的指令。
aof-use-rdb-preamble yes
- 混合持久化 4.0 版本新增
怎么玩?
默认的 AOF 是不开启的,需要手动的进行配置,只要在配置文件把 appendonly
改为 yes 就开启了 AOF。
appendonly yes
之后重启 redis 即可生效。接下来输入几条命令
192.168.200.132:6379> set k1 value1
OK
192.168.200.132:6379> set k2 value2
OK
192.168.200.132:6379> keys *
1) "k2"
2) "k1"
192.168.200.132:6379> get k1
"value1"
之后就能在 redis 启动目录下看到 appendonly.aof 文件
[root@wzx test]# ls
appendonly.aof dump63791.rdb log6379.log redis6379.conf
使用 vim appendonly.aof
查看一下,内容如下
可以明确的看到,它只存储了 set 的命令,而 get 等获取信息的命名没用存储。
文件出错怎么办?
如果这个 AOF 文件有错位,这时候 redis 是启动不起来的吗,我们需要修复这个 aof 文件
假设我在文件末尾随便添加一行无关的
这是重启 redis 并连接的时候,会报错
那么该怎么办?redis 给我们提供了一个工具 redis-check-aof --fix 进行修复
[root@wzx test]# redis-check-aof --fix appendonly.aof
结果如下
如何恢复?
将文件放在指定配置文件的启动目录下(具体可以使用 config get dir
来获取哪个目录),文件是正常的,则会自动读取恢复。
重写规则
AOF 默认就是文件的无限追加,文件会越来越大!所以配置文件中有一个参数
auto-aof-rewrite-min-size 64mb
上面的参数,表达的意思就是,如果 AOF 文件大于 64m,超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof
重写原理:
AOF文件持续增长而过大时,会 fork 出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的 Set 语句。重写 AOF 文件的操作,并没有读取旧的 AOF 文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的 AOF 文件,这点和快照有点类似
触发机制:
Redis 会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于64M时触发
优点
-
每一次修改都同步,文件的完整会更加好!
-
每秒同步一次,可能会丢失一秒的数据
-
从不同步,效率最高的!
缺点:
- 相对于数据文件来说,AOF 远远大于 RDB,修复的速度也比 RDB慢!
- AOF 运行效率也要比 RDB慢,所以我们 Redis 默认的配置就是 RDB持久化!
总结
持久化方式 ?
- RDB 持久化方式能够在指定的时间间隔能对你的数据进行快照存储
- AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以 Redis 协议追加保存每次写的操作到文件末尾
如果同时开启两种持久化方式会怎么样?
- 在这种情况下,当redis重启的时候会优先载入 AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
RDB的数据不实时,同时使用两者时服务器重启也只会找 AOF 文件。那要不要只使用 AOF 呢?
- 作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),
- RDB 可以快速重启,而且不会有 AOF 可能潜在的bug,留着作为一个万一的手段。
那么两个性能该如何抉择?
- 因为 RDB 文件只用作后备用途,建议只在 slaveof 上持久化RDB文件,而且只要 15 分钟备份一次就够
了,只保留save 900 1
这条规则。
2. 如果appendonly yes
1. 好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。
2. 代价一是带来了持续的IO,二是 AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 AOF rewrite 的频率
3. AOF 重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小 100%大小时重写,可以改到适当的数值。
3. 如果不appendonly no
1. 使用 Master-Slave Repllcation 实现高可用性也可以,能省掉一大笔 IO,减少了 rewrite 时带来的系统波动。
2. 但是如果 Master-Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB文件,载入较新的那个,微博就是这种架构。