在线免费国产视频,亚洲无码成人免费在线,又黄又爽又无遮挡国产,日韩爆乳av少妇无码,国产福利精品98视频一区二区

【Redis源碼】Redis 啟動(dòng)過(guò)程分析

pic

簡(jiǎn)介

由于本人目前是華為FusionInsight HD 中Redis組件的Owner,所以要對Redis進(jìn)行深入的了解,這對于C語(yǔ)言水平不咋地的我來(lái)講還是有點(diǎn)難度的,于是我決定先從Redis的啟動(dòng)開(kāi)始看,了解其基本原理。

配置初始化

Redis服務(wù)啟動(dòng)首先做的第一步就是初始化配置。Redis初始化配置主要包括初始化命令表和加載配置兩部分。

初始化ACL 權限信息

主要是通過(guò)加載redis.conf配置文件里面的配置信息,用于控制登錄用戶(hù)執行命令的權限,仔細詳見(jiàn):Redis 6 ACL源碼詳解

初始化命令表

在函數populateCommandTable將redisCommandTable中的命令加載到字典server.commands當中,用于執行命令的時(shí)候使用,并且對于比較常用的命令賦予成員屬性,減少查找。redisCommandTable的結構如下:

struct redisCommand redisCommandTable[] = {
    {"module",moduleCommand,-2,
     "admin no-script",
     0,NULL,0,0,0,0,0,0},

    {"get",getCommand,2,
     "read-only fast @string",
     0,NULL,1,1,1,0,0,0},

    /* Note that we can't flag set as fast, since it may perform an
     * implicit DEL of a large key. */
    {"set",setCommand,-3,
     "write use-memory @string",
     0,NULL,1,1,1,0,0,0},

    {"setnx",setnxCommand,3,
     "write use-memory fast @string",
     0,NULL,1,1,1,0,0,0},
}

  • name:命令的名稱(chēng)
  • proc:命令對應的函數名。redis-server處理命令時(shí)要執行的函數
  • arity:命令的參數個(gè)數,如果是-N代表大于等于N
  • sflags:命令標志,標識命令的類(lèi)型(read/write/admin...)
  • flags:位掩碼,由Redis根據sflags計算
  • get_keys_proc:可選函數,當下面三個(gè)項不能指定哪些參數是key時(shí)使用
  • first_key_index:第一個(gè)是key的參數
  • last_key_index:最后一個(gè)是key的參數
  • key_step:key的“步長(cháng)”,比如MSET的key_step是2,因為它的參數是key,val,key,val這樣的形式
  • microseconds:執行命令所需要的微秒數
  • calls:該命令被調用總次數

防止查找的命令如下:


    server.delCommand = lookupCommandByCString("del");
    server.multiCommand = lookupCommandByCString("multi");
    server.lpushCommand = lookupCommandByCString("lpush");
    server.lpopCommand = lookupCommandByCString("lpop");
    server.rpopCommand = lookupCommandByCString("rpop");
    server.zpopminCommand = lookupCommandByCString("zpopmin");
    server.zpopmaxCommand = lookupCommandByCString("zpopmax");
    server.sremCommand = lookupCommandByCString("srem");
    server.execCommand = lookupCommandByCString("exec");
    server.expireCommand = lookupCommandByCString("expire");
    server.pexpireCommand = lookupCommandByCString("pexpire");
    server.xclaimCommand = lookupCommandByCString("xclaim");
    server.xgroupCommand = lookupCommandByCString("xgroup");
    server.rpoplpushCommand = lookupCommandByCString("rpoplpush");

初始化哨兵模式

當開(kāi)啟哨兵模式時(shí),redis啟動(dòng)就會(huì )初始化哨兵模式相關(guān)參數等。初始化哨兵模式主要是函數initSentinelConfig() 和initSentinel()兩部分。

  • initSentinelConfig()主要是初始化哨兵模式的端口等。
  • initSentinel()主要刪除redis實(shí)例基本的命令,初始化哨兵的相關(guān)命令。
