摘要
Redis 的读写都是在内存中,所以它的性能较高,但在内存中的数据会随着服务器的重启而丢失,为了保证数据不丢失,我们需要将内存中的数据存储到磁盘,以便 Redis 重启时能够从磁盘中恢复原有的数据,而整个过程就叫做 Redis 持久化。Redis 持久化也是 Redis 和 Memcached 的主要区别之一,因为 Memcached 不具备持久化功能。
一、Redis持久化的几种方式
Redis 持久化拥有以下三种方式:
- 快照方式(RDB, Redis DataBase)将某一个时刻的内存数据,以二进制的方式写入磁盘;
- 文件追加方式(AOF, Append Only File),记录所有的操作命令,并以文本的形式追加到文件中;
- 混合持久化方式,Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能减低数据丢失的风险。
二、Redis持久化RDB方式
RDB(Redis DataBase)是将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘的过程。
2.1 手动触发RDB
手动触发持久化的操作有两个: save
和 bgsave
,它们主要区别体现在:是否阻塞 Redis 主线程的执行。
save 命令:在客户端中执行 save
命令,就会触发 Redis 的持久化,但同时也是使 Redis 处于阻塞状态,直到 RDB 持久化完成,才会响应其他客户端发来的命令,所以在生产环境一定要慎用。save
命令使用如下:
从图片可以看出,当执行完 save
命令之后,持久化文件 dump.rdb
的修改时间就变了,这就表示 save
成功的触发了 RDB 持久化。 save
命令执行流程,如下图所示:
bgsave 命令:bgsave(background save)既后台保存的意思, 它和 save
命令最大的区别就是 bgsave
会 fork() 一个子进程来执行持久化,整个过程中只有在 fork() 子进程时有短暂的阻塞,当子进程被创建之后,Redis 的主进程就可以响应其他客户端的请求了,相对于整个流程都阻塞的 save
命令来说,显然 bgsave
命令更适合我们使用。 bgsave
命令使用,如下图所示:bgsave
执行流程,如下图所示:
2.2 自动触发RDB
说完了 RDB 的手动触发方式,下面来看如何自动触发 RDB 持久化? RDB 自动持久化主要来源于以下几种情况。
save m n
save m n
是指在 m 秒内,如果有 n 个键发生改变,则自动触发持久化。 参数 m 和 n 可以在 Redis 的配置文件中找到,例如,save 60 1
则表明在 60 秒内,至少有一个键发生改变,就会触发 RDB 持久化。 自动触发持久化,本质是 Redis 通过判断,如果满足设置的触发条件,自动执行一次 bgsave
命令。 注意:当设置多个 save m n 命令时,满足任意一个条件都会触发持久化。 例如,我们设置了以下两个 save m n 命令:
- save 60 10
- save 600 1
当 60s 内如果有 10 次 Redis 键值发生改变,就会触发持久化;如果 60s 内 Redis 的键值改变次数少于 10 次,那么 Redis 就会判断 600s 内,Redis 的键值是否至少被修改了一次,如果满足则会触发持久化。
flushall
flushall
命令用于清空 Redis 数据库,在生产环境下一定慎用,当 Redis 执行了 flushall
命令之后,则会触发自动持久化,把 RDB 文件清空。 执行结果如下图所示:
主从同步触发
在 Redis 主从复制中,当从节点执行全量复制操作时,主节点会执行 bgsave
命令,并将 RDB 文件发送给从节点,该过程会自动触发 Redis 持久化。
2.3 Redis RDB的配置说明
合理的设置 RDB 的配置,可以保障 Redis 高效且稳定的运行,下面一起来看 RDB 的配置项都有哪些?RDB 配置参数可以在 Redis 的配置文件中找见,具体内容如下:
其中比较重要的参数如下列表: ① save 参数 它是用来配置触发 RDB 持久化条件的参数,满足保存条件时将会把数据持久化到硬盘。 默认配置说明如下:
- save 900 1:表示 900 秒内如果至少有 1 个 key 值变化,则把数据持久化到硬盘;
- save 300 10:表示 300 秒内如果至少有 10 个 key 值变化,则把数据持久化到硬盘;
- save 60 10000:表示 60 秒内如果至少有 10000 个 key 值变化,则把数据持久化到硬盘。
② rdbcompression 参数 它的默认值是 yes
表示开启 RDB 文件压缩,Redis 会采用 LZF 算法进行压缩。如果不想消耗 CPU 性能来进行文件压缩的话,可以设置为关闭此功能,这样的缺点是需要更多的磁盘空间来保存文件。 ③ rdbchecksum 参数 它的默认值为 yes
表示写入文件和读取文件时是否开启 RDB 文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。
Redis 中可以使用命令查询当前配置参数。查询命令的格式为:config get xxx
,例如,想要获取 RDB 文件的存储名称设置,可以使用 config get dbfilename
,执行效果如下图所示:
查询 RDB 的文件目录,可使用命令 config get dir
,执行效果如下图所示:
设置 RDB 的配置,可以通过以下两种方式:
- 手动修改 Redis 配置文件;
- 使用命令行设置,例如,使用
config set dir "/usr/data"
就是用于修改 RDB 的存储目录。
注意:手动修改 Redis 配置文件的方式是全局生效的,即重启 Redis 服务器设置参数也不会丢失,而使用命令修改的方式,在 Redis 重启之后就会丢失。但手动修改 Redis 配置文件,想要立即生效需要重启 Redis 服务器,而命令的方式则不需要重启 Redis 服务器。Redis 的配置文件位于 Redis 安装目录的根路径下,默认名称为 redis.conf。
2.4 RDB 文件恢复
当 Redis 服务器启动时,如果 Redis 根目录存在 RDB 文件 dump.rdb,Redis 就会自动加载 RDB 文件恢复持久化数据。 如果根目录没有 dump.rdb 文件,请先将 dump.rdb 文件移动到 Redis 的根目录。 验证 RDB 文件是否被加载 Redis 在启动时有日志信息,会显示是否加载了 RDB 文件,我们执行 Redis 启动命令:src/redis-server redis.conf
,如下图所示:
从日志上可以看出, Redis 服务在启动时已经正常加载了 RDB 文件。提示:Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。
2.5 RDB的禁用持久化
禁用持久化可以提高 Redis 的执行效率,如果对数据丢失不敏感的情况下,可以在连接客户端的情况下,执行 config set save ""
命令即可禁用 Redis 的持久化,如下图所示:
2.6 RDB 优缺点
1)RDB 优点
- RDB 的内容为二进制的数据,占用内存更小,更紧凑,更适合做为备份文件;
- RDB 对灾难恢复非常有用,它是一个紧凑的文件,可以更快的传输到远程服务器进行 Redis 服务恢复;
- RDB 可以更大程度的提高 Redis 的运行速度,因为每次持久化时 Redis 主进程都会 fork() 一个子进程,进行数据持久化到磁盘,Redis 主进程并不会执行磁盘 I/O 等操作;
- 与 AOF 格式的文件相比,RDB 文件可以更快的重启。
2)RDB 缺点
- 因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终止了,则会丢失一段时间内的 Redis 数据;
- RDB 需要经常 fork() 才能使用子进程将其持久化在磁盘上。如果数据集很大,fork() 可能很耗时,并且如果数据集很大且 CPU 性能不佳,则可能导致 Redis 停止为客户端服务几毫秒甚至一秒钟。
三、Redis 持久化AOF
AOF(Append Only File)中文是附加到文件,顾名思义 AOF 可以把 Redis 每个键值对操作都记录到文件(appendonly.aof)中。
使用 RDB 持久化有一个风险,它可能会造成最新数据丢失的风险。因为 RDB 的持久化有一定的时间间隔,在这个时间段内如果 Redis 服务意外终止的话,就会造成最新的数据全部丢失。可能会操作 Redis 服务意外终止的条件:
- 安装 Redis 的机器停止运行,蓝屏或者系统崩溃;
- 安装 Redis 的机器出现电源故障,例如突然断电;
- 使用
kill -9 Redis_PID
等。
3.1 持久化查询和设置
使用 config get appendonly
命令,如下图所示:其中,第一行为 AOF 文件的名称,而最后一行表示 AOF 启动的状态,yes 表示已启动,no 表示未启动。
开启 AOF 持久化:Redis 默认是关闭 AOF 持久化的,想要开启 AOF 持久化,有以下两种方式:
- 通过命令行的方式;
- 通过修改配置文件的方式(redis.conf)。
命令行启动 AOF,使用 config set appendonly yes
命令,命令行启动 AOF 的优缺点:命令行启动优点是无需重启 Redis 服务,缺点是如果 Redis 服务重启,则之前使用命令行设置的配置就会失效。如下图所示:
配置文件启动 AOF:Redis 的配置文件在它的根路径下的 redis.conf 文件中,获取 Redis 的根目录可以使用命令 config get dir
获取,只需要在配置文件中设置 appendonly yes
即可,默认 appendonly no
表示关闭 AOF 持久化。 配置文件启动 AOF 的优缺点:修改配置文件的缺点是每次修改配置文件都要重启 Redis 服务才能生效,优点是无论重启多少次 Redis 服务,配置文件中设置的配置信息都不会失效。如下图所示:
3.2 触发持久化
AOF 持久化开启之后,只要满足一定条件,就会触发 AOF 持久化。AOF 的触发条件分为两种:自动触发和手动触发。
自动触发:有两种情况可以自动触发 AOF 持久化,分为是:满足 AOF 设置的策略触发和**满足 AOF 重写触发。**其中,AOF 重写触发会在本文的后半部分详细介绍,这里重点来说 AOF 持久化策略都有哪些。 AOF 持久化策略,分为以下三种:
- always:每条 Redis 操作命令都会写入磁盘,最多丢失一条数据;
- everysec:每秒钟写入一次磁盘,最多丢失一秒的数据;
- no:不设置写入磁盘的规则,根据当前操作系统来决定何时写入磁盘,Linux 默认 30s 写入一次数据至磁盘。
手动触发,在客户端执行 bgrewriteaof
命令就可以手动触发 AOF 持久化,可以看出执行完 bgrewriteaof
命令之后,AOF 持久化就会被触发。如下图所示:
3.3 AOF 文件重写
AOF 是通过记录 Redis 的执行命令来持久化(保存)数据的,所以随着时间的流逝 AOF 文件会越来越多,这样不仅增加了服务器的存储压力,也会造成 Redis 重启速度变慢,为了解决这个问题 Redis 提供了 AOF 重写的功能。
什么是 AOF 重写:AOF 重写指的是它会直接读取 Redis 服务器当前的状态,并压缩保存为 AOF 文件。例如,我们增加了一个计数器,并对它做了 99 次修改,如果不做 AOF 重写的话,那么持久化文件中就会有 100 条记录执行命令的信息,而 AOF 重写之后,之后记录一条此计数器最终的结果信息,这样就去除了所有的无效信息。
AOF 重写实现:触发 AOF 文件重写,要满足两个条件,这两个条件也是配置在 Redis 配置文件中的,它们分别:
- auto-aof-rewrite-min-size:允许AOF重写的最小文件容量,默认是 64mb。
- auto-aof-rewrite-percentage:AOF 文件重写的大小比例,默认值是 100,表示 100%,也就是只有当前 AOF 文件,比最后一次(上次)的 AOF 文件大一倍时,才会启动 AOF 文件重写。
查询 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 的值,可使用 config get xxx
命令,如下图所示:
小贴士:只有同时满足 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 设置的条件,才会触发 AOF 文件重写。注意:使用 bgrewriteaof
命令,可以自动触发 AOF 文件重写。
AOF 文件重写是生成一个全新的文件,并把当前数据的最少操作命令保存到新文件上,当把所有的数据都保存至新文件之后,Redis 会交换两个文件,并把最新的持久化操作命令追加到新文件上。
3.3.1 AOF文件重写实现原理
Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库状态相同,但 新AOF文件 不会包含 任何浪费空间的冗余命令,所以新AOF文件的体积通常会比旧AOF文件的体积要小得多。首先 从数据库中 读取 键现在的值,然后 用一条命令 去记录 键值对,代替 之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理。
因为aof_rewrite
函数生成的新AOF文件 只包含 还原当前数据库状态所必须的命令,所以新AOF文件不会浪费任何硬盘空间。注意:在实际中,为了避免 在执行命令时 造成 客户端输入缓冲区溢出,重写程序 在处理 列表、哈希表、集合、有序集合这四种可能会带有多个元素的键时,会先检查键所包含的元素数量,如果元素的数量超过了redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量的值,那么 重写程序 将使用 多条命令来记录键的值,而不单单使用一条命令。在目前版本中,REDIS_AOF_REWRITE_ITEMS_PER_CMD
常量的值为64,这也就是说,如果一个集合键包含了超过64个元素,那么重写程序会用多条SADD
命令来记录这个集合,并且每条命令设置的元素数量也为64个:
如果一个列表键包含了超过64个项,那么重写程序会用多条RPUSH
命令来保存这个列表,并且每条命令设置的项数量也为64个:
重写程序使用类似的方法处理包含多个元素的有序集合键,以及包含多个键值对的哈希表键。
3.3.2 BGREWRITEAOF命令实现原理
aof_rewrite
函数可以很好地完成创建一个新AOF文件的任务,但是,因为这个函数会进行大量的写入操作,所以调用这个函数的线程将被长时间阻塞。因为Redis服务器使用单个线程来处理命令请求,所以如果由服务器直接调用aof_rewrite
函数的话,那么在重写AOF文件期间,服务期将无法处理客户端发来的命令请求。
Redis 决定 将AOF重写程序(aof_rewrite) 放到 子进程里执行,这样做可以同时达到两个目的:
- 子进程 进行 AOF重写 期间,服务器进程(父进程)可以继续处理命令请求。
- 子进程 带有 服务器进程 的 数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性。
不过,使用子进程也有一个问题需要解决,因为子进程在进行AOF重写期间,服务器进程还需要继续处理命令请求,而新的命令可能会对现有的数据库状态进行修改,从而使得服务器当前的数据库状态和重写后的AOF文件所保存的数据库状态不一致。
下面展示了一个AOF文件重写例子,当子进程开始进行文件重写时,数据库中只有k1一个键,但是当子进程完成AOF文件重写之后,服务器进程的数据库中已经新设置了k2、k3、k4三个键,因此,重写后的AOF文件和服务器当前的数据库状态并不一致,新的AOF文件只保存了k1一个键的数据,而服务器数据库现在却有k1、k2、k3、k4四个键
时间 |
服务器进程 |
子进程 |
T1 |
执行命令set k1 v1 |
|
T2 |
执行命令set k1 v2 |
|
T3 |
执行命令set k1 v3 |
|
T4 |
创建子进程,执行AOF文件重写 |
开始AOF文件重写 |
T5 |
执行命令set k2 100 |
执行重写操作 |
T6 |
执行命令set k3 101 |
执行重写操作 |
T7 |
执行命令set k4 102 |
完成AOF的重写操作 |
为了解决这种数据不一致问题,Redis服务器设置了一个AOF重写缓冲区,这个缓冲区 在服务器 创建子进程之后 开始使用,当Redis服务器 执行完一个 写命令之后,它会 同时 将这个写命令 发送给 AOF缓冲区 和 AOF重写缓冲区。
服务器进程需要执行以下三个工作:
- 执行客户端发来的命令
- 将执行后的写命令 追加到 AOF缓冲区
- 将执行后的写命令 追加到 AOF重写缓冲区
这样一来可以保证:
AOF缓冲区的内容 会定期 被写入 和 同步到AOF文件(通过appendfsync选项),对现有AOF文件的处理工作会如常进行。
从创建子进程开始,服务器执行的所有写命令 都会被 记录到 AOF重写缓冲区 里面(这句话前后半句是两件事,互不干扰)
当子进程完成 AOF重写工作 之后,它会向父进程发送一个信号,父进程在接到该信号之后,会调用一个信号处理函数,并执行以下工作:
- 将 AOF重写缓冲区中的所有内容 写入到 新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致
- 对新的AOF文件进行改名,原子地(atomic)覆盖现有的AOF文件,完成新旧两个AOF文件的替
这个信号处理函数执行完毕之后,父进程就可以继续像往常一样接受命令请求了。
3.3.3 AOF文件重写流程
- 执行AOF重写请求
如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再执行,返回如下响应:
- 父进程执行fork创建子进程,开销等同于bgsave过程。
- 主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入AOF缓冲区 并根据 appendfsync策略同步到硬盘,保证原有AOF机制正确性。
- 由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,Redis使用“AOF重写缓冲区”保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。
- 子进程根据内存快照,按照命令合并规则写入到新的AOF文件。每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞
- 新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。
- 父进程把AOF重写缓冲区的数据写入到新的AOF文件。
- 使用新AOF文件替换老文件,完成AOF重写。
3.4 AOF配置说明
合理的设置 AOF 的配置,可以保障 Redis 高效且稳定的运行,以下是 AOF 的全部配置信息和说明。AOF 的配置参数在 Redis 的配置文件中,也就是 Redis 根路径下的 redis.conf
文件中,其中比较重要的是 appendfsync 参数,用它来设置 AOF 的持久化策略,可以选择按时间间隔或者操作次数来存储 AOF 文件,配置参数和说明如下:
3.5 AOF 下的数据恢复
3.5.1 数据的恢复的原理:
加载损坏的AOF文件时会拒绝启动,并打印如下日志:
对于错误格式的AOF文件,先进行备份,然后采用redis-check-aof--fix
命令进行修复,修复后使用diff -u
对比数据的差异,找出丢失的数据,有些可以人工修改补全。
AOF文件可能存在结尾不完整的情况,比如机器突然掉电 导致AOF尾部文件命令写入不全,Redis为我们提供了aof-load-truncated
配置来兼容这种情况,默认开启。加载AOF时,当遇到此问题时会忽略并继续启动,同时打印如下警告日志:
正常数据恢复,正常情况下,只要开启了 AOF 持久化,并且提供了正常的 appendonly.aof 文件,在 Redis 启动时就会自定加载 AOF 文件并启动,小贴士:默认情况下 appendonly.aof 文件保存在 Redis 的根目录下。执行如下图所示:
持久化文件加载规则
- 如果只开启了 AOF 持久化,Redis 启动时只会加载 AOF 文件(appendonly.aof),进行数据恢复;
- 如果只开启了 RDB 持久化,Redis 启动时只会加载 RDB 文件(dump.rdb),进行数据恢复;
- 如果同时开启了 RDB 和 AOF 持久化,Redis 启动时只会加载 AOF 文件(appendonly.aof),进行数据恢复。
在 AOF 开启的情况下,即使 AOF 文件不存在,只有 RDB 文件,也不会加载 RDB 文件。 AOF 和 RDB 的加载流程如下图所示:
简单异常数据恢复:在 AOF 写入文件时如果服务器崩溃,或者是 AOF 存储已满的情况下,AOF 的最后一条命令可能被截断,这就是异常的 AOF 文件。在 AOF 文件异常的情况下,如果为修改 Redis 的配置文件,也就是使用 aof-load-truncated
等于 yes
的配置,Redis 在启动时会忽略最后一条命令,并顺利启动 Redis,执行结果如下:
复杂异常数据恢复:AOF 文件可能出现更糟糕的情况,当 AOF 文件不仅被截断,而且中间的命令也被破坏,这个时候再启动 Redis 会提示错误信息并中止运行,错误信息如下:
出现此类问题的解决方案如下:
- 首先使用 AOF 修复工具,检测出现的问题,在命令行中输入
redis-check-aof
命令,它会跳转到出现问题的命令行,这个时候可以尝试手动修复此文件; - 如果无法手动修复,我们可以使用
redis-check-aof --fix
自动修复 AOF 异常文件,不过执行此命令,可能会导致异常部分至文件末尾的数据全部被丢弃。
3.6 AOF的优缺点
AOF 优点
- AOF 持久化保存的数据更加完整,AOF 提供了三种保存策略:每次操作保存、每秒钟保存一次、跟随系统的持久化策略保存,其中每秒保存一次,从数据的安全性和性能两方面考虑是一个不错的选择,也是 AOF 默认的策略,即使发生了意外情况,最多只会丢失 1s 钟的数据;
- AOF 采用的是命令追加的写入方式,所以不会出现文件损坏的问题,即使由于某些意外原因,导致了最后操作的持久化数据写入了一半,也可以通过 redis-check-aof 工具轻松的修复;
- AOF 持久化文件,非常容易理解和解析,它是把所有 Redis 键值操作命令,以文件的方式存入了磁盘。即使不小心使用
flushall
命令删除了所有键值信息,只要使用 AOF 文件,删除最后的 flushall
命令,重启 Redis 即可恢复之前误删的数据。
AOF 缺点
- 对于相同的数据集来说,AOF 文件要大于 RDB 文件;
- 在 Redis 负载比较高的情况下,RDB 比 AOF 性能更好;
- RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 更健壮。
AOF 保存数据更加完整,它可以记录每次 Redis 的键值变化,或者是选择每秒保存一次数据。AOF 的持久化文件更加易读,但相比与二进制的 RDB 来说,所占的存储空间也越大,为了解决这个问题,AOF 提供自动化重写机制,最大程度的减少了 AOF 占用空间大的问题。同时 AOF 也提供了很方便的异常文件恢复命令: redis-check-aof --fix
,为使用 AOF 提供了很好的保障。
四、混合持久化
RDB 和 AOF 持久化各有利弊,RDB 可能会导致一定时间内的数据丢失,而 AOF 由于文件较大则会影响 Redis 的启动速度,为了能同时使用 RDB 和 AOF 各种的优点,Redis 4.0 之后新增了混合持久化的方式。
在开启混合持久化的情况下,AOF 重写时会把 Redis 的持久化数据,以 RDB 的格式写入到 AOF 文件的开头,之后的数据再以 AOF 的格式化追加的文件的末尾。
4.1 开启混合持久化
查询是否开启混合持久化可以使用 config get aof-use-rdb-preamble
命令,执行结果如下图所示:
其中 yes 表示已经开启混合持久化,no 表示关闭,Redis 5.0 默认值为 yes。 如果是其他版本的 Redis 首先需要检查一下,是否已经开启了混合持久化,如果关闭的情况下,可以通过以下两种方式开启:
- 通过命令行开启
- 通过修改 Redis 配置文件开启
使用命令 config set aof-use-rdb-preamble yes
执行结果如下图所示:小贴士:命令行设置配置的缺点是重启 Redis 服务之后,设置的配置就会失效。
在 Redis 的根路径下找到 redis.conf 文件,把配置文件中的 aof-use-rdb-preamble no
改为 aof-use-rdb-preamble yes
如下图所示:
当在混合持久化关闭的情况下,使用 bgrewriteaof
触发 AOF 文件重写之后,查看 appendonly.aof 文件的持久化日志,如下图所示:
可以看出,当混合持久化关闭的情况下 AOF 持久化文件存储的为标准的 AOF 格式的文件。 当混合持久化开启的模式下,使用 bgrewriteaof
命令触发 AOF 文件重写,得到 appendonly.aof 的文件内容如下图所示:
可以看出 appendonly.aof 文件存储的内容是 REDIS
开头的 RDB 格式的内容,并非为 AOF 格式的日志。
4.2 数据恢复
混合持久化的数据恢复和 AOF 持久化过程是一样的,只需要把 appendonly.aof 放到 Redis 的根目录,在 Redis 启动时,只要开启了 AOF 持久化,Redis 就会自动加载并恢复数据。 Redis 启动信息如下图所示:
可以看出 Redis 在服务器初始化的时候加载了 AOF 文件的内容。
4.3 混合持久化的加载流程
混合持久化的加载流程如下:
- 判断是否开启 AOF 持久化,开启继续执行后续流程,未开启执行加载 RDB 文件的流程;
- 判断 appendonly.aof 文件是否存在,文件存在则执行后续流程;
- 判断 AOF 文件开头是 RDB 的格式, 先加载 RDB 内容再加载剩余的 AOF 内容;
- 判断 AOF 文件开头不是 RDB 的格式,直接以 AOF 格式加载整个文件。
4.4 源码解析
Redis 判断 AOF 文件的开头是否是 RDB 格式的,是通过关键字 REDIS
判断的,RDB 文件的开头一定是 REDIS
关键字开头的,判断源码在 Redis 的 src/aof.c 中,核心代码如下所示:
可以看出 Redis 是通过判断 AOF 文件的开头是否是 REDIS
关键字,来确定此文件是否为混合持久化文件的。小贴士:AOF 格式的开头是 *,而 RDB 格式的开头是 REDIS。
4.5 混合持久化的优缺点
混合持久化优点:
- 混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险。
混合持久化缺点:
- AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;
- 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了。
持久化虽然保证了数据不丢失,但同时拖慢了 Redis 的运行速度,那怎么更合理的使用 Redis 的持久化功能呢? Redis 持久化的最佳实践可从以下几个方面考虑。
1)控制持久化开关
使用者可根据实际的业务情况考虑,如果对数据的丢失不敏感的情况下,可考虑关闭 Redis 的持久化,这样所以的键值操作都在内存中,就可以保证最高效率的运行 Redis 了。 持久化关闭操作:
- 关闭 RDB 持久化,使用命令:
config set save ""
- 关闭 AOF 和 混合持久化,使用命令:
config set appendonly no
2)主从部署
使用主从部署,一台用于响应主业务,一台用于数据持久化,这样就可能让 Redis 更加高效的运行。
3)使用混合持久化
混合持久化结合了 RDB 和 AOF 的优点,Redis 5.0 默认是开启的。
4)使用配置更高的机器
Redis 对 CPU 的要求并不高,反而是对内存和磁盘的要求很高,因为 Redis 大部分时候都在做读写操作,使用更多的内存和更快的磁盘,对 Redis 性能的提高非常有帮助。
五、Redis持久化的面试问题
重写后的AOF文件为什么可以变小?
- 进程内已经超时的数据不再写入文件
- 旧的AOF文件含有无效命令,如del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令
- 多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。