加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

发布时间:2020-12-16 04:45:09 所属栏目:安全 来源:网络整理
导读:本文所引用的源码全部来自Redis2.8.2版本。 Redis AOF数据持久化机制的实现相关代码是redis.c,redis.h,aof.c,bio.c,rio.c,config.c 在阅读本文之前请先阅读Redis数据持久化机制AOF原理分析之配置详解文章,了解AOF相关参数的解析,文章链接 转载请注明,文章

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

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

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

转载请注明,文章出自

下面将介绍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数据库中。

<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;copy<a class="PrintSource" title="print" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;print<a class="About" title="?" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;?<a title="在CODE上查看代码片" href="https://code.csdn.net/snippets/152074" target="_blank">

<img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" width="12" height="12">

<a title="派生到我的代码片" href="https://code.csdn.net/snippets/152074/fork" target="_blank">

<img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" width="12" height="12">

?
    ??
  1. ?loadDataFromDisk()?{??
  2. ??????start?=?ustime();??
  3. ?????(server.aof_state?==?REDIS_AOF_ON)?{??
  4. ?????????(loadAppendOnlyFile(server.aof_filename)?==?REDIS_OK)??
  5. ????????????redisLog(REDIS_NOTICE,,()(ustime()-start)/1000000);??
  6. ????}??{??
  7. ?????????(rdbLoad(server.rdb_filename)?==?REDIS_OK)?{??
  8. ????????????redisLog(REDIS_NOTICE,,??
  9. ????????????????()(ustime()-start)/1000000);??
  10. ????????}???(errno?!=?ENOENT)?{??
  11. ????????????redisLog(REDIS_WARNING,,strerror(errno));??
  12. ????????????exit(1);??
  13. ????????}??
  14. ????}??
  15. }??

Server首先判断加载AOF文件是因为AOF文件中的数据要比RDB文件中的数据要新。

<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;copy<a class="PrintSource" title="print" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;print<a class="About" title="?" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;?<a title="在CODE上查看代码片" href="https://code.csdn.net/snippets/152074" target="_blank">

<img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" width="12" height="12">

<a title="派生到我的代码片" href="https://code.csdn.net/snippets/152074/fork" target="_blank">

<img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" width="12" height="12">

