直奔主題,當啟動Redis的時候,Redis執行了哪些操作?
假設Redis安裝在了/usr/local/目錄下,那麼啟動Redis是通過執行/usr/local/bin/redis-server -c xxx.conf
的方式執行。
redis-server是一個通過編譯server.c檔案生成的程式,因此想了解redis是怎麼啟動的,應該從server.c/main函式入手。
具體程式碼可見:server.c
閱讀main函式,可以知道,整個啟動大致分為五個步驟:初始化server結構體、從配置資料夾在載入引數、初始化伺服器、載入持久化檔案、開始監聽事件。
redis用redisServer結構體來儲存伺服器的屬性和資訊,在server.c檔案中,定義了一個全域性伺服器變數:
struct redisServer server;
複製程式碼
另外,還定義了一個redis命令表,表裡包含了命令以及命令對應的函式:
struct redisCommand redisCommandTable;
複製程式碼
在main函式裡,redis先呼叫initServerConfig函式初始化server結構體。
初始化server結構體
main函式呼叫initServerConfig函式為server的屬性設定一些預設值,比如:
伺服器的執行ID
redis使用的預設埠號,是在server.h定義的CONFIG_DEFAULT_SERVER_PORT = 6379
LRU時鐘
主從備份相關引數
命令表
慢查詢引數
接著會儲存當前執行的路徑和引數,為之後的伺服器重啟使用相同的引數做準備:
server.executable = getAbsolutePath(argv[0]);
server.exec_argv = zmalloc(sizeof(char*)*(argc+1));
server.exec_argv[argc] = NULL;
for (j = 0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]);
複製程式碼
從配置檔案載入引數
redis的啟動引數有很多,其中一個是指定配置檔案。初始化server結構體後,大部分的屬性都會設定到結構體了,但是有部分引數可以通過配置檔案重現設定,比如redis的埠號。
初始化完server結構體後,函式會判斷是否有指定配置檔案,如果有,呼叫loadServerConfig函式,從配置檔案載入相關的配置,把配置檔案對應的引數設定到server結構體。
讀取配置檔案載入引數的流程如下:
- 1、分割引數項
- 2、跳過空行和註釋行
- 3、逐項檢查,如果引數合法,設定配置值到server屬性
至此,redisServer大部分屬性已經設定好,server還有很多資料結構沒有初始化,initServer函式就繼續接下來的初始化工作。
初始化伺服器資料結構
main函式會呼叫initServer函式初始化伺服器狀態,比如:
程式ID
客戶端連結串列
從庫連結串列
為常用值建立共享物件
初始化事件迴圈器
開啟TCP開始監聽套接字
建立伺服器的資料庫,並初始化內部狀態
為serverCron定時器建立時間事件定時器
如果開啟了AOF,開啟AOF檔案,之後恢復資料時需要用到
初始化慢查詢日誌模組
初始化後臺IO模組
載入持久化檔案,還原資料庫
初始化完伺服器的狀態後,伺服器已經處於一個可啟動狀態,因為redis有持久化特性,伺服器還需要載入相應的檔案來還原之前資料庫的資料。 判斷Redis當前開啟了哪種模式,如果是AOF,則通過AOF還原資料庫的資料,否則,載入RDB檔案,通過RDB檔案還原資料庫的資料。
開始監聽事件
main函式會設定beforeSleep和afterSleep回撥函式,然後呼叫aeMain函式啟動事件迴圈器,開始監聽事件。aeMain函式是一個死迴圈,不斷的監聽新請求的到來。
/*
* server啟動後,main函式的最終步驟,不斷地呼叫beforesleep和aeProcessEvents
*/
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);
}
}
複製程式碼
綜上所述,伺服器整個啟動簡化流程圖如下:
原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
更多精彩內容,請關注個人公眾號。