目录
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>
- <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 文件是二进制格式,可以非常快速地加载到内存中,实现Redis服务的快速启动。
- 数据备份: RDB 文件可以很容易地被复制到其他服务器或备份存储中,适合于进行数据备份和灾难恢复。
- 空间紧凑: 由于RDB文件只包含最终的数据,而不是每一条写命令,所以通常比AOF文件更紧凑。
- 减少I/O操作: 相比于AOF持久化,RDB不需要记录每一条写操作命令,因此减少了I/O操作。
- 适合大规模数据恢复: 由于RDB文件包含了数据集的全量快照,适合于大规模数据的恢复。
RDB缺点:
- 数据丢失风险:如果两次快照之间Redis发生故障,那么这段时间内的数据将丢失。
- 数据完整性不高:RDB无法保证数据的完整性和一致性。
- 阻塞:尽管 bgsave 是在后台异步执行的,但在生成RDB文件时,如果数据集非常大,仍然可能会短暂地阻塞主线程。
- 不适合高频率写操作的场景:在写操作非常频繁的场景,会频繁生成RDB快照对性能产生影响。
AOF日志
AOF日志持久化并不是直接保存 Redis 中的数据,而是记录Redis中执行的所有写操作命令。每当Redis执行一个写操作命令,该命令会被追加到AOF文件中。
在 Redis 中 AOF 持久化功能默认是不开启的,需要我们修改 Redis.conf 配置文件中的以下参数
appendonly yes:开启AOF持久化。
appendfilename "appendonly.aof":指定AOF文件的名称。
Redis 会先执行命令,执行命令成功后再将命令记录到 AOF 日志中,如果先写入 AOF 文件还需要检查命令是否执行成功,如果命令执行失败还需要额外操作。先执行命令也保证了AOF 不会阻塞当前写操作命令的执行(但可能会阻塞下一个命令的执行),因为当写操作命令执行成功后,才会将命令记录到 AOF 日志。
AOF持久化,会先将命令写入内存缓冲区中。这个内存缓冲区称为 AOF 缓冲区。然后再通过 wirte系统调用写入到磁盘上的 AOF 文件。但 wirte写入实际上是将数据拷贝到内核缓存区,由内核决定何时进行磁盘IO。如果系统宕机,而缓冲区数据没有写入磁盘,这部分数据就会丢失。
AOF写回策略
Redis可以通过fsync或fdatasync系统调用来请求操作系统将内核缓存区中的数据强制刷新到磁盘上。
AOF提供了三种写回策略: always ,everysec , no。
- always:每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘。即每次执行后都调用 fsync。
- everysec :每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘,即每秒执行一次 fsync 。
- no: 不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘。即不执行 fsync 。
这三种策略各有优缺点, always 可靠性最强性能较差,no 性能最强可靠性最差,everysec则更为折中。大家可以根据自己的需要选择策略。
AOF重写
AOF日志是一个文件,随着执行的写操作命令越来越多,文件的大小会越来越大。如果 AOF 文件过大必然会影响性能。因此 Redis 提供了 AOF重写机制。
当 AOF 文件的大小达到一定阈值时,Redis 会触发 AOF 重写过程。这个阈值可以通过配置设置。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
- auto-aof-rewrite-percentage:指定 AOF 文件大小相对于上一次重写后大小的增长百分比,当超过这个百分比时,Redis 将触发 AOF 重写。
- auto-aof-rewrite-min-size: 这个配置项指定了 AOF 文件的最小大小,只有当 AOF 文件的大小超过这个值时,auto-aof-rewrite-percentage 指定的百分比阈值才会生效。
什么是重写?AOF 文件记录了每一个写操作命令,如果记录了对同一数据的多个操作,实际上只有最后一个操作是有意义的,其他操作都是冗余的。AOF 重写机制通过创建一个新的 AOF 文件来解决这个问题,新文件只包含恢复当前数据集所需的最小命令集合。
在重写时 Redis 会通过 fork() 系统调用创建一个子进程,这个子进程与父进程共享相同的内存空间。子进程会遍历 Redis 数据库中的所有键,并生成一系列可以恢复这些数据的 Redis 命令,同时将这些命令写入到一个临时的 AOF 文件中。
重写完成后,子进程会用新的 AOF 文件替换旧的 AOF 文件,并更新 AOF 文件的文件名。
在重写过程中,主进程并不会阻塞而是继续处理客户端请求,同时将执行后的写命令追加到 「AOF 缓冲区」与「AOF 重写缓冲区」。
当重写完成时,会向主进程发送一条信号,主进程收到该信号后,会调用一个信号处理函数,该函数会做以下工作:
-
将 AOF 重写缓冲区中的所有内容追加到新的 AOF 的文件中。
-
新的 AOF 的文件进行改名,覆盖现有的 AOF 文件。
然后主进程会继续接收命令并执行,重写也就此完成。
AOF优缺点
AOF优点:
- 数据安全性高: AOF 记录了所有写操作,可以提供更好的数据恢复保证。
- 数据完整性: AOF 能够保证即使在 Redis 异常终止的情况下,也不会丢失任何已持久化的写操作。
AOF缺点:
- 磁盘空间使用: AOF 文件可能会比 RDB 文件大,因为它记录了所有的写操作命令。
- 性能影响: 频繁的磁盘I/O操作可能会影响 Redis 的性能。
- 数据恢复速度: 由于 AOF 文件可能包含大量的命令,数据恢复速度会比 RDB 慢。
混合持久化
我们可以看到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 确保了数据的完整性和一致性,同时优化了磁盘空间的使用。