?
    ?loadAppendOnlyFile(?*filename)?{??
  1. ?????redisClient?*fakeClient;??
  2. ?????*fp?=?fopen(filename,);??
  3. ?????redis_stat?sb;??
  4. ?????old_aof_state?=?server.aof_state;??
  5. ?????loops?=?0;??
  6. ??
  7. ??????
  8. ??????
  9. ?????(fp?&&?redis_fstat(fileno(fp),&sb)?!=?-1?&&?sb.st_size?==?0)?{??
  10. ????????server.aof_current_size?=?0;??
  11. ????????fclose(fp);??
  12. ?????????REDIS_ERR;??
  13. ????}??
  14. ??
  15. ?????(fp?==?NULL)?{??
  16. ????????redisLog(REDIS_WARNING,,strerror(errno));??
  17. ????????exit(1);??
  18. ????}??
  19. ??
  20. ?????
  21. ??
  22. ????server.aof_state?=?REDIS_AOF_OFF;??
  23. ??
  24. ????fakeClient?=?createFakeClient();???
  25. ????startLoading(fp);???
  26. ??
  27. ????(1)?{??
  28. ?????????argc,?j;??
  29. ????????unsigned??len;??
  30. ????????robj?**argv;??
  31. ?????????buf[128];??
  32. ????????sds?argsds;??
  33. ?????????redisCommand?*cmd;??
  34. ??
  35. ??????????
  36. ??????????
  37. ?????????(!(loops++?%?1000))?{??
  38. ????????????loadingProgress(ftello(fp));??
  39. ????????????aeProcessEvents(server.el,?AE_FILE_EVENTS|AE_DONT_WAIT);??
  40. ????????}??
  41. ??????????
  42. ?????????(fgets(buf,(buf),fp)?==?NULL)?{??
  43. ?????????????(feof(fp))??
  44. ????????????????;??
  45. ??????????????
  46. ?????????????????readerr;??
  47. ????????}??
  48. ??????????
  49. ?????????(buf[0]?!=?)??fmterr;??
  50. ????????argc?=?atoi(buf+1);??
  51. ?????????(argc??fmterr;??
  52. ??
  53. ????????argv?=?zmalloc((robj*)*argc);??
  54. ?????????(j?=?0;?j?
  55. ?????????????(fgets(buf,fp)?==?NULL)??readerr;??
  56. ?????????????(buf[0]?!=?)??fmterr;??
  57. ????????????len?=?strtol(buf+1,NULL,10);??
  58. ????????????argsds?=?sdsnewlen(NULL,len);??
  59. ??????????????
  60. ?????????????(len?&&?fread(argsds,len,1,fp)?==?0)??fmterr;??
  61. ????????????argv[j]?=?createObject(REDIS_STRING,argsds);??
  62. ?????????????(fread(buf,2,fp)?==?0)??fmterr;???
  63. ????????}??
  64. ??
  65. ??????????
  66. ????????cmd?=?lookupCommand(argv[0]->ptr);??
  67. ?????????(!cmd)?{??
  68. ????????????redisLog(REDIS_WARNING,,?(*)argv[0]->ptr);??
  69. ????????????exit(1);??
  70. ????????}??
  71. ??????????
  72. ????????fakeClient->argc?=?argc;??
  73. ????????fakeClient->argv?=?argv;??
  74. ????????cmd->proc(fakeClient);??
  75. ??
  76. ??????????
  77. ????????redisAssert(fakeClient->bufpos?==?0?&&?listLength(fakeClient->reply)?==?0);??
  78. ??????????
  79. ????????redisAssert((fakeClient->flags?&?REDIS_BLOCKED)?==?0);??
  80. ??
  81. ?????????
  82. ??
  83. ?????????(j?=?0;?j?argc;?j++)??
  84. ????????????decrRefCount(fakeClient->argv[j]);??
  85. ????????zfree(fakeClient->argv);??
  86. ????}??
  87. ??
  88. ?????
  89. ??
  90. ?????(fakeClient->flags?&?REDIS_MULTI)??readerr;??
  91. ??
  92. ????fclose(fp);??
  93. ????freeFakeClient(fakeClient);??
  94. ????server.aof_state?=?old_aof_state;??
  95. ????stopLoading();??
  96. ????aofUpdateCurrentSize();???
  97. ????server.aof_rewrite_base_size?=?server.aof_current_size;??
  98. ?????REDIS_OK;??
  99. ????…………??
  100. }??

在前面一篇关于AOF参数配置的博客遗留了一个问题,server.aof_current_size参数的初始化,下面解决这个疑问。

<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;copy<a class="PrintSource" title="print" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;print<a class="About" title="?" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;?<a title="在CODE上查看代码片" href="https://code.csdn.net/snippets/152074" target="_blank">

<img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" width="12" height="12">

<a title="派生到我的代码片" href="https://code.csdn.net/snippets/152074/fork" target="_blank">

<img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" width="12" height="12">

?
    ?aofUpdateCurrentSize()?{??
  1. ?????redis_stat?sb;??
  2. ??
  3. ?????(redis_fstat(server.aof_fd,&sb)?==?-1)?{??
  4. ????????redisLog(REDIS_WARNING,,??
  5. ????????????strerror(errno));??
  6. ????}??{??
  7. ????????server.aof_current_size?=?sb.st_size;??
  8. ????}??
  9. }??

redis_fstat是作者对Linux中fstat64函数的重命名,该还是就是获取文件相关的参数信息,具体可以Google之,sb.st_size就是当前AOF文件的大小。这里需要知道server.aof_fd即AOF文件描述符,该参数的初始化在initServer()函数中

<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;copy<a class="PrintSource" title="print" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;print<a class="About" title="?" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;?<a title="在CODE上查看代码片" href="https://code.csdn.net/snippets/152074" target="_blank">

<img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" width="12" height="12">

<a title="派生到我的代码片" href="https://code.csdn.net/snippets/152074/fork" target="_blank">

<img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" width="12" height="12">

?
    ??
  1. ?????(server.aof_state?==?REDIS_AOF_ON)?{??
  2. ????????server.aof_fd?=?open(server.aof_filename,O_WRONLY|O_APPEND|O_CREAT,0644);??
  3. ?????????(server.aof_fd?==?-1)?{??
  4. ????????????redisLog(REDIS_WARNING,?,strerror(errno));??
  5. ????????????exit(1);??
  6. ????????}??
  7. ????}??

?

至此,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文件中。具体见下面代码的注释。

<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;copy<a class="PrintSource" title="print" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;print<a class="About" title="?" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;?<a title="在CODE上查看代码片" href="https://code.csdn.net/snippets/152074" target="_blank">

<img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" width="12" height="12">

<a title="派生到我的代码片" href="https://code.csdn.net/snippets/152074/fork" target="_blank">

<img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" width="12" height="12">

?
    ?
  1. ?
  2. ?
  3. ?
  4. ?
  5. ?
  6. ?
  7. ??
  8. ?propagate(?redisCommand?*cmd,??dbid,?robj?**argv,??argc,??
  9. ????????????????flags)??
  10. {??
  11. ??????
  12. ?????(server.aof_state?!=?REDIS_AOF_OFF?&&?flags?&?REDIS_PROPAGATE_AOF)??
  13. ????????feedAppendOnlyFile(cmd,dbid,argv,argc);??
  14. ?????(flags?&?REDIS_PROPAGATE_REPL)??
  15. ????????replicationFeedSlaves(server.slaves,argc);??
  16. }??
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ??
  1. ?feedAppendOnlyFile(?redisCommand?*cmd,??dictid,??argc)?{??
  2. ????sds?buf?=?sdsempty();??
  3. ????robj?*tmpargv[3];??
  4. ??
  5. ?????
  6. ??
  7. ??????
  8. ?????(dictid?!=?server.aof_selected_db)?{??
  9. ?????????seldb[64];??
  10. ??
  11. ????????snprintf(seldb,(seldb),,dictid);??
  12. ????????buf?=?sdscatprintf(buf,,??
  13. ????????????(unsigned?)strlen(seldb),seldb);??
  14. ????????server.aof_selected_db?=?dictid;??
  15. ????}??
  16. ??
  17. ??????
  18. ?????(cmd->proc?==?expireCommand?||?cmd->proc?==?pexpireCommand?||??
  19. ????????cmd->proc?==?expireatCommand)?{??
  20. ??????????
  21. ????????buf?=?catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);??
  22. ????}??
  23. ??????(cmd->proc?==?setexCommand?||?cmd->proc?==?psetexCommand)?{??
  24. ??????????
  25. ????????tmpargv[0]?=?createStringObject(,3);??
  26. ????????tmpargv[1]?=?argv[1];??
  27. ????????tmpargv[2]?=?argv[3];??
  28. ????????buf?=?catAppendOnlyGenericCommand(buf,3,tmpargv);??
  29. ????????decrRefCount(tmpargv[0]);??
  30. ????????buf?=?catAppendOnlyExpireAtCommand(buf,argv[2]);??
  31. ????}??{??
  32. ?????????
  33. ?
  34. ??
  35. ????????buf?=?catAppendOnlyGenericCommand(buf,argc,argv);??
  36. ????}??
  37. ??
  38. ?????
  39. ?
  40. ??
  41. ??????
  42. ?????(server.aof_state?==?REDIS_AOF_ON)??
  43. ????????server.aof_buf?=?sdscatlen(server.aof_buf,buf,sdslen(buf));??
  44. ??
  45. ?????
  46. ?
  47. ?
  48. ??
  49. ??????
  50. ??????
  51. ??????
  52. ??????
  53. ??????
  54. ?????(server.aof_child_pid?!=?-1)??
  55. ????????aofRewriteBufferAppend((unsigned?*)buf,sdslen(buf));??
  56. ?????
  57. ?
  58. ?
  59. ?
  60. ?
  61. ?
  62. ?
  63. ?
  64. ??
  65. ??
  66. ????sdsfree(buf);??
  67. }??

