AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。被写入AOF文件的所有命令都是以Redis的命令请求协议格式(纯文本)保存的。

一,AOF持久化的实现

1.命令追加

当AOF持久化功能处于打开状态时,服务器在执行完一个写命令后,会以协议格式把被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾:

struct redisServer{

  //AOF缓冲区

  sds aof_buf;

}

2.AOF文件的写入和同步

命令请求会先保存到AOF缓冲区中,然后在写入并同步到AOF文件。

Redis服务器进程是一个事件循环,在这个循环中有文件事件,有时间事件。文件事件负责接收客户端的命令请求和向客户端发送命令回复。时间事件负责执行定时运行的函数,比如:serverCron函数。

伪代码:

def eventLoop():

  while true:

    //处理文件事件,接收命令请求以及发送命令回复。处理命令请求时可能会有新内容被追加到aof_buf缓冲区中

    processFileEvents()

    //处理时间事件

    processTimeEvents()

    //考虑是否要把 aof_buf中的内容写入和保存到AOF文件中

    flushAppendOnlyFile()

写入:在现代操作系统中,当数据写入到文件中时,会调用write函数。操作系统会将写入数据暂时保存在一个内存缓存区中,等到缓冲区空间满的时候,才真正将缓冲区中的数据写入到磁盘中。

同步:同时系统也提供了同步函数,它可以强制让操作系统立即将缓冲区中的数据写入到磁盘中。

由上面的代码可以知道,在每个事件循环都会调用flushAppendOnlyFile函数,flushAppendOnlyFile函数的行为由appendfsync的值决定:

always:服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件中,并同步AOF文件(写入并同步)(,把aof_buf数据写入并同步到AOF文件中)

everysec:服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件中(先写入),并且每隔一秒就在子线程中对AOF文件进行一次同步(每隔一秒同步)。

no:服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件中(先写入),至于什么时候同步,由操作系统控制(不知道啥时候同步)。在该模式下的flushAppendOnlyFile的调用不需要同步执行。

二,AOF文件的载入和数据还原

1.数据还原:AOF文件中包含了重建数据库状态的所有写命令,所以服务器只要读入并重新执行一遍AOF文件里保存的写命令,就可以还原数据

2.步骤:

创建一个不带网络连接的伪客户端。(为什么是为客户端:Redis的命令只能在客户端上下文中执行,为什么是不带网络连接:命令来自AOF文件而不是网络连接)

从AOF文件中分析并读取一条写命令

使用伪客户端执行被读出的写命令

一直执行步骤2,3 。直到AOF文件中的所有写命令都被处理完毕

三,AOF重写

1.什么是AOF重写?

为了解决AOF文件体积膨胀,Redis服务器创建一个新的AOF文件替代现有的AOF文件,新旧两个文件保存的数据库状态相同,但是新AOF文件不会包含冗余命令。

Redis把新AOF文件替换旧AOF文件的功能叫 AOF文件重写。

2.AOF文件重写的实现

注意:AOF文件重写并不需要对现有的AOF文件进行如何读取,分析或写入操作,这个功能是通过读取服务器当前的数据库状态来实现的。

原理:首先从数据库中读取键现在的值,然后用一条命令记录键值对,代替之前记录这个键值对的多条命令。

【如果服务器想要用尽量少的命令来记录键的状态,那么最简单的办法不是去读取和分析现有AOF文件的内容,而是直接从数据库中读取键的值,然后用一条写命令来替代保存在AOF文件中的多条写命令,这样就可以把保存键的多条命令减少为一条。】

在实际中,为了避免在执行命令时造成客户端输入缓冲区溢出。在处理有多个元素的键时,会先检查键包含的元素数量,如果超过了一定的值,会使用多条命令来记录键的值。比如一个列表键包含了超过64个项,那么重写程序会用多条rpush命令来保存这个列表。

3.AOF后台重写

问题:由于Redis服务器使用单个线程处理命令请求,当服务器调用aof_rewrite函数时,在重写AOF文件期间,服务器无法处理客户端发送来的命令请求

解决:把AOF重写程序放到子进程中执行,这样子进程重写期间,父进程可以继续处理命令请求。并且子进程带有父进程的数据副本。

那么问题又来了:在子进程进行AOF重写期间,服务器进程在处理命令请求时可能会改变数据库状态,导致服务器当前数据库状态和重写后的AOF文件保存的数据库状态不一致

为了解决数据不一致问题,Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在创建子进程之后使用,当Redis服务器执行完一个写命令后,会同时把这个写命令发送给AOF缓冲区和AOF重写缓冲区。

在子进程执行AOF重写期间,服务器需要:

执行客户端发送过来的命令

将执行后的写命令追加到AOF缓冲区

将执行后的写命令追击到AOF重写缓冲区

