Redis数据持久化机制AOF原理分析一

 

Redis数据持久化机制AOF原理分析一

分类: Redis 2014-01-11 14:19  823人阅读  评论(0)  收藏  举报
AOF redis

目录(?)[+]

本文所引用的源码全部来自Redis2.8.2版本。

Redis AOF数据持久化机制的实现相关代码是redis.c, redis.h, aof.c, bio.c, rio.c, config.c

在阅读本文之前请先阅读Redis数据持久化机制AOF原理分析之配置详解文章,了解AOF相关参数的解析,文章链接

http://blog.csdn.net/acceptedxukai/article/details/18135219

转载请注明,文章出自http://blog.csdn.net/acceptedxukai/article/details/18136903

下面将介绍AOF数据持久化机制的实现


Server启动加载AOF文件数据


Server启动加载AOF文件数据的执行步骤为:main() -> initServerConfig() -> loadServerConfig() -> initServer() -> loadDataFromDisk()。initServerConfig()主要为初始化默认的AOF参数配置;loadServerConfig()加载配置文件redis.conf中AOF的参数配置,覆盖Server的默认AOF参数配置,如果配置appendonly on,那么AOF数据持久化功能将被激活,server.aof_state参数被设置为REDIS_AOF_ON;loadDataFromDisk()判断server.aof_state == REDIS_AOF_ON,结果为True就调用loadAppendOnlyFile函数加载AOF文件中的数据,加载的方法就是读取AOF文件中数据,由于AOF文件中存储的数据与客户端发送的请求格式相同完全符合Redis的通信协议,因此Server创建伪客户端fakeClient,将解析后的AOF文件数据像客户端请求一样调用各种指令,cmd->proc(fakeClient),将AOF文件中的数据重现到Redis Server数据库中。

[cpp]  view plain copy print ? 在CODE上查看代码片
  1. /* Function called at startup to load RDB or AOF file in memory. */  
  2. void loadDataFromDisk(void) {  
  3.     long long start = ustime();  
  4.     if (server.aof_state == REDIS_AOF_ON) {  
  5.         if (loadAppendOnlyFile(server.aof_filename) == REDIS_OK)  
  6.             redisLog(REDIS_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000);  
  7.     } else {  
  8.         if (rdbLoad(server.rdb_filename) == REDIS_OK) {  
  9.             redisLog(REDIS_NOTICE,"DB loaded from disk: %.3f seconds",  
  10.                 (float)(ustime()-start)/1000000);  
  11.         } else if (errno != ENOENT) {  
  12.             redisLog(REDIS_WARNING,"Fatal error loading the DB: %s. Exiting.",strerror(errno));  
  13.             exit(1);  
  14.         }  
  15.     }  
  16. }  
Server首先判断加载AOF文件是因为AOF文件中的数据要比RDB文件中的数据要新。