?

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

<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;copy<a class="PrintSource" title="print" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;print<a class="About" title="?" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;?<a title="在CODE上查看代码片" href="https://code.csdn.net/snippets/152074" target="_blank">

<img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" width="12" height="12">

<a title="派生到我的代码片" href="https://code.csdn.net/snippets/152074/fork" target="_blank">

<img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" width="12" height="12">

?
    ?
  1. ?
  2. ??
  3. ?beforeSleep(?aeEventLoop?*eventLoop)?{??
  4. ????REDIS_NOTUSED(eventLoop);??
  5. ????listNode?*ln;??
  6. ????redisClient?*c;??
  7. ??
  8. ?????
  9. ??
  10. ?????(server.active_expire_enabled?&&?server.masterhost?==?NULL)??
  11. ????????activeExpireCycle(ACTIVE_EXPIRE_CYCLE_FAST);??
  12. ??
  13. ??????
  14. ?????(listLength(server.unblocked_clients))?{??
  15. ????????ln?=?listFirst(server.unblocked_clients);??
  16. ????????redisAssert(ln?!=?NULL);??
  17. ????????c?=?ln->value;??
  18. ????????listDelNode(server.unblocked_clients,ln);??
  19. ????????c->flags?&=?~REDIS_UNBLOCKED;??
  20. ??
  21. ??????????
  22. ??????????
  23. ?????????(c->querybuf?&&?sdslen(c->querybuf)?>?0)?{??
  24. ????????????server.current_client?=?c;??
  25. ????????????processInputBuffer(c);??
  26. ????????????server.current_client?=?NULL;??
  27. ????????}??
  28. ????}??
  29. ??
  30. ??????
  31. ??????
  32. ????flushAppendOnlyFile(0);??
  33. }??

通过上面的代码及注释可以发现,beforeSleep函数做了三件事:1、处理过期键,2、处理阻塞期间的客户端请求,3、将server.aof_buf中的数据追加到AOF文件中并fsync刷新到硬盘上,flushAppendOnlyFile函数给定了一个参数force,表示是否强制写入AOF文件,0表示非强制即支持延迟写,1表示强制写入。

<div class="dp-highlighter bg_cpp">
<div class="bar">
<div class="tools">
[cpp]?<a class="ViewSource" title="view plain" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;view plain<a class="CopyToClipboard" title="copy" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;copy<a class="PrintSource" title="print" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;print<a class="About" title="?" href="http://blog.csdn.net/acceptedxukai/article/details/18136903"&gt;?<a title="在CODE上查看代码片" href="https://code.csdn.net/snippets/152074" target="_blank">

<img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" width="12" height="12">

<a title="派生到我的代码片" href="https://code.csdn.net/snippets/152074/fork" target="_blank">

<img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" width="12" height="12">