当子进程完成重写工作后,向父进程发送一个信号,父进程在接到这个信号后,把AOF重写缓冲区中的所有内容写到新AOF文件中,并对新的AOF文件进行改名,覆盖现有的AOF文件。

第二部分之AOF持久化(第十一章)的更多相关文章

  1. 第二部分之RDB持久化(第十章)

    RDB持久化功能所生成的RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态.(数据库状态:服务器中的非空数据库以及它们的键值对统称为数据库状态) 一.RDB文件的创建 ...

  2. o'Reill的SVG精髓(第二版)学习笔记——第十一章

    第十一章:滤镜 11.1滤镜的工作原理 当SVG阅读器程序处理一个图形对象时,它会将对象呈现在位图输出设备上:在某一时刻,阅读器程序会把对象的描述信息转换为一组对应的像素,然后呈现在输出设备上.例如我 ...

  3. 第二部分之Redis服务器(第十四章)

    Redis服务器复制和多个客户端建立网络连接,处理客户端发送的命令请求,在数据库中保存客户端执行命令所产生的数据. 一,命令请求的执行过程 客户端向服务器发送命令请求 set key value 服务 ...

  4. JavaScript高级程序设计:第二十一章

    第二十一章 Ajax与Comet 一.XMLHttpRequest对象 1.XHT的用法 在使用XHR对象时,要调用的第一个方法时open( ),它接受3个参数:要发送的请求的类型.请求的URL和表示 ...

  5. 第二十一章 Django的分页与cookie

    第二十一章 Django的分页与cookie 第一课 模板 1.模板的继承 在Template目录下新建模板master.html <!DOCTYPE html> <html lan ...

  6. Gradle 1.12用户指南翻译——第二十一章. Gradle 插件

    昨天晚上只顾着和女朋友看<匆匆那年>电视剧的最后几集,所以说好的Android文档<Gradle 插件用户指南>第五章自然也没翻译多少.所以今天也发不了第五章的翻译了,就发几个 ...

  7. “全栈2019”Java多线程第二十一章:同步代码块产生死锁的例子

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  8. “全栈2019”Java异常第二十一章:finally不被执行的情况

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  9. “全栈2019”Java第二十一章:流程控制语句中的决策语句if

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. Oracle day05 建表_约束

    表的创建 标准的建表语法 : CREATE TABLE [schema.] table (column datatype [DEFAULT expr], ... ); 使用子查询创建表的语法 CREA ...

  2. WEB前端开发记录PS常见操作

    1.相邻2个层合并的快捷键方法:先选择上面的一个层,再按ctrl+e. 2.合并一个组内的多个层或组:在该组单击右键,选择“转换为智能对象”,然后可对其进行其它操作,比如:截取该组的为一张图片:ctr ...

  3. 51nod“省选”模测第二场 C 小朋友的笑话(线段树 set)

    题意 题目链接 Sol 直接拿set维护\(li\)连续段.因为set内的区间互不相交,而且每个线段会被至多加入删除一次,所以复杂度是对的. #include<bits/stdc++.h> ...

  4. 转:从输入url到显示网页发生了什么

    在浏览器中输入url到显示网页主要包含两个部分: 网络通信和页面渲染 互联网内各网络设备间的通信都遵循TCP/IP协议,利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信.分层由高到低 ...

  5. #WEB安全基础 : HTML/CSS | 0x5a标签拓展和class、id属性的使用

    a标签不只是能链接到其他网页,也能链接到网页中的元素 class属性让你用CSS对特定的元素进行修饰 这些是一个网页设计者的有力武器 这节课还是一个index.html文件   以下是代码 <h ...

  6. Apex 中的自定义迭代器

    迭代器 迭代器(iterator)可以遍历一个集合变量中的每个元素.Apex提供了Iterator接口来让开发者实现自定义的迭代器. Iterator接口 Iterator接口定义了两个函数: has ...

  7. linux下编译protobuf

    这里我介绍两种方法,一是直接ccmake配置,二是修改cmake文件下面的CMakeList.txt文件 第一种方法:配置ccmake 1.安装sudo apt-get install cmake-c ...

  8. rpc接口调用以太坊智能合约

    rpc接口调用以太坊智能合约 传送门: 柏链项目学院   在以太坊摸爬滚打有些日子了,也遇到了各种各样的问题.这几天主要研究了一下如何通过rpc接口编译.部署和调用合约.也遇到了一些困难和问题,下面将 ...

  9. VMware虚拟机在仅主机模式下的网卡无法动态获取IP

    自己在VMware虚拟机中开启一台主机的时候,发现比以往的开机速度慢了好多,起初不以为然,直到用Xshell通过ssh远程连接eth1的ip地址才发现连接失败(这个ip是之前eth1正常的时候获取的i ...

  10. Docker: 构建Nginx,PHP,Tomcat基础镜像

    Usage: docker build [OPTIONS] PATH | URL | - [flags] Options: -t, --tag list # 镜像名称 -f, --file strin ...