范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

redis之AOF文件加载过程

  redis支持2种持久化功能,分别是RDB持久化和AOF(Append Only File)持久化。
  今天总结下redis加载AOF文件过程,以及加载AOF过程中遇到的问题。
  由于AOF文件里面包含了重建redis数据库状态所需要的所有命令,因此在redis启动过程中需要加载一次AOF文件(前提是redis配置文件中使用的是aof文件),这样就可以还原之前的redis所有状态了。
  redis在启动时加载AOF过程如下 int main(int argc, char **argv) {   ...    // 如果服务器不是运行在 SENTINEL 模式,那么执行以下代码     if (!server.sentinel_mode) { //sentinel和集群只能二选1         /* Things not needed when running in Sentinel mode. */         redisLog(REDIS_WARNING,"Server started, Redis version " REDIS_VERSION);     #ifdef __linux__         linuxOvercommitMemoryWarning();     #endif         // 从 AOF 文件或者 RDB 文件中载入数据         loadDataFromDisk();         // 判断是否启动集群         if (server.cluster_enabled) { //在该函数前会先载入cluster配置nodes.conf,见initServer->clusterInit;             if (verifyClusterConfigWithData() == REDIS_ERR) {                 redisLog(REDIS_WARNING,                     "You can"t have keys in a DB different than DB 0 when in "                     "Cluster mode. Exiting.");                 exit(1);             }         }         // 打印 TCP 端口         if (server.ipfd_count > 0)             redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);         // 打印本地套接字端口         if (server.sofd > 0)             redisLog(REDIS_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);     } else { //sentinel和集群只能二选1         sentinelIsRunning();     }       /* Warning the user about suspicious maxmemory setting. */     // 检查不正常的 maxmemory 配置     if (server.maxmemory > 0 && server.maxmemory < 1024*1024) {         redisLog(REDIS_WARNING,"WARNING: You specified a maxmemory value that is less than 1MB (current value is %llu bytes). Are you sure this is what you really want?", server.maxmemory);     }       // 运行事件处理器,一直到服务器关闭为止     aeSetBeforeSleepProc(server.el,beforeSleep);     aeMain(server.el);        // 服务器关闭,停止事件循环     aeDeleteEventLoop(server.el);       return 0; }
  从上面代码得知,redis在loadDataFromDisk()中加载AOF文件。 void loadDataFromDisk(void) { //loadDataFromDisk和rdbSave对应加载写入     // 记录开始时间     long long start = ustime();     // AOF 持久化是否已打开     if (server.aof_state == REDIS_AOF_ON) {         // 尝试载入 AOF 文件         if (loadAppendOnlyFile(server.aof_filename) == REDIS_OK)             // 打印载入信息,并计算载入耗时长度             redisLog(REDIS_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000);     // AOF 持久化未打开     } else {         // 尝试载入 RDB 文件         if (rdbLoad(server.rdb_filename) == REDIS_OK) {             // 打印载入信息,并计算载入耗时长度             redisLog(REDIS_NOTICE,"DB loaded from disk: %.3f seconds",                 (float)(ustime()-start)/1000000);         } else if (errno != ENOENT) {             redisLog(REDIS_WARNING,"Fatal error loading the DB: %s. Exiting.",strerror(errno));             exit(1);         }     } }
  若开启使用的是AOF持久化,则调用loadAppendOnlyFile进行加载AOF文件。 int loadAppendOnlyFile(char *filename) {      //伪客户端     struct redisClient *fakeClient;       // 打开 AOF 文件     FILE *fp = fopen(filename,"r");、     struct redis_stat sb;     int old_aof_state = server.aof_state;     long loops = 0;        // 检查文件的正确性     if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) {         server.aof_current_size = 0;         fclose(fp);         return REDIS_ERR;     }      // 检查文件是否正常打开     if (fp == NULL) {         redisLog(REDIS_WARNING,"Fatal error: can"t open the append log file for reading: %s",strerror(errno));         exit(1);     }     /* Temporarily disable AOF, to prevent EXEC from feeding a MULTI      * to the same file we"re about to read.       * 暂时性地关闭 AOF ,防止在执行 MULTI 时,           * EXEC 命令被传播到正在打开的 AOF 文件中。      */     server.aof_state = REDIS_AOF_OFF;     //创建一个伪客户端     fakeClient = createFakeClient();     // 设置服务器的状态为:正在载入         startLoading(fp); //startLoading 定义于 rdb.c       while(1) {         int argc, j;         unsigned long len;         robj **argv;         char buf[128];         sds argsds;         struct redisCommand *cmd;           /* Serve the clients from time to time           * 间隔性地处理客户端发送来的请求                   * 因为服务器正处于载入状态,所以能正常执行的只有 PUBSUB 等模块          */         if (!(loops++ % 1000)) {             loadingProgress(ftello(fp));             processEventsWhileBlocked();         }          // 读入文件内容到缓存         if (fgets(buf,sizeof(buf),fp) == NULL) {             if (feof(fp))                 break; // 文件已经读完,跳出             else                 goto readerr;         }           // 确认协议格式,比如 *3r          if (buf[0] != "*") goto fmterr;         // 取出命令参数,比如 *3r  中的 3         argc = atoi(buf+1);        // 至少要有一个参数(被调用的命令)         if (argc < 1) goto fmterr;         // 从文本中创建字符串对象:包括命令,以及命令参数                 // 例如 $3r SETr $3r KEYr $5r VALUEr                 // 将创建三个包含以下内容的字符串对象:         // SET 、 KEY 、 VALUE         argv = zmalloc(sizeof(robj*)*argc);         for (j = 0; j < argc; j++) {             if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;               if (buf[0] != "#39;) goto fmterr;                // 读取参数值的长度             len = strtol(buf+1,NULL,10);             // 读取参数值                         argsds = sdsnewlen(NULL,len);                         if (len && fread(argsds,len,1,fp) == 0)                 goto fmterr;                           // 为参数创建对象             argv[j] = createObject(REDIS_STRING,argsds);               if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */         }           /* Command lookup           *查找命令          */         cmd = lookupCommand(argv[0]->ptr);         if (!cmd) {             redisLog(REDIS_WARNING,"Unknown command "%s" reading the append only file", (char*)argv[0]->ptr);             exit(1);         }           /* Run the command in the context of a fake client           * 调用伪客户端,执行命令          */         fakeClient->argc = argc;         fakeClient->argv = argv;         cmd->proc(fakeClient);           /* The fake client should not have a reply */         redisAssert(fakeClient->bufpos == 0 && listLength(fakeClient->reply) == 0);         /* The fake client should never get blocked */         redisAssert((fakeClient->flags & REDIS_BLOCKED) == 0);           /* Clean up. Command code may have changed argv/argc so we use the          * argv/argc of the client instead of the local variables.           * 清理命令和命令参数对象          */         for (j = 0; j < fakeClient->argc; j++)             decrRefCount(fakeClient->argv[j]);         zfree(fakeClient->argv);     }       /* This point can only be reached when EOF is reached without errors.      * If the client is in the middle of a MULTI/EXEC, log error and quit.       * 如果能执行到这里,说明 AOF 文件的全部内容都可以正确地读取,           * 但是,还要检查 AOF 是否包含未正确结束的事务      */     if (fakeClient->flags & REDIS_MULTI) goto readerr;       fclose(fp);    // 释放伪客户端     freeFakeClient(fakeClient);    // 复原 AOF 状态     server.aof_state = old_aof_state;    // 停止载入     stopLoading();     // 更新服务器状态中, AOF 文件的当前大小     aofUpdateCurrentSize();     // 记录前一次重写时的大小     server.aof_rewrite_base_size = server.aof_current_size;     return REDIS_OK;   // 读入错误 readerr:     // 非预期的末尾,可能是 AOF 文件在写入的中途遭遇了停机     if (feof(fp)) {         redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");      // 文件内容出错     } else {         redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));     }     exit(1); // 内容格式错误 fmterr:     redisLog(REDIS_WARNING,"Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix ");     exit(1); }
  由于AOF文件中保存的都是用户可见的一条条命令,因此loadAppendOnlyFile通过创建一个伪客户端读取AOF文件获取一条条命令来恢复执行。
  redis读取AOF文件并还原数据库的状态过程如下:
  以上就是服务器根据读入AOF文件进行还原数据库状态的原理。
  从上面的介绍可以知道加载AOF文件是redis启动过程中的步骤,当业务线程启动连接redis获取或者保存数据时,若redis正在加载数据,则有可能获取不到数据: 127.0.0.1:6379> get a (error) LOADING Redis is loading the dataset in memory
  原因是当加载过程中,有些客户端发来的命令是不执行的,直接返回上述结果。只有命令带有"l"(小写的L)标志的才会执行,比如info命令等。
  那么怎么判断AOF文件是否加载完成呢?
  刚才说到加载时可以执行info命令,redis info 命令以一种易于理解和阅读的格式,返回关于 Redis 服务器的各种信息和统计数值。该统计信息中有Persistence 参数,该参数中记录着 RDB 和 AOF 的相关信息,其中有个loading字段标志这数据是否正在加载,当正在加载时为1,加载完为0,因此可以根据该字段来判断数据是否加载完毕。 127.0.0.1:6379> info Persistence # Persistence loading:1    // 1表示正在加载数据 ...   127.0.0.1:6379> info Persistence # Persistence loading:0   // 0表示数据加载完毕 ...
  因此业务线程可以根据info命令获取loading 进行判断数据是否加载完毕。 public boolean isLoading(){   try{         String info = (String)redisTemplate.getRequiredConnectionFactory().getConnection()                       .info("Persistence").get("loading");         if("0".equalsIgnoreCase(info)){           return true;         }   }catch (Exception e){       error("Failed to get loading status : {}", e.getMessage());   }   return false; }

家里有小米试试这样做,不用油炸也能香酥可口,做法简单越嚼越香大家好,我是Allie,美好的一天从营养早餐开始,吃好早餐,一整天都精力充沛。早餐吃好午餐吃饱晚餐吃少,低油低盐清淡饮食,这是我多年的习惯,希望和朋友们一起吃出健康吃出美丽吃出好身新民艺评丨相相亲,看看展,聊聊爱人民公园,地处上海市中心最繁华的地段,蜿蜒的曲桥将园内水景分为荷花池和碧翠湖,小桥流水和西山景区的瀑布溪流给游客以欢快之感。人民公园承载着历代上海市民的幸福时光,近年来,周末热闹非第15届海口东盟国家驻广州总领馆对话会在海口举行12月7日,第15届海口东盟国家驻广州总领馆对话会在海口举行。张月和摄中新网海口12月7日电(张月和)以海南自贸港与RCEP重点产业合作机遇为主题的第15届海口东盟国家驻广州总领馆中国空间站第三批空间科学实验样品顺利返回新华社北京12月5日电(记者张泉张建松)神舟十四号载人飞船返回舱12月4日在东风着陆场成功着陆。随舱下行的空间站第三批空间科学实验样品在着陆场交付载人航天工程空间应用系统,并于5日EVGA拍卖其RTX4090原型卡,收入将用作慈善用途EVGA是英伟达在北美最大的AIC,在新一代基于AdaLovelace架构的GeForceRTX40系列发布前突然宣布退出显卡市场,在市场和PC爱好者中引起了很大的反响。当时EVG此刻,冬日里的暗香浮动,快来寻找瘦西湖里第一枝蜡梅花吧冬风扫尽深秋叶,一种生命已走到尽头,却另有一种生机在悄然萌动,是冲寒而开的蜡梅。瘦西湖小金山附近小红桥南疏风馆长廊的几树枝头上,星星点点间已见花蕊,鹅黄色的花苞初绽,预示着一场香气46岁曾黎真时髦,穿黑色皮衣皮裤帅气又拉风,身材气质都很绝头条创作挑战赛通过穿衣风格来改变一个人的气质,是最简单直接的方式。也许内在的涵养品味的修炼,都需要时间的沉淀。但外在的穿衣风格的变化,却简单容易的多。如果你厌倦了同一种风格,不妨试丁俊晖呼吁拯救斯诺克运动,赛制不利于新人成长,中国恐后继无人日前,中国斯诺克领军人物丁俊晖在英国接受了当地媒体TheMetro的独家专访。作为世界斯诺克的知名选手,丁俊晖呼吁当下要拯救斯诺克运动,因此要做出一些改变。采访中提及了现行的排名赛苏有朋最新写真大片曝光坚毅侧脸凸显冷峻气场1905电影网讯近日,苏有朋最新写真大片曝光。苏有朋身穿黑色质感西装叠搭同款色系衬衫,直视镜头充满故事感,简约质感突显个人气场。而内页中,苏有朋则演绎百变风格,黑白色调中坚毅侧脸透资讯带娃神器?福特申请基于音频的婴儿安静系统专利文懂车帝原创常思玥懂车帝原创行业近日,据外媒Fordauthority报道,福特汽车申请了一项与婴儿乘车相关的专利,据了解,该专利可以通过音频让婴儿安静下来。图片来源Fordaut热播剧县委大院微信聊天暴露的细节县委大院央视热播剧县委大院的热播,让我们大家看到了政府工作中的一些不常见的方面,其中的一个细节让人觉得剧组确确实实的用心了。就如图片所示,梅晓歌想要去跟吕青山请示讲话稿是否可以公开
今年37在成都工资8000啥水平?看到评论区很多人都说自己月薪过万。我不太相信。人人月薪过万绝对是假打。很多人都说问问题的人月薪太少了,但是我要说的是问问题的人月薪已经算是中等上等了。我说一下我和朋友的情况,我目前一年级的孩子考试时老师不读题,合理吗?我是小学老师,去年带的一年级学生。我来说说这问题。以我所在的区域来说吧。先说说一年级孩子们面临的第一次大型考试,就是年终统测。我们年终期末统测时,一年级的试卷是有拼音的,也就是说题如果现在A股股票数量和2008年是一样的,那现在对应的点位应该是多少?这是一个非常有趣的问题!其实老股民都知道目前的A股市处于一个失真股指的状态,因为20142018年我们的A股发行量太大,从2500多只股票扩容到了3600多只股票,并且再加上上证5儿子1岁9个月,想培养双语宝宝,自己应该怎么办?孩子会不会混乱?孩子从1至2。5岁是言语掌握的重要时期,有人做个统计,人到了2。5岁可以掌握3000个单词,甚至掌握全部的母语知识。这些知识从何而来?主要是从抚养者那里习得的。怎么得来的?是受语言入伏后,是排毒黄金期,出现哪几个迹象,需抓紧时间排毒?大家好,我是波波医生,现在在疾控中心从事性病艾滋病丙肝防治工作,我来谈谈我的看法。2020入伏从7月16日算起,7月25日初伏结束,共10天。入伏也称头伏或初伏指夏至后第三个庚日起对应届本科生,你有哪些求职方面的建议?没有。这个不能好为人师的,搞不好就误了人家的前途。一般的211院校毕业本科生,冷门专业,求职时应注意的事项如下一早作准备,未雨绸缪。在大四时就要考虑就业问题。思路又有三条,一是准备做了5年程序员不想继续干这行了,请问能有其他什么好的行业推荐?目前薪资15w?从事软件开发已经十几年了,在入行5年的时候还处于对技术极度推崇的阶段,中间还放弃了一家非常有发展潜力并且在里面已经混到了技术经理的位置,最后因为对技术的执着毅然去了一家自认为高大山电视剧风筝有哪些比较大的漏洞?最大的漏洞就是韩冰绝不可能是特务,剧中的韩冰是1931年在江西参加红军的,那个年代参加红军肯定是从底层开始奋斗的,且不说经历过五次反围剿有多么残酷,走过万里长征的红军战士,从出发时山东男篮有篮协副主席宫鲁鸣坐镇,第二阶段能否走出困境?山东男篮有篮协副主席宫鲁鸣坐阵,第二阶段能否走出困境?要说篮协副主席,新疆的阿的江也是篮协副主席,困境比山东还严重,球队走出困境并不是说他们是篮协副主席,关键宫鲁鸣原来也是中国男篮瓜迪奥拉执教曼城一来花了多少钱?16年夏天到21年冬天,瓜迪奥拉截止到目前执教曼城4年半的时间,在转会市场上的总投入已经达到9。5亿欧。就像此前瓜迪奥拉在接受采访的时候所言,曼城能有现在的成绩,如今已经21连胜的在换相机的时候,你觉得是买D850全画幅好,还是D500的apsc好?为什么?换相机这个问题我觉得有点意思啊,题主本身用的是D7000,半幅单反,如果说要换相机还继续半幅的话,那么,换了又有什么意义?不用说D850太贵D850是目前尼康机器里面处于高端单反了