?
    ?flushAppendOnlyFile(?force)?{??
  1. ????ssize_t?nwritten;??
  2. ?????sync_in_progress?=?0;??
  3. ?????(sdslen(server.aof_buf)?==?0)?;??
  4. ??????
  5. ?????(server.aof_fsync?==?AOF_FSYNC_EVERYSEC)??
  6. ????????sync_in_progress?=?bioPendingJobsOfType(REDIS_BIO_AOF_FSYNC)?!=?0;??
  7. ??
  8. ??????
  9. ?????(server.aof_fsync?==?AOF_FSYNC_EVERYSEC?&&?!force)?{??
  10. ?????????
  11. ?
  12. ??
  13. ??????????
  14. ?????????(sync_in_progress)?{??
  15. ??????????????
  16. ?????????????(server.aof_flush_postponed_start?==?0)?{??
  17. ?????????????????
  18. ??
  19. ????????????????server.aof_flush_postponed_start?=?server.unixtime;??
  20. ????????????????;??
  21. ????????????}???(server.unixtime?-?server.aof_flush_postponed_start?
  22. ??????????????????
  23. ?????????????????
  24. ??
  25. ????????????????;??
  26. ????????????}??
  27. ?????????????
  28. ??
  29. ????????????server.aof_delayed_fsync++;??
  30. ????????????redisLog(REDIS_NOTICE,);??
  31. ????????}??
  32. ????}??
  33. ?????
  34. ??
  35. ????server.aof_flush_postponed_start?=?0;??
  36. ??
  37. ?????
  38. ?
  39. ?
  40. ?
  41. ??
  42. ??????
  43. ????nwritten?=?write(server.aof_fd,server.aof_buf,sdslen(server.aof_buf));??
  44. ?????(nwritten?!=?()sdslen(server.aof_buf))?{??
  45. ?????????
  46. ?
  47. ??
  48. ?????????(nwritten?==?-1)?{??
  49. ????????????redisLog(REDIS_WARNING,,strerror(errno));??
  50. ????????}??{??
  51. ????????????redisLog(REDIS_WARNING,??
  52. ?????????????????????????????????????
  53. ???????????????????????????????????,??
  54. ???????????????????????????????????strerror(errno),??
  55. ???????????????????????????????????()nwritten,??
  56. ???????????????????????????????????()sdslen(server.aof_buf));??
  57. ??
  58. ?????????????(ftruncate(server.aof_fd,?server.aof_current_size)?==?-1)?{??
  59. ????????????????redisLog(REDIS_WARNING,???
  60. ???????????????????????????
  61. ???????????????????????????
  62. ?????????????????????????,?strerror(errno));??
  63. ????????????}??
  64. ????????}??
  65. ????????exit(1);??
  66. ????}??
  67. ????server.aof_current_size?+=?nwritten;??
  68. ??
  69. ?????
  70. ??
  71. ??????
  72. ?????((sdslen(server.aof_buf)+sdsavail(server.aof_buf))?
  73. ????????sdsclear(server.aof_buf);??
  74. ????}??{??
  75. ????????sdsfree(server.aof_buf);??
  76. ????????server.aof_buf?=?sdsempty();??
  77. ????}??
  78. ??
  79. ?????
  80. ??
  81. ??????
  82. ??????
  83. ?????(server.aof_no_fsync_on_rewrite?&&??
  84. ????????(server.aof_child_pid?!=?-1?||?server.rdb_child_pid?!=?-1))??
  85. ????????????;??
  86. ??
  87. ??????
  88. ?????(server.aof_fsync?==?AOF_FSYNC_ALWAYS)?{??
  89. ?????????
  90. ??
  91. ????????aof_fsync(server.aof_fd);???
  92. ????????server.aof_last_fsync?=?server.unixtime;??
  93. ????}???((server.aof_fsync?==?AOF_FSYNC_EVERYSEC?&&??
  94. ????????????????server.unixtime?>?server.aof_last_fsync))?{??
  95. ?????????(!sync_in_progress)?aof_background_fsync(server.aof_fd);??
  96. ????????server.aof_last_fsync?=?server.unixtime;??
  97. ????}??
  98. }??

上述代码中请关注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数据持久化方面的巨大帮助,

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

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

--------------------------------------------------------------------------------------------------------------------------------------------------------------

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

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

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

接着上一篇文章,本文将介绍Redis是如何实现AOF rewrite的。

转载请注明,文章出自

?

AOF rewrite的触发机制

?

如果Redis只是将客户端修改数据库的指令重现存储在AOF文件中,那么AOF文件的大小会不断的增加,因为AOF文件只是简单的重现存储了客户端的指令,而并没有进行合并。对于该问题最简单的处理方式,即当AOF文件满足一定条件时就对AOF进行rewrite,rewrite是根据当前内存数据库中的数据进行遍历写到一个临时的AOF文件,待写完后替换掉原来的AOF文件即可。

?

Redis触发AOF rewrite机制有三种:

1、Redis Server接收到客户端发送的BGREWRITEAOF指令请求,如果当前AOF/RDB数据持久化没有在执行,那么执行,反之,等当前AOF/RDB数据持久化结束后执行AOF rewrite

2、在Redis配置文件redis.conf中,用户设置了auto-aof-rewrite-percentage和auto-aof-rewrite-min-size参数,并且当前AOF文件大小server.aof_current_size大于auto-aof-rewrite-min-size(server.aof_rewrite_min_size),同时AOF文件大小的增长率大于auto-aof-rewrite-percentage(server.aof_rewrite_perc)时,会自动触发AOF rewrite

3、用户设置“config set appendonly yes”开启AOF的时,调用startAppendOnly函数会触发rewrite

下面分别介绍上述三种机制的处理.

?

接收到BGREWRITEAOF指令

?
[cpp]?在CODE上查看代码片派生到我的代码片
?
    >?bgrewriteaofCommand(redisClient?*c)?{??
  1. ??????
  2. ?????(server.aof_child_pid?!=?-1)?{??
  3. ????????addReplyError(c,);??
  4. ????}???(server.rdb_child_pid?!=?-1)?{??
  5. ??????????
  6. ??????????
  7. ????????server.aof_rewrite_scheduled?=?1;??
  8. ????????addReplyStatus(c,);??
  9. ????}???(rewriteAppendOnlyFileBackground()?==?REDIS_OK)?{??
  10. ??????????
  11. ????????addReplyStatus(c,);??
  12. ????}??{??
  13. ????????addReply(c,shared.err);??
  14. ????}??
  15. }??
