Redis(三):AOF 持久化


除了 RDB 持久化之外,Redis 还提供了 AOF(Append Only File)持久化功能。RDB 持久化是保存数据库中键值对数据来记录数据库状态的,AOF 以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。 AOF 的主要作用是解决了数据持久化的实时性。

1、AOF 持久化工作流程

AOF 的工作流程包括: 命令写入(append)、文件同步(sync)、文件重写(rewrite)、重启加载(load)
在这里插入图片描述

1)所有的写入命令会追加到 aof_ buf(缓冲区)

2)缓冲区根据对应的策略向硬盘做同步操作

3)随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的

4)当 Redis 服务重启时,可以加载 AOF 文件进行数据恢复

1.1、命令写入(append)

当 AOF 持久化功能打开的情况下,Redis 服务在执行完一个写命令之后,会以Redis协议的格式将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾。

struct redisServer { 
    // ... 
    // AOF 缓冲区 
    sds aof_buf; 
    // ... 
};

如果向服务端执行以下命令:

127.0.0.1:6379> set hello world
OK

该命令执行之后,redis 服务会将以下协议内容追加到 aof_buf 缓冲区的末尾

*3\r\n$3\r\nset\r\n$3\r\nhello\r\n$5\r\nworld\r\

1.2、文件同步(sync)

Redis 服务器进程就是一个事件循环(loop),这个循环中的文件事件负责接收客户端的命令 请求,以及向客户端发送命令回复,而时间事件则负责执行像 serverCron 函数这样需要定时 运行的函数。

因为服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到 aof_buf 缓冲区, 所以 在服务器每次结束一个事件循环之前,它都会调用 flushAppendOnlyFile 函数,考虑是否需要将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件里面。

flushAppendOnlyFile 函数的行为由配置的 appendfsync 的值来决定,不同值产生的行为不同:

1)appendfsync always

命令写入 aof_buf 后调用系统 fsync 操作同步到 AOF 文件

2)appendfsync everysec(默认)

命令写入 aof_buf 后调用系统 write 操作。fsync 同步文件操作由专门线程每秒调用一次

3)appendfsync no

命令写入 aof_buf 后调用系统 write 操作,不对 AOF 文件做 fsync 同步,同步硬盘操作由操作系统负责,通常间隔是 30 秒

系统调用 write 和 fsync 说明:

  • write 操作会触发延迟写(delayed write)机制。Linux 内核提供页缓冲区来提高硬盘 IO 性能。write 操作在写入系统缓冲区后直接返回。同步硬盘操作依赖于系统调度机制,同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
  • fsync 针对单个文件操作,做强制硬盘同步,fsync 将阻塞直到写入硬盘完成后返回,保证了数据持久化。

除了 write、fsync,Linux 还提供了 sync、fdatasync 操作,具体 API 说明参见:http://linux.die.net/man/2/write,http://linux.die.net/man/2/fsync,http://linux.die.net/man/2/sync,http://linux.die.net/man/2/fdatasync。

为了提高文件的写入效率,在现代操作系统中,当用户调用 write 函数,将一些数据写入到 文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间 被填满、或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。

这种做法虽然提高了写入效率,但也为写入数据带来了安全问题,因为如果计算机发生停机, 那么保存在内存缓冲区里面的数据将会丢失。

因此,系统提供了fsync 和 fdatasync 两个同步函数,它们可以强制让操作系统立即将缓冲区 中的数据写入到硬盘里面,从而确保写入数据的安全性。

1.3、AOF 文件重写(rewrite)

随着命令不断写入 AOF, 文件会越来越大,为了解决这个问题,Redis 引入AOF 重写机制压缩文件体积。AOF 文件 重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程。

AOF 重写不仅减小了文件的体积,而且提高了被 Redis 服务加载的速度。

1.3.1、重写后的AOF文件为什么会变小

1、已经超时数据的命令不再写入文件

