server工作流程
当执行./redis-server后,redis数据库的server端就会启动。
然后就会执行redis.c中的main()函数
其中main()函数中的工作可以主要分为以下几个部分:
- 1、初始化server端的配置信息- - -initServerConfig()
- 2、解析运行时的命令参数,并根据参数进行处理,eg:./redis-server - -help
- 3、如果设置了daemonize参数,则将server设为deamon进程- - -daemonize()
- 4、启动server- - -initServer()
- 5、设置周期性处理函数beforeSleep()
- 6、开始工作- - -aeMain()
1、initServerConfig()
初始化server端的配置信息,保存在服务器实例server中,包括监听端口、DB数、命令表等信息。
2、daemonize()
将进程设为守护进程。
守护进程的相关知识之前在linux进程基础 中已经进行了简单介绍。
void daemonize(void) {
int fd;
if (fork() != 0) exit(0); /* parent exits */
setsid(); /* create a new session */
if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) close(fd);
}
}
3、initServer()
这个函数中完成了非常多的任务,包括设置信号处理函数、 创建clients队列、slaves队列、创建数据库、创建共享对象等。
除此之外最重要的两个任务是创建监听socket并监听client、以及创建周期性处理事件。
我们知道,任何一个服务器的的事件都可以分为IO读写事件和时间处理事件,redis同样如此。
1)IO读写事件,包括监听客户端的连接以及与客户端进行数据交互等
2)时间处理事件,在设定的时间处理相关事件,包括周期性刷新数据库等。
这两类事件都是通过server.el这个变量来保存的。
3.1、IO读写事件
首先redis会为服务器创建一个监听fd,来监听来自客户端的连接,主要会调用到以下两个函数
listenToPort(server.port,server.ipfd,&server.ipfd_count);
aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler,NULL);
最后将该事件加入到server.el结构中
- listenToPort:根据传入的port创建监听描述符,同时调用fcntl()将fd设为非阻塞的,然后调用bind()、listen()函数。注意redis会分别根据IPv4、IPv6两种地址分别创建一个socket
- aeCreateFileEvent:创建读写事件。对于监听描述符而言,只需要创建一个读事件监听来自client的连接即可。注意,监听描述符的回调函数为acceptTcpHandler
3.2、时间处理事件
对于server端,redis会周期性的执行serverCron()来完成一些处理,因此将这个事件也加入到server.el结构中
aeCreateTimeEvent(server.el, 1, serverCron,