当AOF rewrite请求被挂起时,在serverCron函数中,会处理。
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ?
  1. ??
  2. ??????
  3. ??????
  4. ??????
  5. ?????(server.rdb_child_pid?==?-1?&&?server.aof_child_pid?==?-1?&&??
  6. ????????server.aof_rewrite_scheduled)??
  7. ????{??
  8. ????????rewriteAppendOnlyFileBackground();??
  9. ????}??

Server自动对AOF进行rewrite

在serverCron函数中会周期性判断
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ??
  1. ???????????
  2. ??????????(server.rdb_child_pid?==?-1?&&??
  3. ?????????????server.aof_child_pid?==?-1?&&??
  4. ?????????????server.aof_rewrite_perc?&&??
  5. ?????????????server.aof_current_size?>?server.aof_rewrite_min_size)??
  6. ?????????{??
  7. ??????????????base?=?server.aof_rewrite_base_size????
  8. ????????????????????????????server.aof_rewrite_base_size?:?1;??
  9. ??????????????growth?=?(server.aof_current_size*100/base)?-?100;??
  10. ?????????????(growth?>=?server.aof_rewrite_perc)?{??
  11. ????????????????redisLog(REDIS_NOTICE,,growth);??
  12. ????????????????rewriteAppendOnlyFileBackground();??
  13. ????????????}??
  14. ?????????}??

config set appendonly yes

当客户端发送该指令时,config.c中的configSetCommand函数会做出响应,startAppendOnly函数会执行AOF rewrite
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ?(!strcasecmp(c->argv[2]->ptr,))?{??
  1. ?????enable?=?yesnotoi(o->ptr);??
  2. ??
  3. ?????(enable?==?-1)??badfmt;??
  4. ?????(enable?==?0?&&?server.aof_state?!=?REDIS_AOF_OFF)?{??
  5. ????????stopAppendOnly();??
  6. ????}???(enable?&&?server.aof_state?==?REDIS_AOF_OFF)?{??
  7. ?????????(startAppendOnly()?==?REDIS_ERR)?{??
  8. ????????????addReplyError(c,??
  9. ????????????????);??
  10. ????????????;??
  11. ????????}??
  12. ????}??
  13. }??
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ?startAppendOnly()?{??
  1. ????server.aof_last_fsync?=?server.unixtime;??
  2. ????server.aof_fd?=?open(server.aof_filename,0644);??
  3. ????redisAssert(server.aof_state?==?REDIS_AOF_OFF);??
  4. ?????(server.aof_fd?==?-1)?{??
  5. ????????redisLog(REDIS_WARNING,,strerror(errno));??
  6. ?????????REDIS_ERR;??
  7. ????}??
  8. ?????(rewriteAppendOnlyFileBackground()?==?REDIS_ERR)?{??
  9. ????????close(server.aof_fd);??
  10. ????????redisLog(REDIS_WARNING,);??
  11. ?????????REDIS_ERR;??
  12. ????}??
  13. ?????
  14. ??
  15. ????server.aof_state?=?REDIS_AOF_WAIT_REWRITE;??
  16. ?????REDIS_OK;??
  17. }??

Redis AOF rewrite机制的实现

从上述分析可以看出rewrite的实现全部依靠rewriteAppendOnlyFileBackground函数,下面分析该函数,通过下面的代码可以看出,Redis是fork出一个子进程来操作AOF rewrite,然后子进程调用rewriteAppendOnlyFile函数,将数据写到一个临时文件temp-rewriteaof-bg-%d.aof中。如果子进程完成会通过exit(0)函数通知父进程rewrite结束,在serverCron函数中使用wait3函数接收子进程退出状态,然后执行后续的AOF rewrite的收尾工作,后面将会分析。

父进程的工作主要包括清楚server.aof_rewrite_scheduled标志,记录子进程IDserver.aof_child_pid = childpid,记录rewrite的开始时间server.aof_rewrite_time_start = time(NULL)等。
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ?rewriteAppendOnlyFileBackground()?{??
  1. ????pid_t?childpid;??
  2. ??????start;??
  3. ??
  4. ??????
  5. ?????(server.aof_child_pid?!=?-1)??REDIS_ERR;??
  6. ????start?=?ustime();??
  7. ?????((childpid?=?fork())?==?0)?{??
  8. ?????????tmpfile[256];??
  9. ??
  10. ??????????
  11. ????????closeListeningSockets(0);??
  12. ????????redisSetProcTitle();??
  13. ????????snprintf(tmpfile,256,,?()?getpid());??
  14. ?????????(rewriteAppendOnlyFile(tmpfile)?==?REDIS_OK)?{??
  15. ?????????????private_dirty?=?zmalloc_get_private_dirty();??
  16. ??
  17. ?????????????(private_dirty)?{??
  18. ????????????????redisLog(REDIS_NOTICE,??
  19. ????????????????????,??
  20. ????????????????????private_dirty/(1024*1024));??
  21. ????????????}??
  22. ????????????exitFromChild(0);??
  23. ????????}??{??
  24. ????????????exitFromChild(1);??
  25. ????????}??
  26. ????}??{??
  27. ??????????
  28. ????????server.stat_fork_time?=?ustime()-start;??
  29. ?????????(childpid?==?-1)?{??
  30. ????????????redisLog(REDIS_WARNING,??
  31. ????????????????,??
  32. ????????????????strerror(errno));??
  33. ?????????????REDIS_ERR;??
  34. ????????}??
  35. ????????redisLog(REDIS_NOTICE,??
  36. ????????????,childpid);??
  37. ????????server.aof_rewrite_scheduled?=?0;??
  38. ????????server.aof_rewrite_time_start?=?time(NULL);??
  39. ????????server.aof_child_pid?=?childpid;??
  40. ????????updateDictResizePolicy();??
  41. ?????????
  42. ?
  43. ?
  44. ??
  45. ????????server.aof_selected_db?=?-1;??
  46. ????????replicationScriptCacheFlush();??
  47. ?????????REDIS_OK;??
  48. ????}??
  49. ?????REDIS_OK;???
  50. }??