2、旧的AOF文件含有很多无效的命令,如:del key、hdel key2、strem keys等。重写时使用进程内数据直接生成,新的AOF文件只会保留最终数据的写入命令

3、多条写命令可以合并为一条,如:lpush list a、lpush list b、lpush list c 可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以 64 个元素为界拆分为多条。

1.3.2、AOF 重写机制的触发

AOF 重写机制可以手动触发和自动触发

1.3.2.1、手动触发

调用 bgrewriteaof 命令

1.3.2.2、自动触发:

自动触发根据 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 参数确定触发时机

  • auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值。
  • auto-aof-rewrite-min-size:运行AOF重写时文件最小体积,默认 64MB

自动触发时机= aof_current_size>auto-aof-rewrite-min-size&&(aof_current_ size-aof_base_size)/ aof_base_ size>= auto-aof-rewrite-percentage

1.3.3、AOF 文件重写流程

在这里插入图片描述

(1)、执行AOF重写请求

如果当前进程正在执行 AOF 重写,请求不执行并返回如下信息:

ERR Background append only file rewriting already in progress

如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再执行,返回如下信息:

Background append only file rewriting scheduled

(2)、 父进程执行fork创建子进程,开销等同于bgsave过程。

(3.1)、 主进程fork完成后,继续响应其他命令请求。所有修改命令依然写入AOF缓冲区并根据 appendfsync 策略同步到硬盘,保证AOF机制的正确性。

(3.2)、 由于fork操作使用写时复制(copy-on-write),子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,Redis 使用AOF重写缓冲区保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。

(4)、 子进程根据内存快照,按照命令合并规则写入到新的AOF文件。每次批量写入硬盘数据量由 aof-rewrite-incremental-fsync 控制,默认为 32MB,防止单次刷盘数据过多造成硬盘阻塞。

(5.1)、 新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息

(5.2)、 父进程把AOF重写缓冲区的数据写入到新的AOF文件

(5.3)、 使用新AOF文件替换老文件,完成AOF重写。

1.3.4、重启加载流程

在这里插入图片描述

1)、AOF持久化开启且存在AOF文件时,优先加载AOF文件,相应日志如下:

* DB loaded from append only file: 2.256 seconds

2)、AOF持久化关闭或AOF文件不存在时,加载RDB文件,相应日志如下:

* DB loaded from disk: 1.325 seconds

3)、持久化文件AOF或RDB文件加载成功后,Redis启动成功

4)、AOF或RDB文件存在错误时,Redis启动失败并打印错误日志

2、AOF 持久化的效率和安全性

appendfsync 选项的值直接决定AOF 持久化功能的效率和安全性。

1)当 appendfsync 的值为 always 时,服务器在每个事件循环都要将 aof_buf 缓冲区中的所有 内容写入到 AOF 文件, 并且同步 AOF 文件, 所以 always 的效率是 三个选项中最慢的,但 从安全性来说, always 也是最安全的,因为即使出现故障停机,AOF持久化也只会丢失一个事件循环中所产生的命令数据。

2)当 appendfsync 的值为 everysec 时,服务器在每个事件循环都要将 aof_ buf 缓冲区中的所有内容写入到AOF 文件,并且每隔一秒就要在子线程中对AOF 文件进行一次同步。 从效率上来讲, everysec 足够快,并且就算出现故障停机,数据库也只丢失一秒钟的命令数据。

3)当 appendfsync 的值为 no 时,服务器在每个事件循环都要将 aof_ buf 缓冲区中的所有内容 写入到 AOF 文件,至于何时对 AOF 文件进行同步,则由操作 系统控制。 因为处于 no 模式 下的 flushAppendOnlyFile 调用无须执行同步操作,所以该模式下的 AOF 文件写入速度总是最快的,不过因为这种模式会在系统缓存中积累一段时间的写入数据,所以该 模式的单次同步时长通常是三种模式中时间最长的。当出现故障停机时,使用 no 模式的服务器将丢失上次同步 AOF 文件之后的所有写命令数据。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值