Redis aof持久化

Redis支持两种持久化方式:rdb与aof,上一篇文章中已经大致介绍了rdb的持久化实现,这篇文章主要介绍aof实现。

与rdb方式相比,aof会使用更多的存储空间,因为它将数据以客户端命令的形式进行存储,并使用ascii编码。但它也有相应的优点,如支持append的方式保存db内容的变动,不需要像rdb方式一样一旦内容有变动,便需要重新完整生成文件才能将变动保存到文件中;同时在子进程持久化的过程中,可以累积客户端的命令到缓存中,最后将缓存内容添加到持久化生成的文件的末尾,几乎可以实现不丢失内容的持久化。

1. aof命令格式

aof的持久化方式不仅可以将client端发送来的命令直接添加到aof文件的末尾,还可以将内存中的数据重写为命令的形式。redis中定义aof中的一条完整命令格式如下:

*count\r\n{$len\r\ncontent\r\n}

以*开头,后面接这条命令中的参数数目count,并以\r\n结束;后面的每一个参数都以$开头,接参数长度len,并以\r\n结束,后面跟实际的参数内容,并以\r\n结束。

举例,命令RPUSH “key1” 1 2 3 4这条命令在aof文件中的表示如下:

*\r\n$\r\nRPUSH\r\n$\r\nkey1\r\n\$\r\n1\r\n$\r\n2\r\n$\r\n3\r\n$\r\n4\r\n

这表示命令中有6个参数,第1个参数长度为5,值为RPUSH,第2个参数长度为4,值为key1,以此类推。

而命令 set “key2” “hello, world”这条命令在aof文件中表示如下:

*\r\n$\r\nset\r\n$\r\nkey2\r\n$\r\nhello, world\r\n

2. db中的数据rewrite

对于已经存储在db中的数据,如果需要以aof的方式进行持久化,那么需要将其重写为命令的形式,这个功能通过aof.c源文件中的rewriteAppendOnlyFileRio函数实现。它会遍历所有的db字典,并遍历每一个字典中的所有key-value对,进行rewrite。重写规则大致如下:

  1. 遍历每一个db,首先添加一条命令"*2\r\n$6\r\nSELECT\r\n$len\r\nj\r\n",其中的len为db索引的字符串形式的长度,j为其字符串表示,每一个db仅在遍历重写它的key-value对之前添加该命令。
  2. 遍历每一对key-value对,根据其类型,添加正确的命令头,一条命令尽可能多的添加数据,但一条命令中参数个数有限制,超过限制则拆分为多条命令。

举例,如果内存中存在一个”name1” “faker”的key-value对,重写命令如下:

*\r\n$\r\nset\r\n$\r\nname\r\n$\r\nfaker\r\n

如果内存中存在一个list,key为”key1”,内容为1 2 3 4,那么其重写后的命令如下:

*\r\n$\r\nRPUSH\r\n$\r\nkey1\r\n\$\r\n1\r\n$\r\n2\r\n$\r\n3\r\n$\r\n4\r\n

3. 命令缓存

redis中aof持久化使用到了两类缓存,一类缓存用于在子进程运行过程中,保存客户端的命令,它是server全局结构的一个list成员aof_rewrite_buf_blocks,该list的节点值类型为

typedef struct aofrwblock {
unsigned long used, free;
char buf[AOF_RW_BUF_BLOCK_SIZE];
} aofrwblock;

当需要将命令保存到aof文件中,而此时server.aof_child_pid != -1(即aof子进程正在运行),命令被添加到aof_rewrite_buf_blocks链接的缓存中。

这个buffer中的数据会通过pipe发送给子进程,发送函数为aofChildWriteDiffData,这个函数在pipe的写事件发生时调用。相应的子进程中会有从pipe接收这些缓存数据的函数aofReadDiffFromParent,这个函数在子进程持久化数据的过程中被主动调用,并将接收的数据保存到server. aof_child_diff中,在内存数据处理完成后,添加到aof文件末尾。

另一类缓存是server.aof_buf,这是一个sds类型的缓存,它在aof持久化开启,并且没有aof子进程运行时使用,客户端命令始终首先保存到该缓存中,然后周期性将该缓存添加到aof文件中。

通过缓存命令的方式,保证了aof持久化不会丢失更新。

4. aof创建流程

一个aof持久化文件的完整创建流程如下:

  1. rewriteAppendOnlyFileBackground启动子进程将db字典中的数据持久化,即使是以aof方式持久化,仍然可以选择将此时db字典中的数据以rdb的方式进行存储,这部分数据恢复时当然也是调用rdb相应函数。
  2. 等待db字典中的数据持久化完成,将持久化过程中子进程接收的aof_child_diff添加到aof文件的末尾。
  3. 父进程将仍未发送给子进程的aof_rewrite_buf_blocks中的累计更新添加到aof文件末尾。初始化server.aof_buf缓存。
  4. 客户端命令被缓存到server.aof_buf末尾,并定期更新到aof文件中。