接下来介绍rewriteAppendOnlyFile函数,该函数的主要工作为:遍历所有数据库中的数据,将其写入到临时文件temp-rewriteaof-%d.aof中,写入函数定义在rio.c中,比较简单,然后将数据刷新到硬盘中,然后将文件名rename为其调用者给定的临时文件名,注意仔细看代码,这里并没有修改为正式的AOF文件名。

在写入文件时如果设置server.aof_rewrite_incremental_fsync参数,那么在rioWrite函数中fwrite部分数据就会将数据fsync到硬盘中,来保证数据的正确性。
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ?rewriteAppendOnlyFile(?*filename)?{??
  1. ????dictIterator?*di?=?NULL;??
  2. ????dictEntry?*de;??
  3. ????rio?aof;??
  4. ?????*fp;??
  5. ?????tmpfile[256];??
  6. ?????j;??
  7. ??????now?=?mstime();??
  8. ??
  9. ?????
  10. ??
  11. ????snprintf(tmpfile,,?()?getpid());??
  12. ????fp?=?fopen(tmpfile,);??
  13. ?????(!fp)?{??
  14. ????????redisLog(REDIS_WARNING,?,?strerror(errno));??
  15. ?????????REDIS_ERR;??
  16. ????}??
  17. ??
  18. ????rioInitWithFile(&aof,fp);???
  19. ????io.file.autosync?=?bytes;每32M刷新一次??
  20. ?????(server.aof_rewrite_incremental_fsync)??
  21. ????????rioSetAutoSync(&aof,REDIS_AOF_AUTOSYNC_BYTES);??
  22. ?????(j?=?0;?j???
  23. ?????????selectcmd[]?=?;??
  24. ????????redisDb?*db?=?server.db+j;??
  25. ????????dict?*d?=?db->dict;??
  26. ?????????(dictSize(d)?==?0)?;??
  27. ????????di?=?dictGetSafeIterator(d);??
  28. ?????????(!di)?{??
  29. ????????????fclose(fp);??
  30. ?????????????REDIS_ERR;??
  31. ????????}??
  32. ??
  33. ??????????
  34. ?????????(rioWrite(&aof,selectcmd,(selectcmd)-1)?==?0)??werr;??
  35. ?????????(rioWriteBulkLongLong(&aof,j)?==?0)??werr;??
  36. ??
  37. ??????????
  38. ????????((de?=?dictNext(di))?!=?NULL)?{??
  39. ????????????sds?keystr;??
  40. ????????????robj?key,?*o;??
  41. ??????????????expiretime;??
  42. ??
  43. ????????????keystr?=?dictGetKey(de);??
  44. ????????????o?=?dictGetVal(de);??
  45. ????????????initStaticStringObject(key,keystr);??
  46. ??
  47. ????????????expiretime?=?getExpire(db,&key);??
  48. ??
  49. ??????????????
  50. ?????????????(expiretime?!=?-1?&&?expiretime?;??
  51. ??
  52. ??????????????
  53. ?????????????(o->type?==?REDIS_STRING)?{??
  54. ??????????????????
  55. ?????????????????cmd[]=;??
  56. ?????????????????(rioWrite(&aof,(cmd)-1)?==?0)??werr;??
  57. ??????????????????
  58. ?????????????????(rioWriteBulkObject(&aof,&key)?==?0)??werr;??
  59. ?????????????????(rioWriteBulkObject(&aof,o)?==?0)??werr;??
  60. ????????????}???(o->type?==?REDIS_LIST)?{??
  61. ?????????????????(rewriteListObject(&aof,&key,o)?==?0)??werr;??
  62. ????????????}???(o->type?==?REDIS_SET)?{??
  63. ?????????????????(rewriteSetObject(&aof,o)?==?0)??werr;??
  64. ????????????}???(o->type?==?REDIS_ZSET)?{??
  65. ?????????????????(rewriteSortedSetObject(&aof,o)?==?0)??werr;??
  66. ????????????}???(o->type?==?REDIS_HASH)?{??
  67. ?????????????????(rewriteHashObject(&aof,o)?==?0)??werr;??
  68. ????????????}??{??
  69. ????????????????redisPanic();??
  70. ????????????}??
  71. ??????????????
  72. ?????????????(expiretime?!=?-1)?{??
  73. ?????????????????cmd[]=;??
  74. ?????????????????(rioWrite(&aof,(cmd)-1)?==?0)??werr;??
  75. ?????????????????(rioWriteBulkObject(&aof,&key)?==?0)??werr;??
  76. ?????????????????(rioWriteBulkLongLong(&aof,expiretime)?==?0)??werr;??
  77. ????????????}??
  78. ????????}??
  79. ????????dictReleaseIterator(di);??
  80. ????}??
  81. ??
  82. ??????
  83. ????fflush(fp);??
  84. ????aof_fsync(fileno(fp));??
  85. ????fclose(fp);??
  86. ??
  87. ?????
  88. ??
  89. ?????(rename(tmpfile,filename)?==?-1)?{??
  90. ????????redisLog(REDIS_WARNING,,?strerror(errno));??
  91. ????????unlink(tmpfile);??
  92. ?????????REDIS_ERR;??
  93. ????}??
  94. ????redisLog(REDIS_NOTICE,);??
  95. ?????REDIS_OK;??
  96. ??
  97. werr:??
  98. ????fclose(fp);??
  99. ????unlink(tmpfile);??
  100. ????redisLog(REDIS_WARNING,,?strerror(errno));??
  101. ?????(di)?dictReleaseIterator(di);??
  102. ?????REDIS_ERR;??
  103. }??

AOF rewrite工作到这里已经结束一半,上一篇文章提到如果server.aof_state != REDIS_AOF_OFF,那么就会将客户端请求指令修改的数据通过feedAppendOnlyFile函数追加到AOF文件中,那么此时AOF已经rewrite了,必须要处理此时出现的差异数据,记得在feedAppendOnlyFile函数中有这么一段代码

[cpp]?在CODE上查看代码片派生到我的代码片
?
    ?(server.aof_child_pid?!=?-1)??
  1. ????????aofRewriteBufferAppend((unsigned?*)buf,sdslen(buf));??

如果AOF rewrite正在进行,那么就将修改数据的指令字符串存储到server.aof_rewrite_buf_blocks链表中,等待AOF rewrite子进程结束后处理,处理此部分数据的代码在serverCron函数中。需要指出的是wait3函数我不了解,可能下面注释会有点问题。

[cpp]?在CODE上查看代码片派生到我的代码片
?
    ??
  1. ??
  2. ?(server.rdb_child_pid?!=?-1?||?server.aof_child_pid?!=?-1)?{??
  3. ?????statloc;??
  4. ????pid_t?pid;??
  5. ??
  6. ?????((pid?=?wait3(&statloc,WNOHANG,NULL))?!=?0)?{??
  7. ?????????exitcode?=?WEXITSTATUS(statloc);??
  8. ?????????bysignal?=?0;??
  9. ??
  10. ?????????(WIFSIGNALED(statloc))?bysignal?=?WTERMSIG(statloc);??
  11. ??
  12. ?????????(pid?==?server.rdb_child_pid)?{??
  13. ????????????backgroundSaveDoneHandler(exitcode,bysignal);??
  14. ????????}???(pid?==?server.aof_child_pid)?{??
  15. ????????????backgroundRewriteDoneHandler(exitcode,bysignal);??
  16. ????????}??{??
  17. ????????????redisLog(REDIS_WARNING,??
  18. ????????????????,??
  19. ????????????????()pid);??
  20. ????????}??
  21. ??????????
  22. ????????updateDictResizePolicy();??
  23. ????}??
  24. }??

对于AOF rewrite期间出现的差异数据,Server通过backgroundSaveDoneHandler函数将server.aof_rewrite_buf_blocks链表中数据追加到新的AOF文件中。

backgroundSaveDoneHandler函数执行步骤:
1、通过判断子进程的退出状态,正确的退出状态为exit(0),即exitcode为0,bysignal我不清楚具体意义,如果退出状态正确,backgroundSaveDoneHandler函数才会开始处理
2、通过对rewriteAppendOnlyFileBackground函数的分析,可以知道rewrite后的AOF临时文件名为temp-rewriteaof-bg-%d.aof(%d=server.aof_child_pid)中,接着需要打开此临时文件
3、调用aofRewriteBufferWrite函数将server.aof_rewrite_buf_blocks中差异数据写到该临时文件中
4、如果旧的AOF文件未打开,那么打开旧的AOF文件,将文件描述符赋值给临时变量oldfd
5、将临时的AOF文件名rename为正常的AOF文件名
6、如果旧的AOF文件未打开,那么此时只需要关闭新的AOF文件,此时的server.aof_rewrite_buf_blocks数据应该为空;如果旧的AOF是打开的,那么将server.aof_fd指向newfd,然后根据相应的fsync策略将数据刷新到硬盘上
7、调用aofUpdateCurrentSize函数统计AOF文件的大小,更新server.aof_rewrite_base_size,为serverCron中自动AOF rewrite做相应判断
8、如果之前是REDIS_AOF_WAIT_REWRITE状态,则设置server.aof_state为REDIS_AOF_ON,因为只有“config set appendonly yes”指令才会设置这个状态,也就是需要写完快照后,立即打开AOF;而BGREWRITEAOF不需要打开AOF
9、调用后台线程去关闭旧的AOF文件
下面是backgroundSaveDoneHandler函数的注释代码
?
[cpp]?在CODE上查看代码片派生到我的代码片
?
    ?
  1. ??
  2. ?backgroundRewriteDoneHandler(?exitcode,??bysignal)?{??
  3. ?????(!bysignal?&&?exitcode?==?0)?{??
  4. ?????????newfd,?oldfd;??
  5. ?????????tmpfile[256];??
  6. ??????????now?=?ustime();??
  7. ??
  8. ????????redisLog(REDIS_NOTICE,??
  9. ????????????);??
  10. ??
  11. ?????????
  12. ??
  13. ????????snprintf(tmpfile,??
  14. ????????????()server.aof_child_pid);??
  15. ????????newfd?=?open(tmpfile,O_WRONLY|O_APPEND);??
  16. ?????????(newfd?==?-1)?{??
  17. ????????????redisLog(REDIS_WARNING,??
  18. ????????????????,?strerror(errno));??
  19. ?????????????cleanup;??
  20. ????????}??
  21. ??????????
  22. ?????????(aofRewriteBufferWrite(newfd)?==?-1)?{??
  23. ????????????redisLog(REDIS_WARNING,??
  24. ????????????????,?strerror(errno));??
  25. ????????????close(newfd);??
  26. ?????????????cleanup;??
  27. ????????}??
  28. ??
  29. ????????redisLog(REDIS_NOTICE,??
  30. ????????????,?aofRewriteBufferSize());??
  31. ??
  32. ?????????
  33. ?
  34. ?
  35. ?
  36. ?
  37. ?
  38. ?
  39. ?
  40. ?
  41. ?
  42. ?
  43. ?
  44. ?
  45. ?
  46. ?
  47. ?
  48. ?
  49. ?
  50. ?
  51. ?
  52. ?
  53. ?
  54. ?
  55. ?
  56. ?
  57. ?
  58. ??
  59. ?????????(server.aof_fd?==?-1)?{??
  60. ??????????????
  61. ??
  62. ??????????????
  63. ?
  64. ??
  65. ?????????????oldfd?=?open(server.aof_filename,O_RDONLY|O_NONBLOCK);??
  66. ????????}??{??
  67. ??????????????
  68. ????????????oldfd?=?-1;???
  69. ????????}??
  70. ??
  71. ?????????
  72. ??
  73. ??????????
  74. ??????????
  75. ?????????(rename(tmpfile,server.aof_filename)?==?-1)?{??
  76. ????????????redisLog(REDIS_WARNING,??
  77. ????????????????,?strerror(errno));??
  78. ????????????close(newfd);??
  79. ?????????????(oldfd?!=?-1)?close(oldfd);??
  80. ?????????????cleanup;??
  81. ????????}??
  82. ??????????
  83. ??????????
  84. ??????????
  85. ?????????(server.aof_fd?==?-1)?{??
  86. ?????????????
  87. ??
  88. ????????????close(newfd);??
  89. ????????}??{??
  90. ??????????????
  91. ????????????oldfd?=?server.aof_fd;??
  92. ??????????????
  93. ????????????server.aof_fd?=?newfd;??
  94. ??????????????
  95. ?????????????(server.aof_fsync?==?AOF_FSYNC_ALWAYS)??
  96. ????????????????aof_fsync(newfd);??
  97. ??????????????(server.aof_fsync?==?AOF_FSYNC_EVERYSEC)??
  98. ????????????????aof_background_fsync(newfd);??
  99. ????????????server.aof_selected_db?=?-1;???
  100. ????????????aofUpdateCurrentSize();??
  101. ????????????server.aof_rewrite_base_size?=?server.aof_current_size;??
  102. ??
  103. ?????????????
  104. ??
  105. ??????????????
  106. ????????????sdsfree(server.aof_buf);??
  107. ????????????server.aof_buf?=?sdsempty();??
  108. ????????}??
  109. ??
  110. ????????server.aof_lastbgrewrite_status?=?REDIS_OK;??
  111. ??
  112. ????????redisLog(REDIS_NOTICE,?);??
  113. ??????????
  114. ??????????
  115. ?????????(server.aof_state?==?REDIS_AOF_WAIT_REWRITE)??
  116. ????????????server.aof_state?=?REDIS_AOF_ON;??
  117. ??
  118. ??????????
  119. ??????????
  120. ?????????(oldfd?!=?-1)?bioCreateBackgroundJob(REDIS_BIO_CLOSE_FILE,(*)()oldfd,NULL);??
  121. ??
  122. ????????redisLog(REDIS_VERBOSE,??
  123. ????????????,?ustime()-now);??
  124. ????}???(!bysignal?&&?exitcode?!=?0)?{??
  125. ????????server.aof_lastbgrewrite_status?=?REDIS_ERR;??
  126. ??
  127. ????????redisLog(REDIS_WARNING,??
  128. ????????????);??
  129. ????}??{??
  130. ????????server.aof_lastbgrewrite_status?=?REDIS_ERR;??
  131. ??
  132. ????????redisLog(REDIS_WARNING,??
  133. ????????????,?bysignal);??
  134. ????}??
  135. ??
  136. cleanup:??
  137. ????aofRewriteBufferReset();??
  138. ????aofRemoveTempFile(server.aof_child_pid);??
  139. ????server.aof_child_pid?=?-1;??
  140. ????server.aof_rewrite_time_last?=?time(NULL)-server.aof_rewrite_time_start;??
  141. ????server.aof_rewrite_time_start?=?-1;??
  142. ??????
  143. ?????(server.aof_state?==?REDIS_AOF_WAIT_REWRITE)??
  144. ????????server.aof_rewrite_scheduled?=?1;??
  145. }??
?

至此,AOF数据持久化已经全部结束了,剩下的就是一些细节的处理,以及一些Linux库函数的理解,对于rename、unlink、wait3等库函数的深入认识就去问Google吧。

?

小结

?
Redis AOF数据持久化的实现机制通过三篇文章基本上比较详细的分析了,但这只是从代码层面去看AOF,对于AOF持久化的优缺点网上有很多分析,Redis的官方网站也有英文介绍,Redis的数据持久化还有一种方法叫RDB,更多RDB的内容等下次再分析。
感谢此篇博客给我在理解Redis AOF数据持久化方面的巨大帮助,,此篇博客对AOF的分析十分的详细。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读