[redis学习笔记]四、Redis的持久化操作

Redis的持久化

RDB(Redis DataBase)

原理

在指定的时间间隔内将内存中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存里。

原理:Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都接收了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。

fork的作业是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。

如果需要进行大规模数据的回复,且对于数据恢复的完整性不是那么敏感,那么RDB方式要更高效。

**RDB缺点:最后一次持久化后的数据可能丢书,无法写入到硬盘。**因为RDB规则是当在多长时间内有多少次更新操作时才触发数据同步。如果刚同步一次数据后,此时Redis仍在进行写入操作,但是未达到触发数据同步的条件,此时Redis服务崩溃,那么这些写入数据则不能同步到文件中。

rdb默认保存的是dump.rdb文件,可通过Redis.conf进行配置

如何触发RDB快照

为了方便举例,将save规则进行更改:

save 900 1
save 300 10
## 更改为20秒内5次写入操作即保存
save 20 5

示例:

## redis_conf 默认dir为redis服务的启动目录 ./;现在可以发现这目录是空的
test_redis ls
## 在test_redis下启动redis服务
➜  test_redis sudo /usr/local/bin/redis-server ~/redis/redis_bak.conf
Password:
➜  test_redis redis-cli -h 127.0.0.1 -p 6379  -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> set k3
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set k3 v3
OK
127.0.0.1:6379> set k4 v4
OK
127.0.0.1:6379> set k5 v5
OK

在20s内执行了5次写入操作,发现生成dump.rdb文件

在这里插入图片描述

Redis.log是配置的Redis启动日志文件

也可以通过命令立即执行一次数据同步操作

  • save

    save时只管保存,其他不管,会阻塞其他命令的执行。如果save执行过程较长,那么其他客户端在save命令后执行了其他命令,那么其他命令会阻塞至save执行完毕。

    举例:

    ## 这里再进行一次 写入操作 时间点10:23 这里应该不符合任何配置的save条件,不会同步数据
    127.0.0.1:6379> set k6 v6
    OK
    ## 手动保存
    127.0.0.1:6379> save
    OK
    ## 查看最后一次快照执行成功的时间
    127.0.0.1:6379> LASTSAVE
    (integer) 1580696630 ## 转换过来是Mon Feb 03 2020 10:23:50 GMT+0800 (中国标准时间)
    

​ 观察dump.rdb文件的变化:

在这里插入图片描述

​ 发现立即执行了一次数据同步。

  • bgsave

    Redis会在后台异步进行快照操作,在进行快照的同时,Redis还可以响应客户端的请求。通过lastsave命令可以获取最后一次成功执行快照的时间

    这里不再举例

  • flushall、flushdb

    这两个命令分别是清空所有库以及当前库。执行这些命令,会立即进行快照,但由于这些命令时清空操作,所以快照文件内容为空。

    在这里插入图片描述

    可以看到执行了flushall之后,即使立刻进行了快照,但是快照文件是空的,再重新启动服务也加载不到数据了。

如何恢复数据

只要运行Redis-server服务的目录下有该备份文件,即可在启动Redis服务时加载到文件中的数据。

config get dir --获取Redis配置的目录

如我在test_Redis下启动Redis服务,

➜  test_redis sudo /usr/local/bin/redis-server ~/redis/redis_bak.conf
➜  test_redis redis-cli -h 127.0.0.1   -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set k6 v6
OK
127.0.0.1:6379> set k7 v7
OK
127.0.0.1:6379> set k8 v8
OK
127.0.0.1:6379> set k9 v9
OK
127.0.0.1:6379> set k10 v10
OK
127.0.0.1:6379> LASTSAVE
(integer) 1580698473
## 停止服务
127.0.0.1:6379> SHUTDOWN
not connected> exit
➜  test_redis clear
## 重新启动服务
➜  test_redis sudo /usr/local/bin/redis-server ~/redis/redis_bak.conf
➜  test_redis redis-cli -h 127.0.0.1   -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
## 加载到这些文件了
127.0.0.1:6379> keys *
1) "k9"
2) "k10"
3) "k8"
4) "k7"
5) "k6"
127.0.0.1:6379>

如果第一次我在test_Redis目录下启动的服务并进行写入操作,那么文件会生成在该目录下。如果第二次我在别的目录下启动服务,能否加载到刚才写入的操作,要看别的目录下是否有dump.rdb以及是否是我们在test_Redis下的那个文件,否则可能服务启动时加载不到任何数据或者加载的是其他dump.rdb文件的数据

禁用RDB保存规则
  1. 在Redis.conf文件中 配置 save “”
  2. 在Redis-cli里执行命令:config set save “”
总结

在这里插入图片描述

优点:

适合大规模的数据恢复;对数据完整性和一致性要求不高

缺点:

在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就

会丢失最后一次快照后的所有修改。

RDB经常需要fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork过程很耗时,可能导致Redis在一些毫秒级上不能响应客户端的请求。fork的时候,内存中的数据会被克隆一份,陡增的内存开销需要考虑。

注意:如果rdb文件有损坏,可以使用redis-check-rdb来修复,示例如下:

➜  bin redis-check-rdb  ~/test_redis/dump.rdb
[offset 0] Checking RDB file /Users/wojiushiwo/test_redis/dump.rdb
[offset 26] AUX FIELD redis-ver = '5.0.0'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1580699961'
[offset 67] AUX FIELD used-mem = '1038144'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 92] Checksum OK
[offset 92] \o/ RDB looks OK! \o/
[info] 0 keys read
[info] 0 expires
[info] 0 already expired