生成一个有效的aof文件后,后续db字典中的数据有变动时,只需要将相应的命令添加到aof文件末尾,即可完成相应的持久化,不需要像rdb一样为了保存新的改动,必须重新完整地对db字典进行处理。

aof文件的载入同样相对简单,按行读取,从*后得到参数数目,然后读取指定数目的参数后,执行命令。

redis源码分析(四)--aof持久化的更多相关文章

  1. redis源码分析(三)--rdb持久化

    Redis rdb持久化 Redis支持两种持久化方式:rdb与aof.rdb将一个节点上的内存数据序列化后存储到磁盘中,序列化的数据以尽可能节约空间的方式存储,并非完全的ascii表示.它的优点在于 ...

  2. Redis源码分析:serverCron - redis源码笔记

    [redis源码分析]http://blog.csdn.net/column/details/redis-source.html   Redis源代码重要目录 dict.c:也是很重要的两个文件,主要 ...

  3. redis源码分析之事务Transaction(下)

    接着上一篇,这篇文章分析一下redis事务操作中multi,exec,discard三个核心命令. 原文地址:http://www.jianshu.com/p/e22615586595 看本篇文章前需 ...

  4. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  5. redis源码分析之发布订阅(pub/sub)

    redis算是缓存界的老大哥了,最近做的事情对redis依赖较多,使用了里面的发布订阅功能,事务功能以及SortedSet等数据结构,后面准备好好学习总结一下redis的一些知识点. 原文地址:htt ...

  6. Redis源码分析(dict)

    源码版本:redis-4.0.1 源码位置: dict.h:dictEntry.dictht.dict等数据结构定义. dict.c:创建.插入.查找等功能实现. 一.dict 简介 dict (di ...

  7. ABP源码分析四:Configuration

    核心模块的配置 Configuration是ABP中设计比较巧妙的地方.其通过AbpStartupConfiguration,Castle的依赖注入,Dictionary对象和扩展方法很巧妙的实现了配 ...

  8. ABP源码分析四十七:ABP中的异常处理

    ABP 中异常处理的思路是很清晰的.一共五种类型的异常类. AbpInitializationException用于封装ABP初始化过程中出现的异常,只要抛出AbpInitializationExce ...

  9. Redis源码分析系列

    0.前言 Redis目前热门NoSQL内存数据库,代码量不是很大,本系列是本人阅读Redis源码时记录的笔记,由于时间仓促和水平有限,文中难免会有错误之处,欢迎读者指出,共同学习进步,本文使用的Red ...

随机推荐

  1. Mongoose 内置 CURD 方 法、扩展 Mongoose Model 的静态方法和 实例方法

    Mongoose 内置 CURD 方 法 Mongoose 内置 CURD 方 法文档地址:https://mongoosejs.com/docs/queries.html 常用的方法如下: Mode ...

  2. Kafka(三)High Availability 高可用

    参考文档: http://www.jasongj.com/2015/04/24/KafkaColumn2/#ACK%E5%89%8D%E9%9C%80%E8%A6%81%E4%BF%9D%E8%AF% ...

  3. 记一次phpmyadmin 4.8.1 远程文件包含漏洞(BUUCTF web)

    题目很简单,一个滑稽 打开源码,发现存在source.php文件 于是访问文件,发现出现一串php源码 提示存在hint.php,于是访问发现一句话 flag not here, and flag i ...

  4. 冰多多团队-第十次Scrum例会

    冰多多团队-alpha第十次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 牛雅哲 修复了Iatdemo语音接口的bug,整个demo pipeline跑通 为词库设计更多的扩展模块和扩展 ...

  5. python windows下安装pip及rarfile

    python之所以被广泛使用,倒不见得是本身语法简单,而是而nodejs/javascript一样把三方库的依赖管理简化了,而不用和java一样非得通过maven管理,而且还得打包后在classpat ...

  6. TX-LCN5.0.2分布式事务框架源码分析-关键线索罗列-txc部分

    1.注解TxcTransaction2.在其注解接口附近查找aop配置:TransactionAspect3.runTransaction是在执行事务业务代码时的包装逻辑4.transactionSe ...

  7. 【FPGA】always (*) 后代码全部显示注释字体的颜色之解决方法

    2015年08月26日 09:44:05 风雨也无晴 阅读数:1289    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/scottly1/art ...

  8. exception: TypeError: Cannot read property '_modulesNamespaceMap' of undefined at getModuleByNamespac

    用 Vue.extend 创造的组件构造器和组件,默认是不集成 store 和 router 的. 比如 main.js 中的这个,其实是挂载在根组件 vm 中.并不是注入到全局 Vue 中.所以你用 ...

  9. MQTT研究之EMQ:【EMQX使用中的一些问题记录(3)】

    EMQX功能强大,但是帮助信息或者可用资料的确有限,遇到个问题,比较难找到处理的头绪,今天,我要记录的是,使用中出现EMQX宕机,但是呢,启动也启动不了. 今天记录的内容,就以操作EMQX 3.2.3 ...

  10. django在centos生产环境的部署

    # 安装数据库和web服务器nginx # yum install –y nginx mariadb-server # 安装虚拟环境 pip install virtualenv pip instal ...