(转)redis源代码分析 – event library
每个cs程序尤其是高并发的网络服务端程序都有自己的网络异步事件处理库,redis不例外。
事件库仅仅包括ae.c、ae.h,还有3个不同的多路复用(本文仅描述epoll)的wrapper文件,事件库封装了框架调用的主循环函数,暴露了时间、文件事件注册和销毁函数,典型的依赖反转模式。
网络操作都在networking.c里,封装了常见的socket操作。
我们从redis启动的main函数开始,从用户发出连接键入命令开始遍历网络事件库所涉及的函数,unix套接口相关函数不表。
首先对几个最常用对象进行解释。

//redis启动的时候(init_server())会创建的一个全局使用的事件循环结构
typedef struct aeEventLoop {
int maxfd; //仅仅是select 使用
long long timeEventNextId;
aeFileEvent events[AE_SETSIZE]; //用于保存epoll需要关注的文件事件的fd、触发条件、注册函数。
aeFiredEvent fired[AE_SETSIZE]; //epoll_wait之后获得可读或者可写的fd数组,通过aeFiredEvent->fd再定位到events。
aeTimeEvent *timeEventHead; //以链表形式保存多个时间事件,每隔一段时间机会触发注册的函数。
int stop;
void *apidata; //每种多路复用方法的使用的私有变量,例如epoll就是epfd和一个事件数组;而select是保存rset、wset。
aeBeforeSleepProc *beforesleep; // sleep之前调用的函数,有些事情是每次循环必须做的,并非文件、时间事件。
} aeEventLoop; //文件可读写事件
typedef struct aeFileEvent {
int mask; //触发条件:读、写
aeFileProc *rfileProc; //当fd可读时执行的事件(accept,read)
aeFileProc *wfileProc; //当fd可写时执行的事件(write)
void *clientData; //caller 传入的数据指针
} aeFileEvent; //超时时间事件
typedef struct aeTimeEvent {
long long id; /* time event identifier. */
long when_sec; /* seconds */
long when_ms; /* milliseconds */
aeTimeProc *timeProc; //当出现超时的时候所执行的事件
aeEventFinalizerProc *finalizerProc;
void *clientData; //caller传入的数据指针
struct aeTimeEvent *next; //单链表指向下一个时间事件
} aeTimeEvent; //从epoll_wait或者select返回的,已经触发的文件事件
typedef struct aeFiredEvent {
int fd;
int mask;
} aeFiredEvent;
我们来模拟redis server 启动和用户键入命令的过程,先上图。