[cpp]  view plain copy print ? 在CODE上查看代码片
  1. int loadAppendOnlyFile(char *filename) {  
  2.     struct redisClient *fakeClient;  
  3.     FILE *fp = fopen(filename,"r");  
  4.     struct redis_stat sb;  
  5.     int old_aof_state = server.aof_state;  
  6.     long loops = 0;  
  7.   
  8.     //redis_fstat就是fstat64函数,通过fileno(fp)得到文件描述符,获取文件的状态存储于sb中,  
  9.     //具体可以参考stat函数,st_size就是文件的字节数  
  10.     if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) {  
  11.         server.aof_current_size = 0;  
  12.         fclose(fp);  
  13.         return REDIS_ERR;  
  14.     }  
  15.   
  16.     if (fp == NULL) {//打开文件失败  
  17.         redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));  
  18.         exit(1);  
  19.     }  
  20.   
  21.     /* Temporarily disable AOF, to prevent EXEC from feeding a MULTI 
  22.      * to the same file we're about to read. */  
  23.     server.aof_state = REDIS_AOF_OFF;  
  24.   
  25.     fakeClient = createFakeClient(); //建立伪终端  
  26.     startLoading(fp); // 定义于 rdb.c ,更新服务器的载入状态  
  27.   
  28.     while(1) {  
  29.         int argc, j;  
  30.         unsigned long len;  
  31.         robj **argv;  
  32.         char buf[128];  
  33.         sds argsds;  
  34.         struct redisCommand *cmd;  
  35.   
  36.         /* Serve the clients from time to time */  
  37.         // 有间隔地处理外部请求,ftello()函数得到文件的当前位置,返回值为long  
  38.         if (!(loops++ % 1000)) {  
  39.             loadingProgress(ftello(fp));//保存aof文件读取的位置,ftellno(fp)获取文件当前位置  
  40.             aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);//处理事件  
  41.         }  
  42.         //按行读取AOF数据  
  43.         if (fgets(buf,sizeof(buf),fp) == NULL) {  
  44.             if (feof(fp))//达到文件尾EOF  
  45.                 break;  
  46.             else  
  47.                 goto readerr;  
  48.         }  
  49.         //读取AOF文件中的命令,依照Redis的协议处理  
  50.         if (buf[0] != '*'goto fmterr;  
  51.         argc = atoi(buf+1);//参数个数  
  52.         if (argc < 1) goto fmterr;  
  53.   
  54.         argv = zmalloc(sizeof(robj*)*argc);//参数值  
  55.         for (j = 0; j < argc; j++) {  
  56.             if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;  
  57.             if (buf[0] != '$'goto fmterr;  
  58.             len = strtol(buf+1,NULL,10);//每个bulk的长度  
  59.             argsds = sdsnewlen(NULL,len);//新建一个空sds  
  60.             //按照bulk的长度读取  
  61.             if (len && fread(argsds,len,1,fp) == 0) goto fmterr;  
  62.             argv[j] = createObject(REDIS_STRING,argsds);  
  63.             if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF 跳过\r\n*/  
  64.         }  
  65.   
  66.         /* Command lookup */  
  67.         cmd = lookupCommand(argv[0]->ptr);  
  68.         if (!cmd) {  
  69.             redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", (char*)argv[0]->ptr);  
  70.             exit(1);  
  71.         }  
  72.         /* Run the command in the context of a fake client */  
  73.         fakeClient->argc = argc;  
  74.         fakeClient->argv = argv;  
  75.         cmd->proc(fakeClient);//执行命令  
  76.   
  77.         /* The fake client should not have a reply */  
  78.         redisAssert(fakeClient->bufpos == 0 && listLength(fakeClient->reply) == 0);  
  79.         /* The fake client should never get blocked */  
  80.         redisAssert((fakeClient->flags & REDIS_BLOCKED) == 0);  
  81.   
  82.         /* Clean up. Command code may have changed argv/argc so we use the 
  83.          * argv/argc of the client instead of the local variables. */  
  84.         for (j = 0; j < fakeClient->argc; j++)  
  85.             decrRefCount(fakeClient->argv[j]);  
  86.         zfree(fakeClient->argv);  
  87.     }  
  88.   
  89.     /* This point can only be reached when EOF is reached without errors. 
  90.      * If the client is in the middle of a MULTI/EXEC, log error and quit. */  
  91.     if (fakeClient->flags & REDIS_MULTI) goto readerr;  
  92.   
  93.     fclose(fp);  
  94.     freeFakeClient(fakeClient);  
  95.     server.aof_state = old_aof_state;  
  96.     stopLoading();  
  97.     aofUpdateCurrentSize(); //更新server.aof_current_size,AOF文件大小  
  98.     server.aof_rewrite_base_size = server.aof_current_size;  
  99.     return REDIS_OK;  
  100.     …………  
  101. }  
在前面一篇关于AOF参数配置的博客遗留了一个问题,server.aof_current_size参数的初始化,下面解决这个疑问。

[cpp]  view plain copy print ? 在CODE上查看代码片
  1. void aofUpdateCurrentSize(void) {  
  2.     struct redis_stat sb;  
  3.   
  4.     if (redis_fstat(server.aof_fd,&sb) == -1) {  
  5.         redisLog(REDIS_WARNING,"Unable to obtain the AOF file length. stat: %s",  
  6.             strerror(errno));  
  7.     } else {  
  8.         server.aof_current_size = sb.st_size;  
  9.     }  
  10. }  
redis_fstat是作者对Linux中fstat64函数的重命名,该还是就是获取文件相关的参数信息,具体可以Google之,sb.st_size就是当前AOF文件的大小。这里需要知道server.aof_fd即AOF文件描述符,该参数的初始化在initServer()函数中

