近期學習了redis底層架構,好多東西之前都沒聽說過,算是大開眼界了。
先梳理下redis正常的通訊流程吧
首先伺服器啟動都有主函數main,這個main函數就在redis.c裡
首先是initserverconfig(),在這裡初始化了redisserver基本的配置資訊,
接着調用loadServerConfig(char *filename) 對 server 全局變量重新初始化。
然後是調用daemonize(),實作守護程序,脫離了控制台,是這個程序
成為獨立的首領程序
接下來是initServer(),這個過程很重要,完成了事件驅動的注冊和一些
回調函數的綁定,回頭仔細說這個函數裡面的功能
初始化伺服器過後aeSetBeforeSleepProc(),設定了伺服器休眠之前會
調用beforeSleep函數
然後進入主要的事件輪詢函數 aeMain(server.el),在這裡完成事件的派發
最後事件輪詢過後我們調用aeDeleteEventLoop,釋放之前開辟的記憶體,
結束程序。
中間略去一些瑣碎的過程,我們總結一下
initserverconfig() ----> loadServerConfig------> daemonize()
initServer()-----> aeSetBeforeSleepProc()------>aeMain()----->
aeDeleteEventLoop
接下來詳細說一下每一個步驟都做了什麼。
看一下main()函數
int main(int argc, char **argv) {
//設定時間,一般都是設定事件poll等待多長時間傳回
struct timeval tv;
/* We need to initialize our libraries, and the server configuration. */
#ifdef INIT_SETPROCTITLE_REPLACEMENT
//程序重命名
spt_init(argc, argv);
#endif
//好像是更改字元編碼
setlocale(LC_COLLATE,"");
//設定多線程安全模式
zmalloc_enable_thread_safeness();
//注冊記憶體使用過量報錯的函數
zmalloc_set_oom_handler(redisOutOfMemoryHandler);
srand(time(NULL)^getpid());
gettimeofday(&tv,NULL);
//哈希種子
dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid());
//伺服器的啟動模式:單機模式、Cluster模式、sentinel模式
server.sentinel_mode = checkForSentinelMode(argc,argv);
initServerConfig();
loadServerConfig(configfile,options);
。。。
//建立守護程序
if (server.daemonize) daemonize();
//初始化伺服器
initServer();
//設定伺服器sleep之前的函數調用
aeSetBeforeSleepProc(server.el,beforeSleep);
//主函數事件驅動
aeMain(server.el);
//删除事件循環的結構,釋放空間
aeDeleteEventLoop(server.el);
return 0;
}