//好吧,从main函数开始吧。 // src/redis.c 853
server.el = aeCreateEventLoop(); //创建一个aeEventLoop结构体,成员apidata指向一个aeApiState对象,如果使用epoll,fd是由epoll_create创建的全局epoll fd ,events[] 用于保存epoll_wait返回的事件组。 // src/redis.c 866
server.ipfd = anetTcpServer(server.neterr,server.port,server.bindaddr); //创建监听。 // src/redis.c 903
aeCreateTimeEvent(server.el, , serverCron, NULL, NULL); //注册一个时间事件serverCron,作用以后再讲。 // src/redis.c 906
aeCreateFileEvent(server.el,server.ipfd,AE_READABLE, acceptTcpHandler,NULL) //为监听fd的注册一个文件事件,首先把listenfd和触发条件epoll_ctl加入到全局的epoll fd进行监控。再以fd作为文件事件event数组index定位,mask填入只读,rfileProc填入acceptTcpHandler函数。 // src/redis.c 1571
aeSetBeforeSleepProc(server.el,beforeSleep); //aeEventLoop注册一个beforeSleep函数,这个函数在主循环里每次会被调用,作用以后再讲。 // src/ redis.c 1572
aeMain() //网络事件库的核心循环函数。 // src/ae.c 379
aeCreateLoop->beforesleep() //就是上面注册的beforeSleep函数。 // src/ae.c 275
aeProcessEvents(eventLoop, AE_ALL_EVENTS); //先调度aeApiPoll,用epoll_wait处理文件事件,返回的fd和触发条件先存储在eventLoop->fired[]里,然后根据fired[]每个事件的的fd,定位到events,根据触发条件调用已经注册的事件。 //文件事件处理完毕后,接下来就是处理超时时间事件,这里不表。 //假如有个用户连接上redis,则从redis servere就从上面的aeApiPoll的poll_wait返回,产生的只读事件会调度上面注册了acceptTcpHandler函数。 // src/networking.c 390
acceptTcpHandler(eventLoop, fd, NULL, AE_READABLE) //accept返回产生了一个新连接的fd(这里省略了很多步骤),需要从新的连接读取数据,于是为这个fd注册可读事件。 // src/networking.c 20
aeCreateFileEvent(server.el,fd,AE_READABLE, readQueryFromClient, c) //于是调用了aeCreateFileEvent 为只读事件注册, 这里的步骤和上面的listen fd 一样。用epoll_ctl将fd加入到epoll fd里等待下次epoll_wait,再注册触发条件和readQueyFromClient函数,接着aeMain()继续执行等待用户的数据。 //假如用户在这个连接键入redis命令例如:set foo bar,redis server端将会从aeApiPoll的epoll_wait返回,和accept一样的处理方式。返回的fd填入到fired[]数组,通过fired[fd]->fd找到是哪个文件事件,找到events[fd]->rfielProc这个函数,就是上面注册的readQueyFromClient 函数。 // src/networking.c 816
readQueyFromClient(server.el, fd, NULL, AE_READABLE) //这个函数首先会执行read从tcp buffer读取用户键入的命令(非阻塞io),然后处理buffer,找到对应的command(lookupCommand),接下来执行这个command(call(c,cmd)),命令执行完毕需要返回结果的时候,会再次注册一个文件事件 // src/networking.c 71
aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, sendReplyToClient, c) //这样下次循环epoll_wait的时候就发现这个fd可写,于是就会执行//sendReplyToClient,讲结果发送给client。 //redis的这个网络事件库是比较标准的网络框架的模式,实现的功能不算多但够用。
原文:http://www.hoterran.info/redis_eventlibrary
(转)redis源代码分析 – event library的更多相关文章
- Redis源代码分析(一)--Redis结构解析
从今天起,本人将会展开对Redis源代码的学习,Redis的代码规模比較小,很适合学习,是一份很不错的学习资料,数了一下大概100个文件左右的样子,用的是C语言写的.希望终于能把他啃完吧,C语言好久不 ...
- redis 源代码分析(一) 内存管理
一,redis内存管理介绍 redis是一个基于内存的key-value的数据库,其内存管理是很重要的,为了屏蔽不同平台之间的差异,以及统计内存占用量等,redis对内存分配函数进行了一层封装,程序中 ...
- Redis源代码分析(23)--- CRC循环冗余算法RAND随机数的算法
他今天就开始学习Redis源代码的一些工具来实现,在任何一种语言工具.算法实现的原理应该是相同的,一些比較经典的算法.比方说我今天看的Crc循环冗余校验算法和rand随机数产生算法. CRC算法全称循 ...
- Redis源代码分析(十一年)--- memtest内存测试
今天,我们继续redis源代码test下测试在封装中的其它文件.今天读数memtest档,翻译了,那是,memory test 存储器测试工具..可是里面的提及了非常多东西,也给我涨了非常多见识,网上 ...
- Redis源代码分析(三)---dict哈希结构
昨天分析完adlist的Redis代码.今天立即马不停蹄的继续学习Redis代码中的哈希部分的结构学习,只是在这里他不叫什么hashMap,而是叫dict.并且是一种全新设计的一种哈希结构,他仅仅是通 ...
- Redis源代码分析(六)--- ziplist压缩列表
ziplist和之前我解析过的adlist列表名字看上去的非常像.可是作用却全然不同.之前的adlist主要针对的是普通的数据链表操作. 而今天的ziplist指的是压缩链表.为什么叫压缩链表呢.由于 ...
- Redis源代码分析(二十)--- ae事件驱动
事件驱动的术语出现更频繁.听起来非常大的,今天我把Redis内部驱动器模型来研究它,奖励的感觉啊.一个ae.c主程序,加4文件的事件类型,让你彻底弄清楚,Redis是怎样处理这些事件的. 在Redis ...
- Redis源代码分析(五)--- sparkline微线图
sparkline这个单词,我第一次看的时候.也不知道这什么意思啊,曾经根本没听过啊,可是这真真实实的出如今了redis的代码中了,刚刚開始以为这也是属于普通的队列嘛.就把他分在了struct包里了. ...
- Redis源代码分析(十三)--- redis-benchmark性能測试
今天讲的这个是用来给redis数据库做性能測试的,说到性能測试,感觉这必定是高大上的操作了.redis性能測试.測的究竟是哪方面的性能,怎样測试,通过什么指标反映此次測试的性能好坏呢.以下我通过源代码 ...
随机推荐
- [ASP.NET]EF跨项目调用问题
在一个项目中调用另一个项目中的模型,在该项目中添加一个模型,解决自动提示问题using问题
- 从零開始写游戏引擎(一) - project创建以及文件夹设置还有版本号控制
一句话提要 好的開始等于成功了一半. 创建文件夹结构 project文件夹下最好分为以下几个文件夹 Docs - 开发文档,设计文档 Assets - 角色,动作,模型和音效等 Source - 代码 ...
- C语言--指针(一)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenVveW91MTMxNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- 兔子-RadioButton和RadioGroup的关系
RadioButton和RadioGroup的关系: 1.RadioButton表示单个圆形单选框.而RadioGroup是能够容纳多个RadioButton的容器 2.每一个RadioGroup中的 ...
- emacs使用本地emacs server模式打开远程文件
使用emacs的用户都知道,一般要打开远程机器上的文件要使用TrampMode模式,调用方式例如以下: C-x C-f /remotehost:filename RET (or /method:use ...
- Oracle 11g 学习3——表空间操作
一.表空间概述 表空间是Oracle中最大的逻辑存储结构,与操作系统中的数据文件相相应: 基本表空间:一般指用户使用的永久性表空间,用于存储用户的永久性数据 暂时表空间: 主要用于存 ...
- Android 编程下获得应用程序的签名
说明:应用程序的签名被封装在 packageInfo 中,所以我们要获得应用程序的签名就需要获得 PackageManager 来获得包含有签名信息的 packageInfo,再通过 packageI ...
- python网络编程三次握手和四次挥手
TCP是因特网中的传输层协议,使用三次握手协议建立连接.当主动方发出SYN连接请求后,等待对方回答SYN+ACK[1],并最终对对方的 SYN 执行 ACK 确认.这种建立连接的方法可以防止产生错误的 ...
- caffe mnist实例 --lenet_train_test.prototxt 网络配置详解
1.mnist实例 ##1.数据下载 获得mnist的数据包,在caffe根目录下执行./data/mnist/get_mnist.sh脚本. get_mnist.sh脚本先下载样本库并进行解压缩,得 ...
- Java环境安装配置好了却不能运行xxx.jar程序?
1,检查Java环境是否已安装或配置成功. WIN+R → cmd → java -version,查看是否可以读取到Java版本信息,如果读取不到,说明Java环境安装或配置有问题,重新装一下. 2 ...