Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis持久化

Redis持久化解读

作者:knight-n

Redis是一种内存级数据库,提供高速读写性能,但数据易失,它支持三种持久化方式:RDB(快照持久化)、AOF(追加文件持久化)和混合持久化,RDB通过快照将数据保存到磁盘,AOF记录所有写操作命令,混合持久化结合两者优点

Redis 是内存级数据库,其数据存储在内存中,因此能够提供快速的读写速度。但我们知道内存属于掉电易失存储器,一旦断电,存储在内存中的数据就会丢失。

在服务器重启和 Redis 服务重启后数据都会丢失。因此 Redis 提供了三种持久化方式:RDB(快照持久化),AOF(追加文件持久化),混合持久化(混合使用 AOF 日志和内存快照)。其中AOF 文件的内容是操作命令,RDB 文件的内容是二进制数据。

RDB快照

RDB快照是一种将Redis数据库状态保存到磁盘上的机制,Redis提供了两个命令:save , bgsave。

这两个命令实际上都会生成一份RDB文件,RDB存储了执行命令时的 Redis 的所有数据,在 Redis 启动时,会自动加载RDB文件恢复数据Redis并没有手动加载RDB文件的命令

save与bgsave

save 命令是在主线程下执行,由于和执行操作命令在同一个线程,所以如果写入 RDB 文件的时间太长,会阻塞主线程。

bgsave 命令会创建一个子进程执行 save 命令,主进程不会阻塞。

Redis可以通过配置文件的选项来实现每隔一段时间自动执行一次 bgsava 命令:

save <seconds> <changes>

使用示例: 上次快照以来有 60 秒并且至少有 1000 个键被改变,则自动执行 bgsave。

save 60 1000

我们可以设置多个 save ,只要有一个条件满足就会执行 bgsave。

save 900 1
save 300 10
save 60 10000

bgsave 会先 fork 创建出子进程,在 Linux 中 fork 创建出的子进程会复制父进程的页表,与父进程共享一份物理内存。

这种方式减少了创建子进程时的性能损耗,从而加快创建子进程的速度,避免主进程阻塞。创建子进程后,子进程只读,同时将数据存储在 RDB 文件中。

当执行命令的主线程内存数据也都是只读操作时,主线程和 bgsave 子进程相互不影响。当主进程对内存数据修改时会触发中断,中断处理程序会申请一份物理内存重新映射到修改的虚拟内存,这个过程叫做写时拷贝

因此,当主进程执行写操作时,对数据的修改不会影响到子进程,子进程持久化的仍是执行 fork 命令时刻的数据。 因此会产生数据丢失。

在极端情况下,如果所有的共享内存都被修改,则此时的内存占用是原先的 2 倍。所以,针对写操作多的场景,我们要留意下快照过程中内存的变化,防止内存被占满了。

RDB优缺点

RDB优点:

RDB缺点:

AOF日志

AOF日志持久化并不是直接保存 Redis 中的数据,而是记录Redis中执行的所有写操作命令。每当Redis执行一个写操作命令,该命令会被追加到AOF文件中。

在 Redis 中 AOF 持久化功能默认是不开启的,需要我们修改 Redis.conf 配置文件中的以下参数

Redis 会先执行命令,执行命令成功后再将命令记录到 AOF 日志中,如果先写入 AOF 文件还需要检查命令是否执行成功,如果命令执行失败还需要额外操作。先执行命令也保证了AOF 不会阻塞当前写操作命令的执行(但可能会阻塞下一个命令的执行),因为当写操作命令执行成功后,才会将命令记录到 AOF 日志。

AOF持久化,会先将命令写入内存缓冲区中。这个内存缓冲区称为 AOF 缓冲区。然后再通过 wirte系统调用写入到磁盘上的 AOF 文件。但 wirte写入实际上是将数据拷贝到内核缓存区,由内核决定何时进行磁盘IO。如果系统宕机,而缓冲区数据没有写入磁盘,这部分数据就会丢失。

AOF写回策略

Redis可以通过fsync或fdatasync系统调用来请求操作系统将内核缓存区中的数据强制刷新到磁盘上。

AOF提供了三种写回策略: always ,everysec , no。

这三种策略各有优缺点, always 可靠性最强性能较差,no 性能最强可靠性最差,everysec则更为折中。大家可以根据自己的需要选择策略。

AOF重写

AOF日志是一个文件,随着执行的写操作命令越来越多,文件的大小会越来越大。如果 AOF 文件过大必然会影响性能。因此 Redis 提供了 AOF重写机制。

当 AOF 文件的大小达到一定阈值时,Redis 会触发 AOF 重写过程。这个阈值可以通过配置设置。

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

什么是重写?AOF 文件记录了每一个写操作命令,如果记录了对同一数据的多个操作,实际上只有最后一个操作是有意义的,其他操作都是冗余的。AOF 重写机制通过创建一个新的 AOF 文件来解决这个问题,新文件只包含恢复当前数据集所需的最小命令集合。

在重写时 Redis 会通过 fork() 系统调用创建一个子进程,这个子进程与父进程共享相同的内存空间。子进程会遍历 Redis 数据库中的所有键,并生成一系列可以恢复这些数据的 Redis 命令,同时将这些命令写入到一个临时的 AOF 文件中。

重写完成后,子进程会用新的 AOF 文件替换旧的 AOF 文件,并更新 AOF 文件的文件名。

在重写过程中,主进程并不会阻塞而是继续处理客户端请求,同时将执行后的写命令追加到 「AOF 缓冲区」与「AOF 重写缓冲区」。

当重写完成时,会向主进程发送一条信号,主进程收到该信号后,会调用一个信号处理函数,该函数会做以下工作:

然后主进程会继续接收命令并执行,重写也就此完成。

AOF优缺点

AOF优点

AOF缺点:

混合持久化

我们可以看到RDB与AOF各有优缺点:RDB 恢复速度快,AOF 丢失数据少?Redis 4.0 引入了一种新的持久化方式,称为混合持久化,它结合了 RDB和 AOF持久化的优点。

我们可以通过配置文件开启混合持久化:

aof-use-rdb-preamble yes

当开启了混合持久化时,在 AOF 重写时,重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

当 Redis 重启时,它会首先加载 RDB 文件快速恢复数据状态。 然后,Redis 会执行保存在 AOF 文件中的写操作命令(这里的内容是 Redis 后台子进程重写 AOF 期间,主线程处理的操作命令。),恢复到最新的数据状态。

混合持久化的主要优点是结合了 RDB 和 AOF 的优点,提供了更快的数据恢复速度和更少的数据丢失风险。在 AOF 重写过程中,Redis 确保了数据的完整性和一致性,同时优化了磁盘空间的使用。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文