[cpp]  view plain copy print ? 在CODE上查看代码片
  1. /* Open the AOF file if needed. */  
  2.     if (server.aof_state == REDIS_AOF_ON) {  
  3.         server.aof_fd = open(server.aof_filename,O_WRONLY|O_APPEND|O_CREAT,0644);  
  4.         if (server.aof_fd == -1) {  
  5.             redisLog(REDIS_WARNING, "Can't open the append-only file: %s",strerror(errno));  
  6.             exit(1);  
  7.         }  
  8.     }  


至此,Redis Server启动加载硬盘中AOF文件数据的操作就成功结束了。


Server数据库产生新数据如何持久化到硬盘


当客户端执行Set等修改数据库中字段的指令时就会造成Server数据库中数据被修改,这些修改的数据应该被实时更新到AOF文件中,并且也要按照一定的fsync机制刷新到硬盘中,保证数据不会丢失。

在上一篇博客中,提到了三种fsync方式:appendfsync always, appendfsync everysec, appendfsync no. 具体体现在server.aof_fsync参数中。

首先看当客户端请求的指令造成数据被修改,Redis是如何将修改数据的指令添加到server.aof_buf中的。

call() -> propagate() -> feedAppendOnlyFile(),call()函数判断执行指令后是否造成数据被修改。

feedAppendOnlyFile函数首先会判断Server是否开启了AOF,如果开启AOF,那么根据Redis通讯协议将修改数据的指令重现成请求的字符串,注意在超时设置的处理方式,接着将字符串append到server.aof_buf中即可。该函数最后两行代码需要注意,这才是重点,如果server.aof_child_pid != -1那么表明此时Server正在重写rewrite AOF文件,需要将被修改的数据追加到server.aof_rewrite_buf_blocks链表中,等待rewrite结束后,追加到AOF文件中。具体见下面代码的注释。

[cpp]  view plain copy print ? 在CODE上查看代码片
  1. /* Propagate the specified command (in the context of the specified database id) 
  2.  * to AOF and Slaves. 
  3.  * 
  4.  * flags are an xor between: 
  5.  * + REDIS_PROPAGATE_NONE (no propagation of command at all) 
  6.  * + REDIS_PROPAGATE_AOF (propagate into the AOF file if is enabled) 
  7.  * + REDIS_PROPAGATE_REPL (propagate into the replication link) 
  8.  */  
  9. void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc,  
  10.                int flags)  
  11. {  
  12.     //将cmd指令变动的数据追加到AOF文件中  
  13.     if (server.aof_state != REDIS_AOF_OFF && flags & REDIS_PROPAGATE_AOF)  
  14.         feedAppendOnlyFile(cmd,dbid,argv,argc);  
  15.     if (flags & REDIS_PROPAGATE_REPL)  
  16.         replicationFeedSlaves(server.slaves,dbid,argv,argc);  
  17. }  
