redis服务器之AOF持久化

大耗子 2020年12月28日 52次浏览

AOF持久化

除了RDB持久化功能之外, Redis还提供了AOF(Append Only File) 持久化功能。 与
RDB持久化通过保存数据库中的键值对来记录数据库状态不同, AOF持久化是通过保存Redis
服务器所执行的写命令来记录数据库状态的。

SET msg "hello"
SADD fruits "apple" "banana" "cherry"
RPUSH numbers 128 256 512

例如上面的例子,数据库做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
5\r\n$4\r\nSADD\r\n$6\r\nfruits\r\n$5\r\napple\r\n$6\r\nbanana\r\n$6\r\ncherry\r\n
5\r\n$5\r\nRPUSH\r\n$7\r\nnumbers\r\n$3\r\n128\r\n$3\r\n256\r\n$3\r\n512\r\n

总之,每个参数都会用\r\n分隔开,然后每个参数前面还要表明参数长度,也是用\r\n分开,最前面标注有几个参数。

AOF文件的写入和同步

  • Redis的服务器进程就是一个事件循环(loop),这个循环中的文件事件负责接收客户端的命令请求, 以及向客户端发送命令回复, 而时间事件则负责执行像serverCron函数这样需要定时运行的函数。
  • 因为服务器在处理文件事件时可能会执行写命令, 使得一些内容被追加到aof_buf缓冲区里面, 所以在服务器每次结束一个事件循环之前, 它都会调用flushAppendOnlyFile函数, 考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里面。
  • 不同的appendfsync值也会产生不同的持久化行为。
appendfsync选项值行为
always将aof_buf缓冲区的所有内容写入并同步到AOF文件中
everysec将aof_buf缓冲区的所有内容写入并同步到AOF文件中,每一秒进行一次对AOF文件进行同步
no将aof_buf缓冲区的所有内容写入并同步到AOF文件中,但不对AOF文件进行同步,同步时机由操作系统决定
  • 通常情况下always丢失只会丢失一条命令,everysec丢失1秒内的命令,no则会丢失上一次同步AOF后的所有命令。

AOF文件的载入和数据还原

  • 由于AOF文件中存储了所有的些命令。所以服务器只需要重新执行一遍命令就还原出了数据。
  • 在实际上的操作中,AOF的还原是通过创建一个不带网络的伪客户端,通过发送执行命令的方式,把数据库还原出来。效果就和有正常客户端建立数据一样。

AOF的重写

  • 由于redis长期的运行,数据库中会出现很多冗余数据,AOF文件越来越大,此时则需要做AOF重写操作,将冗余操作给清除掉,减少AOF文件数据大小。
  • 例如做了添加a,删除a,在添加a,本来应该执行3条命令,但是AOF重写后,命令变得只有添加a一条了。相当于优化了命令的执行,只执行了还原当前数据库状态所必须的命令。所以新AOF不会浪费任何硬盘空间。
  • 但是redis为了防止内存溢出,也不会无限合并,例如一个集合键超过64个元素,redis就会分离开,多条命令执行。
  • 在实际过程中,重写并不对旧的AOF文件进行任何的读操作。而是直接通过读取数据库中的键值对来进行编写新AOF文件的。

AOF的后台重写

  • 由于重写一个AOF文件会进行大量的写操作,所以调用这个函数的线程被长期占用,redis将他作为一个子进程运行,防止影响客户事件。使用进程也有两个好处:
  1. 避免了影响客户线程。
  2. 由于不同进程拥有了自己的数据副本,两个进程各用自己的数据,保证的数据的安全性。(线程共用资源,有可能客户事件修改了数据)
  • 分离到进程重写AOF后,由于客户事件也在处理,必然会出现AOF重写后的数据和现在的数据不一样的情况,所以为了解决这个问题,Redis服务器设置了一个AOF重写缓冲区, 这个缓冲区在服务器创建子进程之后开始使用, 当Redis服务器执行完一个写命令之后, 它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区。
  • 在AOF重写完成后,子进程会发送信号给父进程,父进程收到信号后,将重写缓冲区的内容追加到新的AOF的尾部,此时新的AOF才算正式完成。新AOF覆盖旧AOF。