一:为什么需要持久化

因为Redis是一个完全使用内存来存储数据的数据库,如果机器突然断电、服务器重启或进程挂掉了等等原因,那么存储在Redis中的数据就会丢失,从而引起业务的损失。为了保证存储在内存中的数据安全,Redis引入了持久化这个功能。

二:Redis持久化分类

在Redis中,分别为我们提供了 RDB 和 AOF 两种持久化模式。在4.0及以后版本中,提供了一种混合持久化的功能,就是RDB和AOF结合的持久化模式。

1、分类

1.1、RDB

RDB持久化方式是通过快照完成的。RDB程序将当前内存中的数据快照保存到磁盘中,在Redis重启时,RDB程序可以通过载入RDB文件来还原数据库的状态。

1.2、AOF

AOF(append only file),是以独立日志的方式记录每次的写命令,重启时在执行文件中的命令来达到恢复数据的目的。

1.3、混合模式

混合模式就是同时结合了RDB持久化和AOF持久化混合写入AOF文件。这样就可以结合2者的优点了,快速的加载持久化文件,同时避免数据丢失过多。

2、三者的优缺点

RDB1:RDB的持久化文件是一个二进制文件,而且是经过压缩的,代表Redis在某个时间点的数据快照。非常适合备份,全量复制等场景。可以执行bgsave备份,并把RDB文件拷贝到远程机器中,用于灾难恢复
2:因为数据文件小,所以恢复比AOF快很多
1:RDB不能及时的备份,不能实时持久化。所以如果Redis意外down掉,就会丢失最后一次快照后的所有数据

2:RDB是特定的二进制文件格式,Redis的版本兼容很差,也就是说老的RDB无法兼容新的Redis服务器

AOF1:AOF持久化可以进行秒级备份, 可以尽量减少数据丢失的问题,对比RDB不能实时备份1:因为AOF是以日志形式记录每次写操作,所以它的文件比较大,备份恢复时间相比较RDB来说时间要长
混合1:混合模式结合了RDB和AOF的优缺点,快速加载备份文件同时避免过多的数据丢失当然缺点也是有的:就是AOF里面的RDB部分是压缩格式,不是AOF格式,可读性差,当然这个我们一般情况下可以忽略

三:RDB的使用

1、RDB持久化配置

################################ SNAPSHOTTING  ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
# 配置触发RDB快照的规则
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed //900秒内至少有1个key被改变则做一次快照
# after 300 sec (5 min) if at least 10 keys changed //300秒内至少有300个key被改变则做一次快照
# after 60 sec if at least 10000 keys changed //60秒内至少有10000个key被改变则做一次快照
#
# save 900 1
# save 300 10
# save 60 10000
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save "" //关闭触发RDB快照的规则 # The filename where to dump the DB
dbfilename dump.rdb //RDB持久化数据库文件名,默认dump.rdb stop-writes-on-bgsave-error yes //yes:代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no:表明忽略错误继续写文件。 rdbcompression yes //是否开启RDB文件压缩,yes默认开启压缩,no不开启 rdbchecksum yes //在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动 dir ./ //数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限

2、什么时候触发RDB快照

RDB生成快照可以自动触发,也可以用命令手动触发

  1. 客户端执行命令 save 和 bgsave 会生成快照;
  2. 根据配置文件 save m n 规则进行自动快照;
  3. 主从复制时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照;
  4. 客户端执行数据库清空命令FLUSHALL时候,触发快照;
  5. 客户端执行shutdown关闭redis时,触发快照;

save命令
在客户端执行save命令,这个命令强制Redis执行快照,并且会阻塞Redis,此时Reids不会响应任何请求,知道RDB快照执行完毕,所以一般要慎用

bgsave命令
bgsave就是后台执行的命令,执行这个命令时,Redis会fork出一个子进程来执行快照的生成,(注意:fork出子进程这段时间Reids是阻塞的,不会响应客户端的请求),当子进程创建完成后Redis响应客户端请求。
Redis的自动快照也是用这个命令完成的

配置文件save命令
save m n: 指定在m秒内,redis中有n个键发送改变,则自动触发bgsave命令。 就是上面的 RDB 持久化配置redis.conf 里面的

FLUSHALL触发
flushall命令用于清空数据库,请慎用,当我们使用了则表明我们需要对数据进行清空,那redis当然需要对快照文件也进行清空,所以会触发bgsave。