[cpp]  view plain copy print ? 在CODE上查看代码片
  1. //cmd指令修改了数据,先将更新的数据写到server.aof_buf中  
  2. void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {  
  3.     sds buf = sdsempty();  
  4.     robj *tmpargv[3];  
  5.   
  6.     /* The DB this command was targeting is not the same as the last command 
  7.      * we appendend. To issue a SELECT command is needed. */  
  8.     // 当前 db 不是指定的 aof db,通过创建 SELECT 命令来切换数据库  
  9.     if (dictid != server.aof_selected_db) {  
  10.         char seldb[64];  
  11.   
  12.         snprintf(seldb,sizeof(seldb),"%d",dictid);  
  13.         buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",  
  14.             (unsigned long)strlen(seldb),seldb);  
  15.         server.aof_selected_db = dictid;  
  16.     }  
  17.   
  18.     // 将 EXPIRE / PEXPIRE / EXPIREAT 命令翻译为 PEXPIREAT 命令  
  19.     if (cmd->proc == expireCommand || cmd->proc == pexpireCommand ||  
  20.         cmd->proc == expireatCommand) {  
  21.         /* Translate EXPIRE/PEXPIRE/EXPIREAT into PEXPIREAT */  
  22.         buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);  
  23.     }// 将 SETEX / PSETEX 命令翻译为 SET 和 PEXPIREAT 组合命令  
  24.     else if (cmd->proc == setexCommand || cmd->proc == psetexCommand) {  
  25.         /* Translate SETEX/PSETEX to SET and PEXPIREAT */  
  26.         tmpargv[0] = createStringObject("SET",3);  
  27.         tmpargv[1] = argv[1];  
  28.         tmpargv[2] = argv[3];  
  29.         buf = catAppendOnlyGenericCommand(buf,3,tmpargv);  
  30.         decrRefCount(tmpargv[0]);  
  31.         buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);  
  32.     } else {//其他的指令直接追加  
  33.         /* All the other commands don't need translation or need the 
  34.          * same translation already operated in the command vector 
  35.          * for the replication itself. */  
  36.         buf = catAppendOnlyGenericCommand(buf,argc,argv);  
  37.     }  
  38.   
  39.     /* Append to the AOF buffer. This will be flushed on disk just before 
  40.      * of re-entering the event loop, so before the client will get a 
  41.      * positive reply about the operation performed. */  
  42.     // 将 buf 追加到服务器的 aof_buf 末尾,在beforeSleep中写到AOF文件中,并且根据情况fsync刷新到硬盘  
  43.     if (server.aof_state == REDIS_AOF_ON)  
  44.         server.aof_buf = sdscatlen(server.aof_buf,buf,sdslen(buf));  
  45.   
  46.     /* If a background append only file rewriting is in progress we want to 
  47.      * accumulate the differences between the child DB and the current one 
  48.      * in a buffer, so that when the child process will do its work we 
  49.      * can append the differences to the new append only file. */  
  50.     //如果server.aof_child_pid不为1,那就说明有快照进程正在写数据到临时文件(已经开始rewrite),  
  51.     //那么必须先将这段时间接收到的指令更新的数据先暂时存储起来,等到快照进程完成任务后,  
  52.     //将这部分数据写入到AOF文件末尾,保证数据不丢失  
  53.     //解释为什么需要aof_rewrite_buf_blocks,当server在进行rewrite时即读取所有数据库中的数据,  
  54.     //有些数据已经写到新的AOF文件,但是此时客户端执行指令又将该值修改了,因此造成了差异  
  55.     if (server.aof_child_pid != -1)  
  56.         aofRewriteBufferAppend((unsigned char*)buf,sdslen(buf));  
  57.     /*这里说一下server.aof_buf和server.aof_rewrite_buf_blocks的区别 
  58.       aof_buf是正常情况下aof文件打开的时候,会不断将这份数据写入到AOF文件中。 
  59.       aof_rewrite_buf_blocks 是如果用户主动触发了写AOF文件的命令时,比如 config set appendonly yes命令 
  60.       那么redis会fork创建一个后台进程,也就是当时的数据快照,然后将数据写入到一个临时文件中去。 
  61.       在此期间发送的命令,我们需要把它们记录起来,等后台进程完成AOF临时文件写后,serverCron定时任务 
  62.       感知到这个退出动作,然后就会调用backgroundRewriteDoneHandler进而调用aofRewriteBufferWrite函数, 
  63.       将aof_rewrite_buf_blocks上面的数据,也就是diff数据写入到临时AOF文件中,然后再unlink替换正常的AOF文件。 
  64.       因此可以知道,aof_buf一般情况下比aof_rewrite_buf_blocks要少, 
  65.       但开始的时候可能aof_buf包含一些后者不包含的前面部分数据。*/  
  66.   
  67.     sdsfree(buf);  
  68. }  


Server在每次事件循环之前会调用一次beforeSleep函数,下面看看这个函数做了什么工作?

