近期学习了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;
}