文章目录
- AOF 相关配置
- AOF 文件的修复
- AOF 文件格式
- RESP 协议
- 查看 AOF 文件
- 清单文件
- AOF Rewrite
- Rewrite 策略
- 手动Rewrite
- 自动Rewrite
- AOF 持久化过程
- AOF优缺点
- AOF与RDB混合持久化
AOF (Append Only File) 是把所有对内存进行修改的指令(写操作)以独立日志文件的方式进行记录,重启时通过执行 AOF 文件中的 Redis 命令来恢复数据。
AOF 相关配置
- AOF的开启
默认情况下 AOF 持久化是没有开启的,通过修改配置文件中的 appendonly 属性为 yes 可以开启。但是在生产环境下,修改配置文件需要重启Redis服务器才能生效。所以,采用下面方式开启 AOF 更好。
- 文件名配置
Redis 7 在这里发生了重大变化。以前的Redis版本中只有一个 appendonly.aof 文件,现在变成了三类文件,并且这三类文件名的前缀都是appendonly.aof。
-
基本文件:可以是 RDB 格式也可以是 AOF 格式。其存放的内容是由 RDB 转为 AOF 当时内存的快照数据。在数据量非常大的时候,该文件可以有多个。
-
增量文件:以操作日志形式记录转为 AOF 后的写入操作。该文件可以有多个。
-
清单文件:用于维护 AOF 文件的创建顺序,保障激活时的应用顺序。该文件只有一个。
- AOF 文件目录配置
为了方便管理,可以专门为 AOF 持久化文件指定存放目录。目录名由 appenddirname 属性指定,存放的位置由 redis.conf 配置文件的 dir 属性指定的目录决定。
- 混合式持久化开启
对于基本文件可以是 RDF 格式也可以是 AOF 格式。通过 aof-use-rdb-preamble 属性可以选择。其默认值为 yes,即默认 AOF 持久化的基本文件为 rdb 格式文件,也就是默认采用混合式持久化。如果关闭混合持久化,那么第一个基本文件就是 AOF 格式。
- appendfsync(同步策略)
Linux 操作系统中为了提升性能,使用了页缓存。当我们将 aof_buf 的内容写到磁盘上时,此时数据并没有真正的落盘,而是在页缓存中,为了将页缓存中的数据真正落盘,需要执行 fsync / fdatasync 命令来强制刷盘。这边的文件同步做的就是刷盘操作,或者叫文件刷盘可能更容易理解一些。
AOF 缓存区的同步文件策略由参数 appendfsync 控制,有三种同步策略,各个值的含义如下:
-
always
:命令写入 aof_buf 后立即调用系统 write 操作和系统 fsync 操作同步到 AOF 文件,fsync 完成后线程返回。这种情况下,每次有写命令都要同步到 AOF 文件,硬盘 IO 成为性能瓶颈,Redis 只能支持大约几百TPS写入,严重降低了 Redis 的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低 SSD 的寿命。可靠性较高,数据基本不丢失。 -
no
:命令写入 aof_buf 后调用系统 write 操作,不对 AOF 文件做 fsync 同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。 -
everysec
:命令写入 aof_buf 后调用系统 write 操作,write 完成后线程返回;fsync 同步文件操作由专门的线程每秒调用一次。everysec 是前述两种策略的折中,是性能和数据安全性的平衡,因此是 Redis 的默认配置,也是我们推荐的配置。
- no-appendfsync-on-rewrite
设置为 yes 表示 rewrite 期间对新写操作不 fsync,暂时存在内存中,等 rewrite 完成后再写入,默认为 no。但如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。
- aof-rewrite-incremental-fsync
当 bgrewriteaof 在执行过程也是先将 rewrite 计算的结果写入到了 aof_rewrite_buf 缓存中,然后当缓存中数据达到一定量后就会调用 fsync()进行刷盘操作,即数据同步,将数据写入到临时文件。该属性用于控制 fsync()每次刷盘的数据量最大不超过 4MB。这样可以避免由于单次刷盘量过大而引发长时间阻塞。
- aof-load-truncated
在进行 AOF 持久化过程中可能会出现系统突然宕机的情况,此时写入到 AOF 文件中的最后一条数据可能会不完整。当主机启动后,Redis 在 AOF 文件不完整的情况下是否可以启动,取决于属性 aof-load-truncated 的设置。其值为:
-
yes:AOF 文件最后不完整的数据直接从 AOF 文件中截断删除,不影响 Redis 的启动。
-
no:AOF 文件最后不完整的数据不可以被截断删除,Redis 无法启动。
在设置为no的时候AOF文件损坏,如何启动?可以使用redis-check-aof工具修复AOF文件,该工具会截断尾部无法解析的AOF。修复完成后Redis才可以启动。
- aof-timestamp-enabeld
该属性设置为 yes 则会开启在 AOF 文件中增加时间戳的显示功能,可方便按照时间对数据进行恢复。但该方式可能会与 AOF 解析器不兼容,所以默认值为 no,不开启。
AOF 文件的修复
先故意损坏aof文件的末尾
如果aof-load-truncated设置为no,在将Redis服务器关机,此时Redis服务器肯定无法正常启动。
使用redis-check-aof工具对AOF文件进行修复,Redis就可以启动。
AOF 文件格式
RESP 协议
RESP是Redis序列化协议的简写。它是一种直观的文本协议,优势在于实现异常简单,解析性能极好。Redis协议将传输的结构数据分为5种最小单元类型,单元结束时统一加上回车换行符号\r\n。
- 单行字符串:首字节是
+
,后面跟上单行字符串,以CRLF( “\r\n” )结尾。例如返回"OK": “+OK\r\n” - 错误(Errors):首字节是
-
,与单行字符串格式一样,只是字符串是异常信息,例如:“-Error message\r\n” - 数值:首字节是
:
,后面跟上数字格式的字符串,以CRLF结尾。例如:“:10\r\n” - 多行字符串:首字节是
$
,表示二进制安全的字符串,最大支持512MB: - 数组:首字节是
*
,后面跟上数组元素个数,再跟上元素,元素数据类型不限:
查看 AOF 文件
打开 appendonly.aof.1.incr.aof 文件,可以看到如下格式内容。
对照Redis协议,*2表示当前命令包含 2 个参数,分别是SELECT和0;$6表示下一行的信息有6个字符;下面的消息同理。
清单文件
该文件首先会按照 seq 序号列举出所有基本文件,基本文件 type 类型为 b,然后再按照seq 序号再列举出所有增量文件,增量文件 type 类型为 i。对于 Redis 启动时的数据恢复,也会按照该文件由上到下依次加载它们中的数据。
AOF Rewrite
随着使用时间的推移,AOF 文件会越来越大。为了防止 AOF 文件由于太大而占用大量的磁盘空间,降低性能,Redis 引入了 Rewrite 机制来对 AOF 文件进行压缩。所谓 Rewrite 其实就是对 AOF 文件进行重写整理。当 Rewrite 开启后,主进程 redis-server创建出一个子进程 bgrewriteaof,由该子进程完成 rewrite 过程。首先会读取当前数据库的状态,将结果写入到一个临时文件,写入完毕后,再 rename 该临时文件为原 aof文件名,覆盖原有文件。
AOF重写的实现原理:首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令。从原理的角度理解下面的重写策略会方便很多。
Rewrite 策略
rewrite 计算也称为 rewrite 策略。rewrite 计算遵循以下策略:
- 读操作命令不写入文件
- 无效命令不写入文件(比如多次set同一个key,前面的set就是无效命令)
- 过期数据不写入文件
- 多条命令合并写入文件(Hash、集合等数据结构以及对同一个key的值多次进行加减操作等)
手动Rewrite
该命令会使主进程 redis-server 创建出一个子进程 bgrewriteaof,由该子进程完成 rewrite过程。而在 rewrite 期间,redis-server 仍是可以对外提供读写服务的。
自动Rewrite
手动方式需要人办干预,所以一般采用自动方式。由于 Rewrite 过程是一个计算过程,需要消耗大量系统资源,会降低系统性能。所以,Rewrite 过程并不是随时随地任意开启的,而是通过设置一些条件,当满足条件后才会启动,以降低对性能的影响。
- auto-aof-rewrite-percentage: 当 aof 文件相较于上一次的 aof 文件大小的百分比达到多少时触发 AOF 重写。举个例子,auto-aof-rewrite-percentage 选项配置为 100,上一版本的 aof 文件大小为 100M,那么当我们的 aof 文件达到 200M 的时候,触发 AOF 重写;
- auto-aof-rewite-min-size:开启 rewrite 的 AOF 文件最小值,默认 64MB。也就是最小能容忍 aof 文件的大小,超过这个大小必须进行 AOF 重写;
注意:
在实际中,为了避免在执行命令是造成客户端输入缓冲区溢出,重写程序在处理列表、哈希表、集合、有序集合这四种可能会带有多个元素的键时,会先检查所包含的元素数量,如果元素数量超过了 redis.h/REDIS_AOF_REWRITE_ITEMS_PRE_CMD 常量的值,那么重写程序将使用多条命令来记录键的值,而不单单使用一条命令。
在目前版本中,REDIS_AOF_REWRITE_ITEMS_PRE_CMD 常量的值是64,也就是说,如果一个集合键包含了超过64个元素,那么重写程序会用多条 SADD 命令来记录这个集合,并且每条命令设置的元素数量也为64个。
AOF 持久化过程
注意:
在整个 AOF 后台重写过程中,只有信号处理函数执行时会对服务器进程(父进程)造成阻塞,在其他时候,AOF 后台重写不会阻塞父进程,这将 AOF 重写对服务器性能造成的影响降到了最低。
AOF优缺点
优点:
- AOF 持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据而已。
- AOF 文件使用 Redis 命令追加的形式来构造,因此,即使 Redis 只能向 AOF 文件写入命令的片断,使用 redis-check-aof 工具也很容易修正 AOF 文件。
- AOF 文件的格式可读性较强,这也为使用者提供了更灵活的处理方式。例如,如果我们不小心错用了 FLUSHALL 命令,在重写还没进行时,我们可以手工将最后的 FLUSHALL 命令去掉,然后再使用 AOF 来恢复数据。
缺点:
- 对于具有相同数据的的 Redis,AOF 文件通常会比 RDF 文件体积更大。
- 虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。但在 Redis 的负载较高时,RDB 比 AOF 具好更好的性能保证。
- RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 方式更健壮。官方文档也指出,AOF 的确也存在一些 BUG,这些 BUG 在 RDB 没有存在。
AOF与RDB混合持久化
虽然跟 AOF 相比,RDB 快照的恢复速度快,但快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销,那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?
在 Redis4.0 提出了混合使用 AOF 和 RDB 快照的方法,也就是两次 RDB 快照期间的所有命令操作由 AOF 日志文件进行记录。这样的好处是 RDB 快照不需要很频繁的执行,可以避免频繁 fork 对主线程的影响,而且 AOF 日志也只记录两次快照期间的操作,不用记录所有操作,也不会出现文件过大的情况,避免了重写开销。