[cpp]  view plain copy print ? 在CODE上查看代码片
  1. /* This function gets called every time Redis is entering the 
  2.  * main loop of the event driven library, that is, before to sleep 
  3.  * for ready file descriptors. */  
  4. void beforeSleep(struct aeEventLoop *eventLoop) {  
  5.     REDIS_NOTUSED(eventLoop);  
  6.     listNode *ln;  
  7.     redisClient *c;  
  8.   
  9.     /* Run a fast expire cycle (the called function will return 
  10.      * ASAP if a fast cycle is not needed). */  
  11.     if (server.active_expire_enabled && server.masterhost == NULL)  
  12.         activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);  
  13.   
  14.     /* Try to process pending commands for clients that were just unblocked. */  
  15.     while (listLength(server.unblocked_clients)) {  
  16.         ln = listFirst(server.unblocked_clients);  
  17.         redisAssert(ln != NULL);  
  18.         c = ln->value;  
  19.         listDelNode(server.unblocked_clients,ln);  
  20.         c->flags &= ~REDIS_UNBLOCKED;  
  21.   
  22.         /* Process remaining data in the input buffer. */  
  23.         //处理客户端在阻塞期间接收到的客户端发送的请求  
  24.         if (c->querybuf && sdslen(c->querybuf) > 0) {  
  25.             server.current_client = c;  
  26.             processInputBuffer(c);  
  27.             server.current_client = NULL;  
  28.         }  
  29.     }  
  30.   
  31.     /* Write the AOF buffer on disk */  
  32.     //将server.aof_buf中的数据追加到AOF文件中并fsync到硬盘上  
  33.     flushAppendOnlyFile(0);  
  34. }  
通过上面的代码及注释可以发现,beforeSleep函数做了三件事:1、处理过期键,2、处理阻塞期间的客户端请求,3、将server.aof_buf中的数据追加到AOF文件中并fsync刷新到硬盘上,flushAppendOnlyFile函数给定了一个参数force,表示是否强制写入AOF文件,0表示非强制即支持延迟写,1表示强制写入。

