AOF持久化是如何实现的?

  • 除了RDB持久化功能之外,Redis还提供了AOF持久化功能。与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。如下图
发送写命令
保存被执行的写命令
客户端
服务器
AOF文件

例子:
输入set msg "hello"
查看AOF文件

2\r\n$6\r\nSELECT\r\n$1\r\n0\r\n
3\r\n$3\r\nSET\r\n$3\r\nmsg\r\n$5\r\nhello\r\n

可以看见的是redis服务器自动给我们加了个SELECT命令。

  • 服务器启动时,会载入和执行AOF文件。

AOF持久化的实现

  1. 命令追加
  • 当AOF持久化功能开启时,每执行完一个命令后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾.
  1. AOF文件的写入和同步
  • Redis的服务进程是一个事件循环,每次结束一个事件循环之前,服务进程调用flushAppendOnlyFile函数,考虑是否将aof_buf缓冲区中的内容写入和保存到AOF文件。
  • flushAppendOnlyFile 函数的行为由服务器配置的 appendfsync 选项的值来决定
appendfsync 选项的值flushAppendOnlyFile 函数的行为
always将 aof_buf 缓冲区中的所有内容写入并同步到 AOF 文件
everysec将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 如果上次同步 AOF 文件的时间距离现在超过一秒钟, 那么再次对 AOF 文件进行同步, 并且这个同步操作是由一个线程专门负责执行的
no将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 但并不对 AOF 文件进行同步, 何时同步由操作系统来决定

注意
如果用户没有主动为 appendfsync 选项设置值, 那么 appendfsync 选项的默认值为 everysec

文件的写入和同步

  • 为了提高文件的写入效率, 在现代操作系统中, 当用户调用 write 函数, 将一些数据写入到文件的时候, 操作系统通常会将写入数据暂时保存在一个内存缓冲区里面, 等到缓冲区的空间被填满、或者超过了指定的时限之后, 才真正地将缓冲区中的数据写入到磁盘里面。
  • 如果计算机发生停机, 那么保存在内存缓冲区里面的写入数据将会丢失。
  • 系统提供了 fsync 和 fdatasync 两个同步函数, 它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面, 从而确保写入数据的安全性。

AOF持久化的效率和安全性

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

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

  • 当 appendfsync 的值为 no 时, 服务器在每个事件循环都要将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 至于何时对 AOF 文件进行同步, 则由操作系统控制。

因为处于 no 模式下的 flushAppendOnlyFile 调用无须执行同步操作, 所以该模式下的 AOF 文件写入速度总是最快的, 不过因为这种模式会在系统缓存中积累一段时间的写入数据, 所以该模式的单次同步时长通常是三种模式中时间最长的: 从平摊操作的角度来看, no 模式和 everysec 模式的效率类似, 当出现故障停机时, 使用 no 模式的服务器将丢失上次同步 AOF 文件之后的所有写命令数据。

AOF文件的载入和数据还原

服务器只要执行AOF文件里面的所有命令,就能还原服务器关闭之前的数据库状态。

Created with Raphaël 2.2.0 服务器启动 创建伪客户端 从AOF文件中读取命令 使用伪客户端执行命令 AOF文件中的命令是否全部执行完毕? 载入完毕 yes no

AOF重写

服务器运行时间变长,执行的命令变多了,那么AOF文件中的内容也会变得越来越多,体积越来越大,这样可能会影响服务器的运行。

  • 可以通过读取数据库的状态来生成新的AOF文件,代替老旧的AOF文件。
  • 新的AOF文件只包含有当前数据库内容的插入命令。这些命令是必须被执行的,所以新的AOF文件不会浪费任何硬盘空间。
  • 为了防止插入一个元素就执行一条命令的情况,我们可以一条插入命令包含多个元素,这样避免了在执行命令的时候造成客户端输入缓冲区溢出。通常情况下,如果一个列表或其他所包含的元素数量超过64时,每条插入命令都将包含64个元素(最后一条命令除外)。

AOF后台重写

  • 由于redis是单线程运行的,如果直接执行重写AOF文件的命令,那么服务器在重写期间将无法处理客户端的发送的命令请求。
  • 所以AOF重写功能在子进程中执行,保证了父进程(服务进程)任能够处理客户端的请求命令,使用了进程而不是线程,避免了使用锁的情况,保证了数据的安全性。
  1. 如果在子进程在重写的过程中,服务器进程处理了新的命令,导致写前数据库状态和写后AOF保存的数据库状态不一致。
    为了解决这个问题。提出了AOF重写缓冲区的概念
Created with Raphaël 2.2.0 创建AOF重写子进程 追加命令至AOF缓冲区和AOF重写缓冲区 重写是否完成? 将AOF重写缓冲区的内容写入新AOF文件 新AOF文件替换旧AOF文件 yes no

为什么不直接使用AOF缓冲区?

  • AOF缓冲区的内容是定期被写入和同步到AOF文件中去,那么从创建子进程开始,服务器执行的所有命令都会被记录到AOF重写缓冲区中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值