Redis Server启动过程的详细步骤

目录
  • 1、 初始化参数配置
  • 2、 加载并解析配置文件
  • 3、 初始化服务器内部变量
  • 4、执行事件驱动框架

本文基于社区版redis 4.0.8

1、 初始化参数配置

由函数initserverconfig()实现,具体操作就是给配置参数赋初始化值:

//设置时区
setlocale(lc_collate,"");
//设置随机种子
char hashseed[16];
getrandomhexchars(hashseed,sizeof(hashseed));
dictsethashfunctionseed((uint8_t*)hashseed);
//初始化module
void initserverconfig(void) {
    //servercron函数执行频率,默认10ms
    server.hz = config_default_hz;
    //监听端口,默认6379
    server.port = config_default_server_port;
    server.tcp_backlog = config_default_tcp_backlog;
    server.dbnum = config_default_dbnum;
    ......
    //初始化命令表
    server.commands = dictcreate(&commandtabledicttype,null);
    server.orig_commands = dictcreate(&commandtabledicttype,null);
    populatecommandtable();
    server.delcommand = lookupcommandbycstring("del");
    server.multicommand = lookupcommandbycstring("multi");
    server.lpushcommand = lookupcommandbycstring("lpush");
    server.lpopcommand = lookupcommandbycstring("lpop");
    server.rpopcommand = lookupcommandbycstring("rpop");
    server.sremcommand = lookupcommandbycstring("srem");
    server.execcommand = lookupcommandbycstring("exec");
    server.expirecommand = lookupcommandbycstring("expire");
    server.pexpirecommand = lookupcommandbycstring("pexpire");
    ......
}

2、 加载并解析配置文件

在这一阶段,会对命令行传入的参数进行解析,并且调用 loadserverconfig 函数,对命令行参数和配置文件中的参数进行合并处理,然后为 redis 各功能模块的关键参数设置合适的取值,以便 server 能高效地运行。

//filename表示配置文件全路径名称;
//options表示命令行输入的配置参数,如port=4000
void loadserverconfig(char *filename, char *options) {
    sds config = sdsempty();
    char buf[config_max_line+1];

    /* 加载配置文件到内存 */
    if (filename) {
        file *fp;

        if (filename[0] == '-' && filename[1] == '
//filename表示配置文件全路径名称;
//options表示命令行输入的配置参数,如port=4000
void loadserverconfig(char *filename, char *options) {
    sds config = sdsempty();
    char buf[config_max_line+1];
    /* 加载配置文件到内存 */
    if (filename) {
        file *fp;
        if (filename[0] == '-' && filename[1] == '\0') {
            fp = stdin;
        } else {
            if ((fp = fopen(filename,"r")) == null) {
                serverlog(ll_warning,
                    "fatal error, can't open config file '%s'", filename);
                exit(1);
            }
        }
        while(fgets(buf,config_max_line+1,fp) != null)
            config = sdscat(config,buf);
        if (fp != stdin) fclose(fp);
    }
    /* append the additional options */
    if (options) {
        config = sdscat(config,"\n");
        config = sdscat(config,options);
    }
    //解析配置
    loadserverconfigfromstring(config);
    sdsfree(config);
}
') {             fp = stdin;         } else {             if ((fp = fopen(filename,"r")) == null) {                 serverlog(ll_warning,                     "fatal error, can't open config file '%s'", filename);                 exit(1);             }         }         while(fgets(buf,config_max_line+1,fp) != null)             config = sdscat(config,buf);         if (fp != stdin) fclose(fp);     }     /* append the additional options */     if (options) {         config = sdscat(config,"\n");         config = sdscat(config,options);     }     //解析配置     loadserverconfigfromstring(config);     sdsfree(config); }

3、 初始化服务器内部变量

在完成对运行参数的解析和设置后,main 函数会调用 initserver 函数,对 server 运行时的各种资源进行初始化工作。包括了 server 资源管理所需的数据结构初始化、键值对数据库初始化、server 网络框架初始化等。
最后调用 loaddatafromdisk 函数,从磁盘上加载 aof 或者是 rdb 文件,以便恢复之前的数据。

void initserver(void) {
    /* 初始化需要的各种资源 */
    server.clients = listcreate();//初始化客户端链表
    server.pid = getpid();
    server.current_client = null;
    server.clients = listcreate();
    server.clients_to_close = listcreate();
    server.slaves = listcreate();
    server.monitors = listcreate();
   server.clients_pending_write = listcreate();
   server.slaveseldb = -1; /* force to emit the first select command. */
   server.unblocked_clients = listcreate();
   server.ready_keys = listcreate();
   server.clients_waiting_acks = listcreate();
   server.get_ack_from_slaves = 0;
   server.clients_paused = 0;
   server.system_memory_size = zmalloc_get_memory_size();

   createsharedobjects();
    //调用aecreateeventloop函数创建aeeventloop结构体,并赋值给server结构的el变量
    //maxclients 变量的值大小,可以在 redis 的配置文件 redis.conf 中进行定义,默认值是 1000
    server.el = aecreateeventloop(server.maxclients+config_fdset_incr);
    if (server.el == null) {
        serverlog(ll_warning,
            "failed creating the event loop. error message: '%s'",
            strerror(errno));
        exit(1);
    }
    ......
    
    /* 创建数据库结构*/
    for (j = 0; j < server.dbnum; j++) {
        server.db[j].dict = dictcreate(&dbdicttype,null);
        server.db[j].expires = dictcreate(&keyptrdicttype,null);
        server.db[j].blocking_keys = dictcreate(&keylistdicttype,null);
        server.db[j].ready_keys = dictcreate(&objectkeypointervaluedicttype,null);
        server.db[j].watched_keys = dictcreate(&keylistdicttype,null);
        server.db[j].id = j;
        server.db[j].avg_ttl = 0;
    } 
    
    ......
        
    //创建事件循环框架
    server.el = aecreateeventloop(server.maxclients+config_fdset_incr);
    …
    //开始监听设置的网络端口
    if (server.port != 0 &&
            listentoport(server.port,server.ipfd,&server.ipfd_count) == c_err)
            exit(1);
    …
    //为server后台任务创建定时事件
    if (aecreatetimeevent(server.el, 1, servercron, null, null) == ae_err) {
            serverpanic("can't create event loop timers.");
            exit(1);
    }
    …
    //为每一个监听的ip设置连接事件的处理函数accepttcphandler
    for (j = 0; j < server.ipfd_count; j++) {
            if (aecreatefileevent(server.el, server.ipfd[j], ae_readable,
                accepttcphandler,null) == ae_err)
           { … }
    }
}

4、执行事件驱动框架

事件驱动框架是 redis server 运行的核心。该框架一旦启动后,就会一直循环执行,每次循环会处理一批触发的网络读写事件。main 函数直接调用事件框架的主体函数 aemain(在ae.c文件中)后,就进入事件处理循环了。当然,在进入事件驱动循环前,main 函数会分别调用 aesetbeforesleepproc 和 aesetaftersleepproc 两个函数,来设置每次进入事件循环前 server 需要执行的操作,以及每次事件循环结束后 server 需要执行的操作。下面代码显示了这部分的执行逻辑,你可以看下。

aesetbeforesleepproc(server.el,beforesleep);
aesetaftersleepproc(server.el,aftersleep);
aemain(server.el);
aedeleteeventloop(server.el);

到此这篇关于redis server启动过程的详细步骤的文章就介绍到这了,更多相关redis server启动过程 内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