redis持久化之AOF

号外号外,新建Redis交流讨论群:332160890,欢迎加入!!


一、说明

1.1AOF相关配置项

配置项

作用

aof_rewrite_perc

百分比阈值,当aof的增量超过这个阈值时,开始aofrewrite操作

aof_rewrite_min_size

aof的文件大小超过该值时才有可能进行rewrite操作,默认该值大小为64M

aof_load_truncated

在意外出现AOF读取退出时不会停止,而是删除错误之后的数据

aof_rewrite_incremental_fsync

用于标示在rewrite过程中是否增量进行fsync操作,便于均摊磁盘IO压力,增量每次写入自动进行fsync

aof_no_fsync_on_rewrite

AOFrewrite过程中,正常的aof操作只进行write操作,不进行fsync操作

aof_state

AOF状态,AOF_ON/AOF_OFF/AOF_REWRITE, AOF_REWRITE等待rewrite完成

aof_rewrite_scheduled

已计划进行AOFrewrite过程,这里可能不是立即进行rewrite的时候设置该值

aof_fsync

AOFfsync策略,三种:AOF_FSYNC_NO,不进行fsync操作;AOF_FSYNC_ALWAYS,立即fsync操作;AOF_FSYNC_EVERYSEC,可以延时fsync

1.2 AOF文件中命令格式

——————————————

*<count>\r\n      => count表示后面跟着的参数个数

$<len>\r\n         => len表示后面参数字符串长度

<argv>\r\n         => argv表示参数字符串

——————————————

二、流程分析

2.1、启动时加载AOF文件

1)main函数中调用loadDataFromDisk函数,用于从磁盘中载入数据;

2)在loadDataFromDisk函数中,当redis服务配置中开启了AOF功能时,会调用loadAppendOnlyFile函数执行载入据操作;

3)在loadAppendOnlyFile函数中,会打开AOF文件读取数据,载入数据是通过调用createFakeClient伪装一个客户端读取AOF中的命令,读取完命令后,调用lookupCommand函数获取到当前命令对应的命令处理结构,再通过命令cmd的proc函数执行命令操作,将命令内容保存到内存当中;

2.2、服务过程中正常添加aof内容

1)当有用户与redis交互时,任何命令最终都会通过propagate函数将命令内容传递给AOF当中;

2)在propagate函数中,当符合条件时会调用feedAppendOnly函数执行命令写入AOF过程;

3)在feedAppendOnly函数中,首先判断当前命令处理的数据是否与上一次写入AOF时同一个db,如果不是,增加一个切换数据库的命令(SELECT),并将该命令按照AOF要求格式存入buf中,然后再根据命令不同的处理函数调用不同的catAppendOnly*函数,得到最终当前命令应该存入AOF中的buf数据,在这个函数里面,并不执行写入AOF文件的写入操作(个人认为是为了避免每次单个命令响应慢的思想),而仅仅是将buf的数据存放到aof_buf缓冲区当中,同时如果当前redis正在执行AOF的rewrite过程时,还会将buf中的数据通过aofRewriteBufferAppend函数传递给rewrite子进程(这部分暂时不继续,作为第三部分介绍);

4)上面提到,新增的命令内容并没有直接写入到AOF文件中去,那这些内存数据是什么时候写入进去的呢?实际上,aof_buf中的内容是在另一个函数中被写入的,之所以没有立即写入,一方面是存在命令频繁,单次写入可能会比较浪费的情况;另一方面,这里面的写入不单纯是write操作这么简单,为了保证数据完整性,每次写入是需要真正写入到磁盘中去,因此redis采用了其他的方式来完成这一过程;

5)在remain函数中,在处理事件之前,会调用beforeSleep函数,就是这个函数中,会有写入AOF真正的过程;

6)在beforeSleep函数中是通过调用flushAppendOnlyFile来将aof_buf的缓冲数据写入到磁盘中去的;

7)在flushAppendOnlyFile函数中,首先判断是否有后台async线程正在操作,如果有,则推迟将aof_buf写入AOF文件的时间,但是每次推迟的时间不会超过2秒钟,如果推迟时间已经超过了2秒钟,会进行强制写入并根据策略的不同调用fsync写入磁盘;

2.3、服务AOF内容的重写

1)AOF的rewrite过程一般会在三种情况下发生:1、配置文件中设置了aofrewrite策略;2、当aof的大小超过了设定的值;3、当有客户端要求rewrite操作时(这点是和rdb不一样的,由于AOF是累积数据,存在冗余以及浪费的情况,rdb是一次性的);

2)无论上述那种情况,都会调用rewriteAppendOnlyFileBackground函数来fork子进程,用于执行后台aofrewrite进程,真正执行命令操作的是rewriteAppendOnlyFile函数;

3)在rewriteAppendOnlyFile函数中,会依次读取DB内容,并根据类型的不同,调用不同的类型写入数据函数执行AOF写出命令;

AOF的rewrite过程看似很简洁,实际上还有其他的内在逻辑:

1)由于AOFRDB不同,AOF是更加接近实时数据,而RDB是快照数据,因为在AOF的rewrite过程中,如果有新的命令过来并且会更新内存空间,也就是3.2.3的流程中提到的,需要将这些命令也传递给AOF的rewrite子进程,而这些命令的传递是通过管道来实现的;其中,aofChildWriteDiffData函数用于将主进程中新增的aof命令缓冲aof_rewrite_buf_blocks发送给子进程;aofRewriteBufferAppend函数用于在接受新命令时根据要求将新命令内容写入到缓冲区aof_rewrite_buf_blocks中取;aofRewriteBufferWrite是在rewrite完成后,将aof_rewrite_buf_blocks中还没有传递给子进程的数据写入到新的aof文件中;


猜你喜欢

转载自blog.csdn.net/fusan2004/article/details/65632551