Base: redis 2.4.4
Update : redis 2.8.7


Reids基于 事件驱动(Event-driven) 构建服务。
Event-driven,提到这个,很容易想到如雷贯耳的libevent库(libeven封装了以下三种事件的响应:IO事件,定时器事件,信号事件)。
Redis的没有采用庞大的libevent库,而是自己写了一个,牺牲了一些平台通用性,但是性能非常强劲 。memcache采用了libevent,有人认为这是redis的优于性能比memcache性能。没有系统性的测试过,此处保留意见。

ae.h ae.c networking.c   anet.c  net.h ae_epoll.c ae_select.c ae_kqueue.c
ae.h、ae.c :event library具体实现
networking.c : 与客户端的交互 
anet.h anet.c : 网络通信
ae_epoll.c ae_select.c ae_kqueue.c  : 不同系统多路IO封装
             ae_epoll.c : linux平台
             ae_select.c :unix平台
             ae_kqueue.c : BSD、APPLE

根据操作系统进行多路IO类型选择,linux系统选择为epoll


[cpp]  view plain  copy


 


1. #ifdef __linux__  
2. #define HAVE_EPOLL 1  
3. #endif  
4.   
5. #if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)  
6. #define HAVE_KQUEUE 1  
7. #endif  
8.   
9. #ifdef __sun  
10. #include <sys/feature_tests.h>  
11. #ifdef _DTRACE_VERSION  
12. #define HAVE_EVPORT 1  
13. #endif  
14. #endif


[cpp]  view plain  copy


 

1. #ifdef HAVE_EVPORT  
2. #include "ae_evport.c"  
3. #else  
4.     #ifdef HAVE_EPOLL  
5.     #include "ae_epoll.c"  
6.     #else  
7.         #ifdef HAVE_KQUEUE  
8.         #include "ae_kqueue.c"  
9.         #else  
10.         #include "ae_select.c"  
11.         #endif  
12.     #endif  
13. #endif




其中ae_epoll.c中封装了epoll的实现



多路IO封装



aeApiCreate:创建句柄(epoll_create)


aeApiFree:关闭句柄(close)


aeApiAddEvent:事件添加(epoll_ctl)


aeApiDelEvent:事件删除(epoll_ctl)


aeApiPoll:等待事件发生(epoll_wait)



服务处理

:    


1. 初始化server, 等待客户端连接,并注册事件,回调函数acceptTcpHandler/acceptUnixHandler


[cpp]  view plain  copy


 


    1. if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE,  
    2. "creating file event");  
    3. if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,  
    4. "creating file event");


    2. 回调函数acceptTcpHandler/acceptUnixHandler


    在监听到新连接请求时,接收连接,创建redisClient对象,并注册事件(回调函数readQueryFromClient)


    [cpp]  view plain  copy


     


    1. void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {  
    2.     ......   
    3.     nread = read(fd, c->querybuf+qblen, readlen);  
    4.     ......  
    5. if (nread) {  
    6.         sdsIncrLen(c->querybuf,nread);  
    7.         c->lastinteraction = server.unixtime;  
    8. if (c->flags & REDIS_MASTER) c->reploff += nread;  
    9. else {  
    10.         server.current_client = NULL;  
    11. return;  
    12.     }  
    13.     ......  
    14. }


    3. 客户端请求处理:


    在接收到客户端请求数据后,首先对请求进行分析,解析完成后反馈请求


    [cpp]  view plain  copy


     


      1. void processInputBuffer(redisClient *c) {  
      2. while(sdslen(c->querybuf)) {  
      3. //分析请求  
      4. if (c->argc == 0) {  
      5.             resetClient(c);  
      6. else {  
      7. if (processCommand(c) == REDIS_OK)  
      8.                 resetClient(c);  
      9.         }  
      10.     }  
      11. }



      在请求处理完成后,反馈结果.



      Redis执行完客户端请求后,会调用addReply,在addReply中调用installWriteEvent来注册一个事件,并绑定事件处理函数sendReplyToClient,用来把响应发送到client



      4.主循环


      处理定时事件和注册事件


      [cpp]  view plain  copy


       


        1. void aeMain(aeEventLoop *eventLoop) {  
        2.     eventLoop->stop = 0;  
        3. while (!eventLoop->stop) {  
        4. if (eventLoop->beforesleep != NULL)  
        5.             eventLoop->beforesleep(eventLoop);  
        6.         aeProcessEvents(eventLoop, AE_ALL_EVENTS);  
        7.     }  
        8. }


        beforesleep通过aeSetBeforeSleepProc定义,主要是特殊处理vm和aof相关的请求


        rfileProc和wfileProc即注册事件时定义的回调函数