本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
Redis Server启动过程的详细步骤
phpren · 334浏览 · 发布于2022-02-08 +关注

本文主要介绍了Redis Server启动过程的详细步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文基于社区版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] == '\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);
}


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);


 


相关推荐

使用SELECT语句检索数据

奔跑的男人 · 810浏览 · 2019-06-03 09:33:43
部署MySQL延迟从库的几个好处

吴振华 · 692浏览 · 2019-05-14 21:57:51
MongoDB凭什么跻身数据库排行前五?

iamitnan · 732浏览 · 2019-06-18 10:04:56
Oracle开启和关闭的几种模式

qq2360248666 · 761浏览 · 2019-06-04 10:18:47
加载中

0评论

评论
我从小喜欢编程,一直在学习中,从未停止,未来也是如此!
小鸟云服务器
扫码进入手机网页