🚄【Redis 干货领域】从底层彻底吃透 AOF 原理(基础篇)
AOF 持久化方式
AOF 持久化方式是将 redis 的操作日志以追加的方式写入磁盘文件中。AOF 持久化是以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
AOF 实现方式
AOF(append only file)持久化是以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中命令达到恢复数据的目的。
AOF 的主要作用是解决了数据持久化的实时性,目前已经是 Redis 持久化的主流方式。
AOF 优势
该机制可以带来更高的数据安全性,即数据持久性。
Redis 中提供了 3 中同步策略,即每秒同步、每修改同步和不同步。
每秒同步:事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。
每次修改:而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。
不同步:可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
由于该机制对日志文件的写入操作采用的是 append 模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。
如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在 Redis 下一次启动之前,我们可以通过 redis-check-aof 工具来帮助我们解决数据一致性的问题。
如果日志过大,Redis 可以自动启用 rewrite 机制,压缩和瘦身相关的 aof 文件。
Redis 以 append 模式不断的将修改数据写入到老的磁盘文件中,同时 Redis 还会创建一个临时的新文件用于记录此期间有哪些修改命令被执行。
因此在进行 rewrite 切换时可以更好的保证数据安全性。
AOF 包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
AOF 命令写入
AOF 命令写入的内容直接是文本协议格式。AOF 文件是纯文本文件,其内容正是 Redis 客户端向 Redis 发送的原始通信协议的内容。
例如:set hello world 这条命令,在 AOF 缓冲区会追加如下文本:
$3 : set 指令的长度。set 长度 == 3
set:代表着 set 指令
$5:hello key 对应的值长度
hello:key 值
$5:world value 对应的值长度
world:value 值
AOF 为什么直接采用文本协议格式?可能的理由如下:
文本协议具有很好的兼容性。 - 开启 AOF 后,所有写入命令都包含追加操作,直接采用协议格式,避免二次处理开销。
文本协议具有可读性,方便直接修改和处理。
AOF 为什么把命令追加到 aof_buf 中?
Redis 使用单线程响应命令,如果每次写 AOF 文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。
先写入缓冲区 aof_buf 中,还有另一个好处,Redis 可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡。
AOF 配置
在 redis 的 redis.conf 配置文件中:
打开文件,找到 APPEND ONLY MODE 对应内容,默认情况下 Redis 没有开启 AOF(append only file)方式的持久化,通过 appendonly 参数开启:
AOF 文件的保存位置和 RDB 文件的位置相同
redis 默认关闭,开启需要手动把 no 改为 yes
指定本地数据库文件名,默认值为 appendonly.aof
Redis 支持三种不同的刷写模式,Redis 提供了多种 AOF 缓冲区同步文件策略,由参数 appendfsync 控制:
每次有数据修改发生时都写入 AOF 文件中
每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用
Redis 服务的 AOF 文件同步策略:
always (最安全但是最慢) :同步持久化,每次发生数据变化会立刻写入到磁盘中。性能较差当数据完整性比较好(慢,安全)
everysec (默认的同步策略):出厂默认推荐,每秒异步记录一次(默认值)
no (最快但是不安全):不同步
当进程中 BGSAVE 或 BGREWRITEAOF 命令正在执行时不阻止主进程中的 fsync()调用(默认为 no,当存在延迟问题时需调整为 yes).
虽然每次执行更改数据库内容的操作时,AOF 都会将命令记录在 AOF 文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每 30 秒会执行一次同步操作,以便将硬盘缓存中的内容真正地 写入硬盘,在这 30 秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用 AOF 持久化的应用都无法容忍这样的损失,这就需要 Redis 在写入 AOF 文件后主动要求系统将缓存内容同步到硬盘中。
AOF 重写机制
随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入了 AOF 重写机制压缩文件体积。AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程。
AOF 重写原理
重写后的 AOF 文件为什么可以变小?有如下原因:
进程内已经超时的数据不再写文件。
旧的 AOF 文件含有无效命令,如 del key1、set a 111、set a 222 等。重写使用进程内数据直接生成,这样新的 AOF 文件只保留最终数据的写入命令。
多条写命令可以合并为一个,如 lpush list a、lpush list b、 lpush list c 可以转化为:lpush list a b c。
为了防止合并的数据过大造成客户端缓冲区溢出,对于 list、set、hash、zset 等类型,以 64 个元素为界拆分为多条。
AOF 重写原理
AOF 的工作原理是将写操作追加到文件中,文件的冗余内容会越来越多。所以聪明的 Redis 新增了重写机制。当 AOF 文件的大小超过所设定的阈值时,Redis 就会对 AOF 文件的内容压缩。
Redis 会 fork 出一条新进程,读取内存中的数据,并重新写到一个临时文件中。并没有读取旧文件。最后替换旧的 aof 文件。
需要压缩重写的案例:
AOF 带来了另一个问题,持久化文件会变得越来越大。比如,我们调用 INCR test 命令 100 次,文件中就必须保存全部的 100 条命令,但其实 99 条都是多余的。
因为要恢复数据库的状态其实文件中保存一条 SET test 100 就够了。
为了合并重写 AOF 的持久化文件,Redis 提供了 bgrewriteaof 命令。收到此命令后,Redis 将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件,以此来实现控制 AOF 文件的合并重写(会将重写过程中接收的的新的指令和生成新的重写后 AOF 文件中的指令进行合并)。
注意:由于是模拟快照的过程,因此在重写 AOF 文件时并没有读取旧的 AOF 文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的 AOF 文件
AOF 重写目的
AOF 重写降低了文件占用空间,除此之外,另一个目的是:更小的 AOF 文件可以更快地被 Redis 加载。
AOF 重写过程可以手动触发和自动触发:
配置重写 rewrite 触发机制
手动触发:直接调用 bgrewriteaof 命令
自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定自动触发时机
auto-aof-rewrite-min-size: 限制了允许重写的最小 AOF 文件,通常在 AOF 文件很小的时候即使其中有些冗余命令也可是可以忽略的。
auto-aof-rewrite-percentage: 当前的 AOF 文件大小超过上一次重写的 AOF 文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的 AOF 大小为依据。
注意,执行 AOF 重写请求时,父进程依然响应命令,Redis 使用"AOF 重写缓冲区"保存这部分新数据,防止新 AOF 文件生成期间丢失这部分数据。
解释含义:当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发。一般都设置为 3G,64M 太小了, 这里的“一倍”和“64M” 可以通过配置文件修改。
AOF 与 RDB 二者选择的标准(结合上一篇文章)
权衡的标准是对数据的一致性要求和性能之间的平衡。看系统是愿意牺牲一些性能,换取更高的缓存一致性(AOF),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行 save 的时候,再做备份(RDB)。
AOF 的执行流程
开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入硬盘中的 AOF 文件。
AOF 的工作流程操作有:
命令写入(append)
文件同步(sync)
文件重写(rewrite)
重启加载(load)
AOF 流程如下:
所有的写入命令会追加到 aof_buf(缓冲区)中。
AOF 缓冲区根据对应的策略向硬盘做同步操作。
随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
当 Redis 服务重启时,可以加载 AOF 文件进行数据恢复。
AOF 重启加载
AOF 和 RDB 文件都可以用于服务器重启时的数据恢复。
AOF 持久化开启且存在 AOF 文件时,优先加载 AOF 文件;
AOF 关闭或者 AOF 文件不存在时,加载 RDB 文件;
加载 AOF/RDB 文件城后,Redis 启动成功;
AOF/RDB 文件存在错误时,Redis 启动失败并打印错误信息。
根据 AOF 文件恢复数据
正常情况下,将 appendonly.aof 文件拷贝到 redis 的安装目录的 bin 目录下,重启 redis 服务即可。但在实际开发中,可能因为某些原因导致 appendonly.aof 文件格式异常,从而导致数据还原失败,可以通过命令 redis-check-aof --fix appendonly.aof 进行修复 。从下面的操作演示中体会。
若打算使用 Redis 的持久化。建议 RDB 和 AOF 都开启。其实 RDB 更适合做数据的备份,留一后手。AOF 出问题了,还有 RDB。
AOF 的优缺点
AOF 优点
数据的完整性和一致性更高
AOF 劣势
相同数量的数据集而言,AOF 文件通常要大于 RDB 文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
同步策略的不同,AOF 在运行效率上往往会慢于 RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和 RDB 一样高效。
数据的完整性和一致性更高因为 AOF 记录的内容多,文件会越来越大,数据恢复也会越来越慢。
对于相同数量的数据集而言,AOF 文件通常要大于 RDB 文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
总结
每秒同步策略的效率是比较高的,同步禁用策略的效率和 RDB 一样高效。
AOF 的数据完整性比 RDB 高,但记录内容多了,会影响数据恢复的效率。
RDB 与 AOF 二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行 save 的时候,再做备份(rdb)。
Redis 允许同时开启 AOF 和 RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动 Redis 后 Redis 会使用 AOF 文件来恢复数据,因为 AOF 方式的持久化可能丢失的数据更少。
若只打算用 Redis 做缓存,可以关闭持久化。
版权声明: 本文为 InfoQ 作者【李浩宇/Alex】的原创文章。
原文链接:【http://xie.infoq.cn/article/a11c408763e3b03e849b3439f】。文章转载请联系作者。
评论