您好,欢迎访问一九零五行业门户网

Redis源码解析1

前言 redis(remotedictionaryserver)是一个由salvatore sanfilippo写的key-value存储系统。 它有以下特点: 总体结构 redis是一个单线程的服务器(除了写磁盘会开子进程,vm管理会开线程,先忽略这两块) 所以,它的服务器启动流程非常清晰,看下图,不再
前言
redis(remote dictionary server)是一个由salvatore sanfilippo写的key-value存储系统。
它有以下特点:
总体结构redis是一个单线程的服务器(除了写磁盘会开子进程,vm管理会开线程,先忽略这两块)
所以,它的服务器启动流程非常清晰,看下图,不再赘述
事件循环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三个接口函数进行处理
这三个接口函数又会映射到具体的某一种网络模型中,而这是在编译期确定下来的
具体如下图所示:
添加删除事件,由
aecreatefileevent、aedeletefileevent函数完成,其函数分发流程如下图:
2. 服务端socket建立流程1. 在服务器初始化时,建立侦听socket,并绑定ip、port
    支持 tcp连接 与本机的unixsocket连接
1if (server.port != 0) {2server.ipfd = anettcpserver(server.neterr,server.port,server.bindaddr);3 ... ... 4 }5if (server.unixsocket != null) {server.sofd = anetunixserver(server.neterr,server.unixsocket,server.unixsocketperm);8 ... ...9}
2. 侦听socket绑定到事件句柄
1if (server.ipfd > 0 && aecreatefileevent(server.el,server.ipfd,ae_readable,);3if (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) { 2int cport, cfd; 3char cip[128]; 4 redis_notused(el); 5 redis_notused(mask); 6 redis_notused(privdata);cfd = anettcpaccept(server.neterr, fd, cip, &cport);10if (cfd == ae_err) {, server.neterr);12return;13 }, cip, cport);}
acceptcommonhandler中做的事很简单,调用 createclient函数,创建新的redisclient对象
acceptcommonhandler(int fd) {2redisclient *c;3if ((c = createclient(fd)) == null) {);;7 }8 ... ...9 }
在 createclient函数中,将新连接绑定到事件循环中
1 redisclient *createclient(int fd) { 2redisclient *c = zmalloc(sizeof(redisclient)); 3c->bufpos = 0; 4 5 anetnonblock(null,fd); 6 anettcpnodelay(null,fd); 7if (aecreatefileevent(server.el,fd,ae_readable, {10 close(fd);11 zfree(c);12return null;13}
当连接上有数据到达时,便会触发 readqueryfromclient函数,进行实际的网络数据读取与处理
3. timer事件redis将所有timer绑定到事件循环中进行处理
通过函数 aecreatetimeevent 创建新的timer事件
每一帧事件循环中,通过processtimeevents函数进行处理
其它类似信息

推荐信息