shutdown触发
shutdown命令触发就不用说了,redis在关闭前处于安全角度将所有数据全部保存下来,以便下次启动会恢复

主从复制触发
在redis主从复制中,从节点执行全量复制操作,主节点会执行bgsave命令,并将rdb文件发送给从节点

3、RDB格式规范

----------------------------# RDB is a binary format. There are no new lines or spaces in the file.
52 45 44 49 53 # Magic String "REDIS"
00 00 00 03 # RDB Version Number in big endian. In this case, version = 0003 = 3
----------------------------
FE 00 # FE = code that indicates database selector. db number = 00
----------------------------# Key-Value pair starts
FD $unsigned int # FD indicates "expiry time in seconds". After that, expiry time is read as a 4 byte unsigned int
$value-type # 1 byte flag indicating the type of value - set, map, sorted set etc.
$string-encoded-key # The key, encoded as a redis string
$encoded-value # The value. Encoding depends on $value-type
----------------------------
FC $unsigned long # FC indicates "expiry time in ms". After that, expiry time is read as a 8 byte unsigned long
$value-type # 1 byte flag indicating the type of value - set, map, sorted set etc.
$string-encoded-key # The key, encoded as a redis string
$encoded-value # The value. Encoding depends on $value-type
----------------------------
$value-type # This key value pair doesn't have an expiry. $value_type guaranteed != to FD, FC, FE and FF
$string-encoded-key
$encoded-value
----------------------------
FE $length-encoding # Previous db ends, next db starts. Database number read using length encoding.
----------------------------
... # Key value pairs for this database, additonal database FF ## End of RDB file indicator
8 byte checksum ## CRC 64 checksum of the entire file.

https://ningyu1.github.io/site/post/34-redis-rdb/  这里是一个中文版RDB格式规范的翻译

4、数据恢复

当Redis关闭后,在启动时候,并且AOF持久化也没有开启,那么将使用RDB快照文件恢复数据。

模拟操作:停掉Redis,然后重新启动 Redis, 看看Redis的启动日志

四:AOF的使用

1、AOF配置

appendonly no                   # yes:开启AOF, no: 关闭AOF

appendfilename "appendonly.aof" # 指定AOF的文件名

appendfsync everysec
#everysec:数据将使用调用操作系统write写入文件,并使用fsync每秒一次从内核刷新到磁盘。
# 这是折中的方案,兼顾性能和数据安全,所以redis默认推荐使用该配置。
#always:表示每次有写操作都调用fsync方法强制内核将数据写入到aof文件。
# 这种情况下由于每次写命令都写到了文件中, 虽然数据比较安全,但是因为每次写操作都会同步到AOF文件中,
# 所以在性能上会有影响,同时由于频繁的IO操作,硬盘的使用寿命会降低
#no :不使用fsync方法同步,而是交给操作系统write函数去执行同步操作,在linux操作系统中大约每30秒刷一次缓冲。
# 这种情况下,缓冲区数据同步不可控,并且在大量的写操作下,aof_buf缓冲区会堆积会越来越严重,
# 一旦redis出现故障,数据丢失 auto-aof-rewrite-percentage 100
#当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,
#如100代表当前AOF文件是上次重写的两倍时候才重写。
auto-aof-rewrite-min-size 64mb
#AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。 aof-load-truncated yes
#当redis突然运行崩溃时,会出现aof文件被截断的情况,Redis可以在发生这种情况时退出并加载错误,以下选项控制此行为。
#如果aof-load-truncated设置为yes,则加载截断的AOF文件,Redis服务器启动发出日志以通知用户该事件。
#如果该选项设置为no,则服务将中止并显示错误并停止启动。当该选项设置为no时,用户需要在重启之前使用“redis-check-aof”实用程序修复AOF文件在进行启动。

2、AOF在服务端的执行

当AOF的持久化功能打开时,服务器在执行完一个命令后,会以协议格式将被执行的命令追加到服务器状态的 aof_buf 缓冲区的末尾:

//redis.h
struct redisServer {
//...
sds aof_buf; /* AOF buffer, written before entering the event loop */
//...
}

比如,你在客户端执行下面的命令:

redis > SET KEY VALUE
OK

那么服务器在执行这个 SET 命令之后, 会将以下redis协议内容追加到 aof_buf 缓冲区的末尾:

