Redis 网络部分代码-Redis Server端
参考http://pauladamsmith.com/articles/redis-under-the-hood.html#event-loop-setup
http://www.yiihsia.com/tag/redis/
Redis Server端
- initServerConfig()首先初始化配置信息
- 这个函数里面会设置server的相关信息如:port、dbnum、Command table等
- 先创建Command命令的字典server.commands = dictCreate(&commandTableDictType,NULL)
- populateCommandTable()就是将常用的命令加入Command字典
- loadServerConfig根据命令行参数设置server的配置文件;并且导入配置文件;根据配置文件设置server的port等信息
redis.c 的main函数里面的initServer会执行如下操作
- 如果需要配置文件里面配置了后台运行程序,那么就fork一个子进程;然后父进程exit;让子进程运行程序
- initServer
- 忽略SIGPIPE写端关闭信号 和SIGHUP终端退出信号
- 生成client 、slaves 以及monitors等的list
- 创建 sharedObjectsStruct 其中包括robj *crlf, *ok, *err,
- aeCreateEventLoop创建aeEventLoop *eventLoop,主要是做一些初始化工作并create一个epollfd
- 这个函数里面会调用aeApiCreate来真正的create一个epoll的描述符state->epfd=epoll_create(1024)
- 当port为合法的时候就会去调用anetTcpServer;这个函数会anetCreateSocket用于监听客户端请求的socketfd;然后anetListen会bind 还会listen开始监听客户端请求
- anetCreateSocket(err,AF_INET)这个函数里会创建一个socket然后会设置socket的相关属性:如设置setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));这样如果一个服务断掉之后不用等待很久就可以立即使用这个端口
- 接下来会dictCreate创建dict(此处略去一万字)
- aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL)如果有超时时间发生会去调用serverCron这个回调函数
- aeCreateTimeEvent里面会设置超时时间;将其添加到timeEventHead里面并作为list的head;并设置这个event的回调函数是serverCron
- 接下来应该看的就是serverCron干了些什么
- 打印非空db的一些信息,log功能
- 如果当前没有后台运行dump数据保存到文件的进程,则可以根据内存使用情况重新调整hashTables大小
- 日志输出一些client的连接信息
- 检测idle的client 连接,关闭idle连接
- 判断是否有正在进行dump数据到文件的后台进程;如果有判断是否已经结束,进行结束后的一些工作(这个跟replication有关,后续详细说明);没有则判断是否需要启动新的进程dump数据到文件
- 处理expired的key
- vmSwapOut功能,如果启动了vm选项,则判断是否超过vmMaxMemory,如果超过进行value的swap
- 判断如果server是slave,则连接master,发送sync命令,和master同步数据
- aeCreateFileEvent他的回调函数是acceptTcpHandler;aeCreateFileEvent这里面主要是将要监听的sockfd添加到epoll的事件队列里面epoll_ctl(state->epfd,op,fd,&ee)
- acceptTcpHandler至于他的回调函数要干的事情就是anetTcpAccept接受连接;将与客户端已经建立连接的cfd加入到epoll事件队列并调用它的回调函数
- acceptCommonHandler这个函数就是将与客户端已经建立连接的cfd加入到epoll事件队列 他会调用createClient:他会设置cfd为非阻塞并且为TcpNoDela然后aeCreateFileEvent将cfd加入到epoll事件队列里面;aeCreateFileEvent的回调函数是readQueryFromClient;处理客户端的Query
- createClient(fd)设置fd的属性并且调用aeCreateFileEvent(server.el,fd,AE_READABLE, readQueryFromClient, c) 将fd加入到epoll队列里面;设置Client的若干属性;将该Client加入.server.client的尾部;他的回调函数是readQueryFromClient
- readQueryFromClient的作用是读入客户端输入的数据,并调用processInputBuffer解析并处理用户的请求
- createClient(fd)设置fd的属性并且调用aeCreateFileEvent(server.el,fd,AE_READABLE, readQueryFromClient, c) 将fd加入到epoll队列里面;设置Client的若干属性;将该Client加入.server.client的尾部;他的回调函数是readQueryFromClient
- acceptCommonHandler这个函数就是将与客户端已经建立连接的cfd加入到epoll事件队列 他会调用createClient:他会设置cfd为非阻塞并且为TcpNoDela然后aeCreateFileEvent将cfd加入到epoll事件队列里面;aeCreateFileEvent的回调函数是readQueryFromClient;处理客户端的Query
- acceptTcpHandler至于他的回调函数要干的事情就是anetTcpAccept接受连接;将与客户端已经建立连接的cfd加入到epoll事件队列并调用它的回调函数
- 如果vm是可用的那么执行 vmInit()(此处略去一万字)
- aeSetBeforeSleepProc(server.el,beforeSleep):当 Redis进入事件驱动的main循环之前即获取准备就绪事件之前需要完成的工作:这个他会去试着为没有被阻塞的客户处理他们等待在buffer中的命令;并且会调用flushAppendOnlyFile 写AOF缓冲区在硬盘上
- 如果vm是可用的那将已经IO准备就绪的进行swap
- 执行非阻塞Client命令
- 写AOF到disk上
- aeMain(server.el)在每次进行aeProcessEvent之前都需要调用beforeSleep:
- aeProcessEvent获得准备就绪的事件;并且调用它的回调函数.检查超时事件(线性扫描超市队列)并执行超时事件的回调函数
- aeDeleteEventLoop(server.el)
浙公网安备 33010602011771号