Redis 持久化技术
RDB 是默认持久化方式,但 Redis 允许 RDB 与 AOF 两种持久化技术同时
开启,此时系统会使用 AOF 方式做持久化,即 AOF 持久化技术的优先级要更高。同样的道
理,两种技术同时开启状态下,系统启动时若两种持久化文件同时存在,则优先加载 AOF
持久化文件。
RDB 持久化
RDB , Redis DataBase ,是指将内存中某一时刻的数据快照 全量 写入到指定的 rdb 文件的持久化技术。 RDB 持久化默认是开启的。当 Redis 启动时会自动读取 RDB 快照文件,将数据 从硬盘载入到内存,以恢复 Redis 关机前的数据库状态。
RDB 持久化的执行有三种方式:手动 save 命令、手动 bgsave 命令,与自动条件触发。手动 save 命令,手动 bgsave 命令通过在 redis-cli 客户端中执行 save 命令可立即进行一次持久化保存。 save 命令在执行期间会阻塞 redis-server 进程,直至持久化过程完毕。而在 redis-server 进程阻塞期间, Redis不能处理任何读写请求,无法对外提供服务。通过在 redis-cli 客户端中执行 bgsave 命令可立即进行一次持久化保存。不同于 save 命令的是,正如该命令的名称一样, background save ,后台运行 save 。 bgsave 命令会使服务器进程 redis-server 生成一个子进程,由该子进程负责完成保存过程。在子进程进行保存过程中,不会阻塞 redis-server 进程对客户端读写请求的处理。自动条件触发自动条件触发的本质仍是 bgsave 命令的执行。只不过是用户通过在配置文件中做相应的设置后, Redis 会根据设置信息自动调用 bgsave 命令执行。
RDB 持久化过程
在进行持久化过程中,如果 redis-server 进程接收到了用户写请求,则系统会将
内存中发生数据修改的物理块 copy 出一个副本。等内存中的全量数据 copy 结束后,会再将副本中的数据 copy 到 RDB 临时文件。这个副本的生成是由于 Linux 系统的 写时复制技术( Copy-On-Write )实现的
写时复制技术是 Linux 系统的一种进程管理技术。原本在 Unix 系统中,当一个主进程通过 fork() 系统调用创建子进程后,内核进程会复制主进程的整个内存空间中的数据,然后分配给子进程。这种方式存在的问题有以下几点: 这个过程非常耗时 这个过程降低了系统性能 如果主进程修改了其内存数据,子进程副本中的数据是没有修改的。即出现了数据冗余,而冗余数据最大的问题是数据一致性无法保证。现代的 Linux 则采用了更为有效的方式:写时复制。子进程会继承父进程的所有资源,其中就包括主进程的内存空间。即子进程与父进程共享内存。只要内存被共享,那么该内存就是只读的(写保护的)。而写时复制则是在任何一方需要写入数据到共享内存时都会出现异常,此时内核进程就会将需要写入的数据 copy 出一个副本写入到另外一块非共享内存区域。
AOF 持久化
AOF , Append Only File ,是指 Redis 将每一次的写操作都以日志的形式记录到一个 AOF文件中的持久化技术。当需要恢复内存数据时,将这些写操作重新执行一次,便会恢复到之前的内存数据状态。
默认情况下 AOF 持久化是没有开启的,通过修改配置文件中的 appendonly 属性为 yes
可以开启。
Redis 7 发生了重大变化。原来只有一个 appendonly.aof 文件,现在具有了三类多个文件: 基本文件:可以是 RDF 格式也可以是 AOF 格式。其存放的内容是由 RDB 转为 AOF 当时内存的快照数据。该文件可以有多个。 增量文件:以操作日志形式记录转为 AOF 后的写入操作。该文件可以有多个。 清单文件:用于维护 AOF 文件的创建顺序,保障激活时的应用顺序。该文件只有一个。
混合式持久化开启
对于基本文件可以是 RDF 格式也可以是 AOF 格式。通过 aof-use-rdb-preamble 属性可以
选择。其默认值为 yes ,即默认 AOF 持久化的基本文件为 rdb 格式文件,也就是默认采用混
合式持久化。
AOF 文件格式
AOF 文件包含三类文件:基本文件、增量文件与清单文件。其中基本文件一般为 rdb 格
式,在前面已经研究过了。下面就来看一下增量文件与清单文件的内容格式。
增量文件扩展名为 .aof ,采用 AOF 格式。 AOF 格式其实就是 Redis 通讯协议格式, AOF
持久化文件的本质就是基于 Redis 通讯协议的文本,将命令以纯文本的方式写入到文件中。
清单文件 appendonly.aof.manifest
该文件首先会按照 seq 序号列举出所有基本文件,基本文件 type 类型为 b ,然后再按照
seq 序号再列举出所有增量文件,增量文件 type 类型为 i 。
对于 Redis 启动时的数据恢复,也会按照该文件由上到下依次加载它们中的数据。
rewrite
随着使用时间的推移, AOF 文件会越来越大。为了防止 AOF 文件由于太大而占用大量
的磁盘空间,降低性能, Redis 引入了 Rewrite 机制来对 AOF 文件进行压缩。
所谓 Rewrite 其实就是对 AOF 文件进行重写整理。当 Rewrite 开启后,主进程 redis-server
创建出一个子进程 bgrewriteaof ,由该子进程完成 rewrite 过程。其首先对现有 aof 文件进行
rewrite 计算,将计算结果写入到一个临时文件,写入完毕后,再 rename 该临时文件为原 aof
文件名,覆盖原有文件。
Rewrite 过程的执行有两种方式。一种是通过 bgrewriteaof 命令手动开启,一种是通过
设置条件自动开启。
appendfsync
当客户端提交写操作命令后,该命令就会写入到 aof_buf 中,而 aof_buf 中的数据持久
化到磁盘 AOF 文件的过程称为数据同步。
何时将 aof_buf 中的数据同步到 AOF 文件?采用不同的数据同步策略,同时的时机是不
同的,有三种策略:
always :写操作命令写入 aof_buf 后会立即调用 fsync() 系统函数,将其追加到 AOF 文件。
该策略效率较低,但相对比较安全,不会丢失太多数据。最多就是刚刚执行过的写操作
在尚未同步时出现宕机或重启,将这一操作丢失。
no :写操作命令写入 aof_buf 后什么也不做,不会调用 fsync() 函数。而将 aof_buf 中的
数据同步磁盘的操作由操作系统负责。 Linux 系统默认同步周期为 30 秒。效率较高。
everysec :默认策略。写操作命令写入 aof_buf 后并不直接调用 fsync() ,而是每秒调用
一次 fsync() 系统函数来完成同步。该策略兼顾到了性能与安全,是一种折中方案。
aof-rewrite-incremental-fsync
当 bgrewriteaof 在执行过程也是先将 rewrite 计算的结果写入到了 aof_rewrite_buf 缓存
中,然后当缓存中数据达到一定量后就会调用 fsync() 进行刷盘操作,即数据同步,将数据写
入到临时文件。该属性用于控制 fsync() 每次刷盘的数据量最大不超过 4MB 。这样可以避免由
于单次刷盘量过大而引发长时间阻塞。
AOF 持久化过程