*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n

redis协议解释

首先Redis是以行来划分,每行以\r\n行结束。每一行都有一个消息头,消息头共分为5种分别如下:

(+) 表示一个正确的状态信息,具体信息是当前行+后面的字符。

(-)  表示一个错误信息,具体信息是当前行-后面的字符。

(*) 表示消息体总共有多少行,不包括当前行,*后面是具体的行数。

($) 表示下一行数据长度,不包括换行符长度\r\n,$后面则是对应的长度的数据。

(:) 表示返回一个数值,:后面是相应的数字节符。

3、AOF持久化的过程

3.1、追加写入
      就是上面介绍的在服务端的执行,将每一条命令以redis的协议写入到aof_buf缓冲区,暂存在这里,然后根据策略一次性写入到硬盘

3.2、同步写入硬盘
     我们在上面AOF配置里面有一个配置选项:appendfsync ,里面有no,always,everysec 3个选项
     当写命令写入到aof_buf 缓冲区后,Redis会根据这3种策略,同步缓冲区数据到硬盘,详细说明见 AOF配置

3.3、文件重写bgrewriteaof
为什么要重写AOF文件?
因为在Redis的运行过程中,AOF的文件越来越大,导致恢复的时候所需要的时间越来越长,所以要对AOF文件进行优化。

重写策略:

  • 重复或无效的命令不写入文件
  • 过期的数据不再写入文件
  • 多条命令合并写入(当多个命令能合并一条命令时候会对其优化合并作为一个命令写入,例如"RPUSH list1 a RPUSH list1 b" 合并为"RPUSH list1 a b" )

什么时候重写呢?
每次当serverCron(服务器周期性操作函数)函数执行时,它会检查以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:

  • 没有BGSAVE命令(RDB持久化)/AOF持久化在执行;
  • 没有BGREWRITEAOF在进行;
  • 当前AOF文件大小要大于server.aof_rewrite_min_size的值;
  • 当前AOF文件大小和最后一次重写后的大小之间的比率等于或者大于指定的增长百分比(auto-aof-rewrite-percentage参数)

4、AOF触发条件

4.1、手动触发命令
      bgrewriteaof

127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started

4.2、自动触发
      配置文件里的2个选项

  • auto-aof-rewrite-min-size: AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。
  • auto-aof-rewrite-percentage:当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比,如100代表当前AOF文件是上次重写的两倍时候才重写。 

5、数据恢复

Redis的数据恢复,它优先使用AOF来恢复,我们可以停掉Redis来模拟Redis故障,然后重启Redis进行数据恢复。

查看Reids的日志,看看是不是恢复成功了

五:混合持久化

这个是Redis4.0 推出的一个新功能,包含了RDB和AOF 2者的优点

  • RDB 持久化能够快速地储存和恢复数据, 但是在服务器停机时却会丢失大量数据;
  • AOF 持久化能够有效地提高数据的安全性, 但是在储存和恢复数据方面却要耗费大量的时间。

这种持久化能够通过 AOF 重写操作创建出一个同时包含 RDB 数据和 AOF 数据的 AOF 文件, 其中 RDB 数据位于 AOF 文件的开头, 它们储存了服务器开始执行重写操作时的数据库状态; 至于那些在重写操作执行之后执行的 Redis 命令, 则会继续以 AOF 格式追加到 AOF 文件的末尾, 也即是 RDB 数据之后。

1、配置

# 我们可以在appendonly yes命令 下面加上以下的配置,然后重启Reids
aof-use-rdb-preamble yes

2、混合持久化过程

混合持久化同样也是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。
简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,

3、实践操作

首先开启混合持久化的配置, 然后在客户端使用bgrewriteaof命令

127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started

然后可以看看日志,发生了什么

六:其他一些命令

查看Redis状态信息

info stats

rdb 文件检查

redis-check-rdb /etc/redis/dump.rdb

aof 文件检查

redis-check-aof /etc/redis/appendonly.aof

查看持久化信息

info Persistence

七:参考

https://github.com/antirez/redis
http://blog.huangz.me/2017/redis-rdb-aof-mixed-persistence.html  混合存储
https://redis.io/topics/persistence  持久化
https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format  RDB格式规范
https://blog.csdn.net/weixin_39040059/article/details/79120416
https://blog.csdn.net/weixin_39040059/article/details/79120444

05-18 17:09