struct redisCommand sentinelcmds[] = { 
      {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0}, 
      {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0},   
      {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0},   
      {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, 
      {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0},  
      {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0},  
      {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0},  
      {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0}, 
      {"role",sentinelRoleCommand,1,"ok-loading",0,NULL,0,0,0,0,0},
      {"client",clientCommand,-2,"read-only no-script",0,NULL,0,0,0,0,0}, 
      {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0}, 
      {"auth",authCommand,2,"no-auth no-script ok-loading ok-stale fast",0,NULL,0,0,0,0,0},
      {"hello",helloCommand,-2,"no-auth no-script fast",0,NULL,0,0,0,0,0}  
}

檢查RDB/AOF文件

啟動(dòng)前會(huì )會(huì )通過(guò)函數redis_check_rdb_main()/redis_check_aof_main()檢查RDB/AOF文件的完整性。

命令行參數處理

如果是簡(jiǎn)單的參數例如-v或--version、-h或--help,就會(huì )直接調用相應的方法,打印信息。如果是使用其他配置文件,則修改server.exec_argv。對于其他信息,會(huì )將他們轉換成字符串,然后添加進(jìn)配置文件,例如“--port 6380”就會(huì )被轉換成“port 6380\n”加進(jìn)配置文件。這時(shí),redis就會(huì )調用loadServerConfig()函數來(lái)加載配置文件,這個(gè)過(guò)程會(huì )覆蓋掉前面初始化默認配置文件的變量的值。

初始化Redis

初始化 Shared object

createSharedObjects()函數會(huì )創(chuàng )建一些shared對象保存在全局的shared變量中,對于不同的命令,可能會(huì )有相同的返回值(比如報錯)。這樣在返回時(shí)就不必每次都去新增對象了,保存到內存中了。這個(gè)設計就是以Redis啟動(dòng)時(shí)多消耗一些時(shí)間為代價(jià),換取運行的更小的延遲。

初始化監聽(tīng)事件

initServer()函數調用aeCreateEventLoop()函數(ae.c文件)來(lái)增加循環(huán)事件,并將結果返回給server的el成員。Redis使用不同的函數來(lái)兼容各個(gè)平臺,在Linux平臺使用epoll,在BSD使用kqueue,都不是的話(huà),最終會(huì )使用select。Redis輪詢(xún)新的連接以及I/O事件,有新的事件到來(lái)時(shí)就會(huì )及時(shí)作出響應。

監聽(tīng)端口

anetUnixServer()函數中使用函數anetListen監聽(tīng)端口。

初始化LRU鍵池

evictionPoolAlloc函數用于初始化LRU的鍵池,Redis的key過(guò)期策略是近似LRU算法

void evictionPoolAlloc(void) {
    struct evictionPoolEntry *ep;
    int j;

    ep = zmalloc(sizeof(*ep)*EVPOOL_SIZE);
    for (j = 0; j < EVPOOL_SIZE; j++) {
        ep[j].idle = 0;
        ep[j].key = NULL;
        ep[j].cached = sdsnewlen(NULL,EVPOOL_CACHED_SDS_SIZE);
        ep[j].dbid = 0;
    }
    EvictionPoolLRU = ep;
}


定時(shí)任務(wù)

Redis會(huì )執行aeCreateTimeEvent()(在ae.c文件中)函數,用來(lái)新建一個(gè)循環(huán)執行serverCron()函數的事件。serverCron()默認每100毫秒執行一次。

 /* Create the timer callback, this is our way to process many background
  * operations incrementally, like clients timeout, eviction of unaccessed
  * expired keys and so forth. */
if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
    serverPanic("Can't create event loop timers.");
    exit(1);
}

主循環(huán)事件

程序調用aeMain()函數,進(jìn)入主循環(huán),這時(shí)其他的一些循環(huán)事件也會(huì )分別被調用。

void aeMain(aeEventLoop *eventLoop) {
    eventLoop->stop = 0;
    while (!eventLoop->stop) {
        if (eventLoop->beforesleep != NULL)
            eventLoop->beforesleep(eventLoop);
        aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
    }
}

到此Redis就啟動(dòng)完成了。



標 題:《【Redis源碼】Redis 啟動(dòng)過(guò)程分析
作 者:zeekling
提 示:轉載請注明文章轉載自個(gè)人博客:浪浪山旁那個(gè)村

    評論
    0 評論
avatar

取消
在线免费国产视频,亚洲无码成人免费在线,又黄又爽又无遮挡国产,日韩爆乳av少妇无码,国产福利精品98视频一区二区