• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

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

mysql 搞代码 4年前 (2022-01-09) 19次浏览 已收录 0个评论

本文所引用的源码全部来自Redis2.8.2版本。 Redis AOF数据持久化机制的实现相关代码是redis.c, redis.h, aof.c, bio.c, rio.c, config.c 在阅读本文之前请先阅读Redis数据持久化机制AOF原理分析之配置详解文章,了解AOF相关参数的解析,文章链接 http://blog

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

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

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

http://blog.gaodaima.com/acceptedxukai/article/details/18135219

转载请注明,文章出自http://blog.gaodaima.com/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数据库中。

/* Function called at startup to load RDB or AOF file in memory. */void loadDataFromDisk(void) {    long long start = ustime();    if (server.aof_state == REDIS_AOF_ON) {        if (loadAppendOnlyFile(server.aof_filename) == REDIS_OK)            redisLog(REDIS_NOTICE,"DB loaded from append only file: %.3f seconds",(float)(ustime()-start)/1000000);    } else {        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);        }    }}

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

int loadAppendOnlyFile(char *filename) {    struct redisClient *fakeClient;    FILE *fp = fopen(filename,"r");    struct redis_stat sb;    int old_aof_state = server.aof_state;    long loops = 0;    //redis_fstat就是fstat64函数,通过fileno(fp)得到文件描述符,获取文件的状态存储于sb中,    //具体可以参考stat函数,st_size就是文件的字节数    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. */    server.aof_state = REDIS_AOF_OFF;    fakeClient = createFakeClient(); //建立伪终端    startLoading(fp); // 定义于 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 */        // 有间隔地处理外部请求,ftello()函数得到文件的当前位置,返回值为long        if (!(loops++ % 1000)) {            loadingProgress(ftello(fp));//保存aof文件读取的位置,ftellno(fp)获取文件当前位置            aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);//处理事件        }        //按行读取AOF数据        if (fgets(buf,sizeof(buf),fp) == NULL) {            if (feof(fp))//达到文件尾EOF                break;            else                goto readerr;        }        //读取AOF文件中的命令,依照Redis的协议处理        if (buf[0] != '*') goto fmterr;        argc = atoi(buf+1);//参数个数        if (argc < 1) goto fmterr;        argv = zmalloc(sizeof(robj*)*argc);//参数值        for (j = 0; j ptr);        if (!cmd) {            red<p style="color:transparent">本文来源gao!%daima.com搞$代*!码$网3</p>isLog(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 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. */    if (fakeClient->flags & REDIS_MULTI) goto readerr;    fclose(fp);    freeFakeClient(fakeClient);    server.aof_state = old_aof_state;    stopLoading();    aofUpdateCurrentSize(); //更新server.aof_current_size,AOF文件大小    server.aof_rewrite_base_size = server.aof_current_size;    return REDIS_OK;	…………}

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

void aofUpdateCurrentSize(void) {    struct redis_stat sb;    if (redis_fstat(server.aof_fd,&sb) == -1) {        redisLog(REDIS_WARNING,"Unable to obtain the AOF file length. stat: %s",            strerror(errno));    } else {        server.aof_current_size = sb.st_size;    }}

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

/* Open the AOF file if needed. */    if (server.aof_state == REDIS_AOF_ON) {        server.aof_fd = open(server.aof_filename,O_WRONLY|O_APPEND|O_CREAT,0644);        if (server.aof_fd == -1) {            redisLog(REDIS_WARNING, "Can't open the append-only file: %s",strerror(errno));            exit(1);        }    }

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

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

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


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Redis数据持久化机制AOF原理分析一

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址