AOF(Append Only File)

原理

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录)。只追加文件不可以改写文件,Redis启动之初会读取该文件重新构建数据。换言之,Redis重启的话就根据日志文件的内容将写指令从前向后执行一次以完成数据的恢复。

默认AOF保存的是appendonly.aof文件,可在Redis.conf中配置。

使用

启动AOF配置

在Redis.conf中 修改默认的appendonly no,改为yes

恢复数据

将有数据的aof文件复制一份保存到对应目录(Redis.conf中配置的dir的目录,如果配置的是./ 则将aof文件复制到启动Redis服务的目录下),重启Redis即可加载到aof文件数据

举例:

## 启动服务,会立刻生成一个文件appendonly.aof
➜  test_redis sudo /usr/local/bin/redis-server ~/redis/redis_bak.conf
Password:
➜  test_redis redis-cli -h 127.0.0.1   -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
(empty list or set)
## 默认aof策略是每秒备份一次 所以下面的写操作会被备份到aof文件中
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
## 停止服务
127.0.0.1:6379> SHUTDOWN
not connected> exit
## 重启服务
➜  test_redis sudo /usr/local/bin/redis-server ~/redis/redis_bak.conf
➜  test_redis redis-cli -h 127.0.0.1   -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
## 从aof文件中加载到数据
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379>

查看下aof文件的内存:

*2
$6
SELECT
$1
0
*3
$3
set
$2
k1
$2
v1
*3
$3
set
$2
k2
$2
v2

可以看到确实是以日志模式记录下写操作。

但是如果aof文件被写坏了,我们看还能不能正常的恢复数据:

在aof文件中写入随机内容,如下

*2
$6
SELECT
$1
0
*3
$3
set
$2
k1
$2
v1
*3
$3
set
$2
k2
$2
v2
sdbjakdbsabdsakdbsajkk

重启服务

➜  test_redis sudo /usr/local/bin/redis-server ~/redis/redis_bak.conf
Password:
➜  test_redis ps -ef |grep redis
  501 21743 16955   0 11:38上午 ttys001    0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn redis

发现服务并没有起来,查看Redis.log日志,日志中有如下提示:

21734:M 03 Feb 2020 11:38:33.453 # Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

意思是说我们的aof文件已经损坏,需要修复。

因此得出结论,aof文件被写坏了不仅不能恢复数据,连服务都起不来

接下来,修复aof文件,修复语句:redis-check-aof --fix 目录下的appendonly.aof

示例:

## 修复aof文件
➜  test_redis sudo /usr/local/bin/redis-check-aof --fix appendonly.aof
0x              51: Expected prefix '*', got: 's'
AOF analyzed: size=105, ok_up_to=81, diff=24
This will shrink the AOF from 105 bytes, with 24 bytes, to 81 bytes
Continue? [y/N]: y
## 修复成功
Successfully truncated AOF
➜  test_redis sudo /usr/local/bin/redis-server ~/redis/redis_bak.conf
➜  test_redis redis-cli -h 127.0.0.1   -p 6379 -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
## 数据被再次加载进来
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
127.0.0.1:6379>

再次查看aof文件内容:

*2
$6
SELECT
$1
0
*3
$3
set
$2
k1
$2
v1
*3
$3
set
$2
k2
$2
v2

发现刚才那些随机内容已经被删除了。

rewrite

AOF采用文件追加的方式,文件会越来越大。为了避免这种情况,新增了重写机制。当AOF文件的大小超过设定的阈值时,reids就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。也可以使用命令来完成:bgrewriteaof

原理:

AOF文件持续增长而过大时,会fork出一条新进程将文件重写(先写进一个临时文件,待写完后将临时文件更名为appendonly.aof),遍历新进程的内存中的数据,每条记录有一条set语句。重写aof文件的操作并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写到了一个新的aof文件中

触发机制:

Redis.conf中配置的auto-aof-rewrite-min-size、auto-aof-rewrite-percentage即是触发的条件。

Redis会记录上次重写的AOF文件大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

总结

在这里插入图片描述

AOF文件是一个只进行追加的日志文件,Redis可以在aof文件体积变得过大时,自动地在后台对AOF进行重写。

AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作已Redis协议的格式保存,因此AOF文件的内容很容易被人读懂。

对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积,根据所使用的同步策略,AOF的恢复速度和运行效率会慢于RDB。AOF的appendfsync everysec策略效率较好,appendfsync no策略效率和RDB相当。

Redis的持久化总结

RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。

AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Redis协议追加保存每次写的操作到文件末尾。Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

同时开启两种持久化方式

在这种情况下,当Redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。

由于AOF的特点是文件在不断变化不好备份,因此RDB更适合用于备份数据库。

建议只在slave上持久化RDB文件,设置15分钟备份一次即可

如果配置中也开启了AOF,优势是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价:

  1. 带来了持续的IO(服务重启时会加载aof文件,相当于将aof文件中的命令重新执行了一次)。
  2. AOF rewtire中将产生的新数据写入新文件造成的阻塞几乎是你不可避免的。因此应当尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了(可能会经常性的超过这个阈值而进行rewrite)。默认超过原大小100%时重写也可以改为一个适当的数值。

如果不开启AOF,依靠主从赋值也可以实现高可用,能省掉一大笔IO也减少了rewrite时带来的系统波动。但是如果主从都崩溃的话,会丢失一段时间的数据(重新启动时要比较主从rdb文件选择最新的一个)。

发布了116 篇原创文章 · 获赞 23 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/zyxwvuuvwxyz/article/details/104164008