[cpp]  view plain copy print ? 在CODE上查看代码片
  1. void flushAppendOnlyFile(int force) {  
  2.     ssize_t nwritten;  
  3.     int sync_in_progress = 0;  
  4.     if (sdslen(server.aof_buf) == 0) return;  
  5.     // 返回后台正在等待执行的 fsync 数量  
  6.     if (server.aof_fsync == AOF_FSYNC_EVERYSEC)  
  7.         sync_in_progress = bioPendingJobsOfType(REDIS_BIO_AOF_FSYNC) != 0;  
  8.   
  9.     // AOF 模式为每秒 fsync ,并且 force 不为 1 如果可以的话,推延冲洗  
  10.     if (server.aof_fsync == AOF_FSYNC_EVERYSEC && !force) {  
  11.         /* With this append fsync policy we do background fsyncing. 
  12.          * If the fsync is still in progress we can try to delay 
  13.          * the write for a couple of seconds. */  
  14.         // 如果 aof_fsync 队列里已经有正在等待的任务  
  15.         if (sync_in_progress) {  
  16.             // 上一次没有推迟冲洗过,记录推延的当前时间,然后返回  
  17.             if (server.aof_flush_postponed_start == 0) {  
  18.                 /* No previous write postponinig, remember that we are 
  19.                  * postponing the flush and return. */  
  20.                 server.aof_flush_postponed_start = server.unixtime;  
  21.                 return;  
  22.             } else if (server.unixtime - server.aof_flush_postponed_start < 2) {  
  23.                 // 允许在两秒之内的推延冲洗  
  24.                 /* We were already waiting for fsync to finish, but for less 
  25.                  * than two seconds this is still ok. Postpone again. */  
  26.                 return;  
  27.             }  
  28.             /* Otherwise fall trough, and go write since we can't wait 
  29.              * over two seconds. */  
  30.             server.aof_delayed_fsync++;  
  31.             redisLog(REDIS_NOTICE,"Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.");  
  32.         }  
  33.     }  
  34.     /* If you are following this code path, then we are going to write so 
  35.      * set reset the postponed flush sentinel to zero. */  
  36.     server.aof_flush_postponed_start = 0;  
  37.   
  38.     /* We want to perform a single write. This should be guaranteed atomic 
  39.      * at least if the filesystem we are writing is a real physical one. 
  40.      * While this will save us against the server being killed I don't think 
  41.      * there is much to do about the whole server stopping for power problems 
  42.      * or alike */  
  43.     // 将 AOF 缓存写入到文件,如果一切幸运的话,写入会原子性地完成  
  44.     nwritten = write(server.aof_fd,server.aof_buf,sdslen(server.aof_buf));  
  45.     if (nwritten != (signed)sdslen(server.aof_buf)) {//出错  
  46.         /* Ooops, we are in troubles. The best thing to do for now is 
  47.          * aborting instead of giving the illusion that everything is 
  48.          * working as expected. */  
  49.         if (nwritten == -1) {  
  50.             redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));  
  51.         } else {  
  52.             redisLog(REDIS_WARNING,"Exiting on short write while writing to "  
  53.                                    "the append-only file: %s (nwritten=%ld, "  
  54.                                    "expected=%ld)",  
  55.                                    strerror(errno),  
  56.                                    (long)nwritten,  
  57.                                    (long)sdslen(server.aof_buf));  
  58.   
  59.             if (ftruncate(server.aof_fd, server.aof_current_size) == -1) {  
  60.                 redisLog(REDIS_WARNING, "Could not remove short write "  
  61.                          "from the append-only file.  Redis may refuse "  
  62.                          "to load the AOF the next time it starts.  "  
  63.                          "ftruncate: %s", strerror(errno));  
  64.             }  
  65.         }  
  66.         exit(1);  
  67.     }  
  68.     server.aof_current_size += nwritten;  
  69.   
  70.     /* Re-use AOF buffer when it is small enough. The maximum comes from the 
  71.      * arena size of 4k minus some overhead (but is otherwise arbitrary). */  
  72.     // 如果 aof 缓存不是太大,那么重用它,否则,清空 aof 缓存  
  73.     if ((sdslen(server.aof_buf)+sdsavail(server.aof_buf)) < 4000) {  
  74.         sdsclear(server.aof_buf);  
  75.     } else {  
  76.         sdsfree(server.aof_buf);  
  77.         server.aof_buf = sdsempty();  
  78.     }  
  79.   
  80.     /* Don't fsync if no-appendfsync-on-rewrite is set to yes and there are 
  81.      * children doing I/O in the background. */  
  82.     //aof rdb子进程运行中不支持fsync并且aof rdb子进程正在运行,那么直接返回,  
  83.     //但是数据已经写到aof文件中,只是没有刷新到硬盘  
  84.     if (server.aof_no_fsync_on_rewrite &&  
  85.         (server.aof_child_pid != -1 || server.rdb_child_pid != -1))  
  86.             return;  
  87.   
  88.     /* Perform the fsync if needed. */  
  89.     if (server.aof_fsync == AOF_FSYNC_ALWAYS) {//总是fsync,那么直接进行fsync  
  90.         /* aof_fsync is defined as fdatasync() for Linux in order to avoid 
  91.          * flushing metadata. */  
  92.         aof_fsync(server.aof_fd); /* Let's try to get this data on the disk */  
  93.         server.aof_last_fsync = server.unixtime;  
  94.     } else if ((server.aof_fsync == AOF_FSYNC_EVERYSEC &&  
  95.                 server.unixtime > server.aof_last_fsync)) {  
  96.         if (!sync_in_progress) aof_background_fsync(server.aof_fd);//放到后台线程进行fsync  
  97.         server.aof_last_fsync = server.unixtime;  
  98.     }  
  99. }  
上述代码中请关注server.aof_fsync参数,即设置Redis fsync AOF文件到硬盘的策略,如果设置为AOF_FSYNC_ALWAYS,那么直接在主进程中fsync,如果设置为AOF_FSYNC_EVERYSEC,那么放入后台线程中fsync,后台线程的代码在bio.c中。


小结

文章写到这,已经解决的了Redis Server启动加载AOF文件和如何将客户端请求产生的新的数据追加到AOF文件中,对于追加数据到AOF文件中,根据fsync的配置策略如何将写入到AOF文件中的新数据刷新到硬盘中,直接在主进程中fsync或是在后台线程fsync。

至此,AOF数据持久化还剩下如何rewrite AOF,接受客户端发送的BGREWRITEAOF请求,此部分内容待下篇博客中解析。

感谢此篇博客给我在理解Redis AOF数据持久化方面的巨大帮助,http://chenzhenianqing.cn/articles/786.html

本人Redis-2.8.2的源码注释已经放到Github中,有需要的读者可以下载,我也会在后续的时间中更新,https://github.com/xkeyideal/annotated-redis-2.8.2

本人不怎么会使用Git,望有人能教我一下。

你可能感兴趣的:(Redis数据持久化机制AOF原理分析一)