欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

Redis源码解析1

程序员文章站 2024-02-16 11:12:10
...

前言 Redis(REmoteDIctionaryServer)是一个由Salvatore Sanfilippo写的key-value存储系统。 它有以下特点: 总体结构 Redis是一个单线程的服务器(除了写磁盘会开子进程,VM管理会开线程,先忽略这两块) 所以,它的服务器启动流程非常清晰,看下图,不再

前言

Redis(REmote DIctionary Server)是一个由Salvatore Sanfilippo写的key-value存储系统。
它有以下特点:

总体结构

Redis是一个单线程的服务器(除了写磁盘会开子进程,VM管理会开线程,先忽略这两块)
所以,它的服务器启动流程非常清晰,看下图,不再赘述

Redis源码解析1

事件循环 1. 数据结构

通过 aeEventLoop 结构来表示一个事件框架,美国服务器,分析如下:

1 typedef struct aeEventLoop { timeEventNextId; aeFileEvent events[AE_SETSIZE]; aeFiredEvent fired[AE_SETSIZE]; aeTimeEvent *timeEventHead; stop; aeBeforeSleepProc *beforesleep; 10 } aeEventLoop;

2. 事件函数分发流程

redis支持 epoll、kqueue、select 三种网络模型

网络框架的代码实现主要在以下几个文件中:

ae.c / ae.h // 网络框架
ae_epoll.c // epoll模型的实现
ae_kqueue.c // kqueue模型的实现
ae_select.c // select模型的实现

程序选择哪一种,网站空间,是在编译期确定的

1 1 file ae.c #ifdef HAVE_EPOLL #ifdef HAVE_KQUEUE #include

框架函数非常简单,从初始化到结束,主要的函数就3个
aeCreateEventLoop、aeMain、aeDeleteEventLoop
其中,aeMain是事件循环的主体函数,它又会调用 aeProcessEvents函数

三个主体函数会调用 aeApiCreate、aeApiPool、aeApiFree三个接口函数进行处理
这三个接口函数又会映射到具体的某一种网络模型中,而这是在编译期确定下来的

具体如下图所示:

Redis源码解析1

添加删除事件,由
aeCreateFileEvent、aeDeleteFileEvent函数完成,其函数分发流程如下图:

Redis源码解析1

2. 服务端socket建立流程

1. 在服务器初始化时,建立侦听socket,并绑定IP、Port
支持 TCP连接 与本机的unixSocket连接

1 if (server.port != 0) { 2 server.ipfd = anetTcpServer(server.neterr,server.port,server.bindaddr); 3 ... ... 4 } 5 if (server.unixsocket != NULL) { server.sofd = anetUnixServer(server.neterr,server.unixsocket,server.unixsocketperm); 8 ... ... 9 }

2. 侦听socket绑定到事件句柄

1 if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE, ); 3 if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE, );

其中“acceptTcpHandler”、“acceptUnixHandler” 是事件回调函数
当新连接到达时,会触发进入这两个函数

3. 再来看看 accept***Handler 里做了什么

1 void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { 2 int cport, cfd; 3 char cip[128]; 4 REDIS_NOTUSED(el); 5 REDIS_NOTUSED(mask); 6 REDIS_NOTUSED(privdata); cfd = anetTcpAccept(server.neterr, fd, cip, &cport); 10 if (cfd == AE_ERR) { , server.neterr); 12 return; 13 } , cip, cport); }

acceptCommonHandler中做的事很简单,调用 CreateClient函数,创建新的redisClient对象

acceptCommonHandler(int fd) { 2 redisClient *c; 3 if ((c = createClient(fd)) == NULL) { ); ; 7 } 8 ... ... 9 }

在 createClient函数中,将新连接绑定到事件循环中

1 redisClient *createClient(int fd) { 2 redisClient *c = zmalloc(sizeof(redisClient)); 3 c->bufpos = 0; 4 5 anetNonBlock(NULL,fd); 6 anetTcpNoDelay(NULL,fd); 7 if (aeCreateFileEvent(server.el,fd,AE_READABLE, { 10 close(fd); 11 zfree(c); 12 return NULL; 13 }

当连接上有数据到达时,便会触发 readQueryFromClient函数,进行实际的网络数据读取与处理

3. Timer事件

Redis将所有Timer绑定到事件循环中进行处理
通过函数 aeCreateTimeEvent 创建新的Timer事件
每一帧事件循环中,通过processTimeEvents函数进行处理