Redis server启动后会做哪些操作?
Redis 是典型的 Client-Server 架构,一旦 Redis 实例开始运行,Redis server 也就会启动,而 main 函数其实也会负责 Redis server 的启动运行。
Redis 针对以下三个问题的实现思路:
Redis server 启动后具体会做哪些初始化操作?
Redis server 初始化时有哪些要害配置项?
Redis server 如何开始解决客户端申请?
(1) Redis Server 启动
源码地址 https://github.com/redis/redi...
//file: src/server.c// #L5297 5297行int main(int argc, char **argv) { // 省略局部代码... // 1. 启动RedisServer时 初始化配置及资源 initServer(); // 2. 循环解决申请及事件,直到服务器敞开为止 aeMain(server.el); }
(1.1) 启动RedisServer初始化配置及资源
在 initServer 这个函数内,Redis 做了这么三件重要的事件。
1、创立一个epoll对象
2、对配置的监听端口进行listen
3、把 listen socket 让 epoll 给治理起来
void initServer(void) { // 1. 创立epoll server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR); // 2. 监听端口 listenToPort(server.port,server.ipfd,&server.ipfd_count) // 3. 注册accept事件处理器 (只是注册 前面会用到) for (j = 0; j < server.ipfd_count; j++) { aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler,NULL) }}
(1.2) 循环解决申请
// file: src/ae.c /** * 循环处理事件 * * @param *eventLoop */ void aeMain(aeEventLoop *eventLoop) { eventLoop->stop = 0; // 循环处理事件 while (!eventLoop->stop) { // 处理事件 aeProcessEvents(eventLoop, AE_ALL_EVENTS| AE_CALL_BEFORE_SLEEP| AE_CALL_AFTER_SLEEP); }}
// file: src/ae.c /** * 处理事件 * * @param *eventLoop * @param flags */ int aeProcessEvents(aeEventLoop *eventLoop, int flags){ // 省略局部细节... // 调用多路复用API获取就绪事件 numevents = aeApiPoll(eventLoop, tvp); // 解决写事件 fe->wfileProc(eventLoop,fd,fe->clientData,mask); // 解决读事件 fe->rfileProc(eventLoop,fd,fe->clientData,mask); }
其实整个 Redis 的工作过程,就只须要了解分明 main 函数中调用的 initServer
和 aeMain
这两个函数就足够了。
(2) RedisServer网络申请解决流程
(2.1) 绑定地址并监听套接字(bind listen)
// file: src/server.c // 监听端口/** * @param port * @param *fds * @param *count */int listenToPort(int port, int *fds, int *count) { // ... for (j = 0; j < server.bindaddr_count || j == 0; j++) { // ... 省略 绑定IPV6 IPV4的细节 anetTcp6Server anetTcpServer // 绑定 fds[*count] = anetTcpServer(server.neterr,port,NULL, server.tcp_backlog); // ... } return C_OK;}
Redis 是反对开启多个端口的,所以在 listenToPort 中咱们看到是启用一个循环来调用 anetTcpServer。
在 anetTcpServer 中,逐渐会开展调用,直到执行到 bind 和 listen 零碎调用。
// file: src/anet.c /** * @param *err * @param port * @param *bindaddr * @param backlog */int anetTcpServer(char *err, int port, char *bindaddr, int backlog){ return _anetTcpServer(err, port, bindaddr, AF_INET, backlog);}/** * @param *err * @param port * @param *bindaddr * @param af * @param backlog */static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backlog){ int s = -1, rv; char _port[6]; /* strlen("65535") */ struct addrinfo hints, *servinfo, *p; // 创立套接字 s = socket(p->ai_family,p->ai_socktype,p->ai_protocol) // 设置端口重用 anetSetReuseAddr(err,s) // 监听 anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog)
/** * 监听 * * @param *err * @param s 对应创立的套接字fd * @param *sa socket地址信息 (协定 地址) * @param len * @param backlog */static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog) { // 绑定ip端口 bind(s,sa,len) // 监听套接字 listen(s, backlog) return ANET_OK;}
(2.2) 和客户端建设连贯(accept)
// file: src/networking.c /** * 接管tcp处理器 * * @param *el * @param fd * @param *privdata * @param mask */void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { // ... // 接管tcp申请 cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport); // ... // 接管通用解决 acceptCommonHandler(connCreateAcceptedSocket(cfd),0,cip);}
(2.2.1) 接管tcp申请-anetTcpAccept
// file: src/anet.c /** * 接管tcp申请 * * @param *err * @param s fd * @param *ip * @param ip_len * @param *port */int anetTcpAccept(char *err, int s, char *ip, size_t ip_len, int *port) { int fd; struct sockaddr_storage sa; // 套接字地址存储构造体 socklen_t salen = sizeof(sa); // 接管申请 fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen) // ... return fd;}
// file: src/anet.c /** * @param *err * @param s * @param *sa * @param *len */ static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) { int fd; while(1) { // 接管socket数据 // fd是socket返回的socket,指向的定义的SOCKADDR_IN 构造体指针,指针的大小 fd = accept(s,sa,len); // ... break; } return fd;}
参考资料
Redis高性能IO模型
https://weikeqin.com/2022/01/...
Redis源码分析与实战 学习笔记 Day8 08 | Redis server启动后会做哪些操作?
https://time.geekbang.org/col...