技术开发 频道

Redis数据库:事件驱动库结构详解

  【IT168技术】Redis实现了它自己的事件库。事件库的实现在ae.c文件中。要弄明白Redis事件库是如何工作的最好的方法就是弄明白Redis是如何使用它的。

  为什么需要事件库【FAQ】

  Q:你期望一个网络服务器如何工作?

  A:在它监听的端口等待连接的到来并且为之服务。

  Q:在一个描述符上调用accept时会阻塞,你是如何处理的?

  A:先保存这个描述符然后在描述符上进行非阻塞的read/write操作。

  Q:为什么要进行非阻塞的read/write?

  A:如果操作正阻塞在文件(Unix中socket也是看作文件的)上,那么服务器还怎么再接受其他的连接请求呢。

  Q:我觉得我要在socket上做很多的非阻塞的操作,是这样吗?

  A:是的,这也正是事件库为你完成的工作。

  Q:那么事件库是如何工作的?

  A:它使用操作系统提供的带计时器的polling方式。

  Q:那么有没有什么开源的事件库能完成你描述的功能吗?

  A:是的,Libevent和Libev是我能想起来的你说的那样的库。

  Q:Redis使用的这样的的事件库来处理socket I/O的吗?

  A:不是的,因为一些原因Redis使用了自己的事件库。

  初始化事件库

  在redis.c中定义了initServer函数用来初始化redisServer结构体中的一些字段。其中一个字段就是Redis事件循环 el:

aeEventLoop *el

   initServer函数通过调用在ae.c文件中定义的aeCreateEventLoop函数初始化server.el字段。aeEventLoop的定义如下:

typedef struct aeEventLoop
{
    
int maxfd;
    
long long timeEventNextId;
    aeFileEvent events
[AE_SETSIZE]; /* Registered events */
    aeFiredEvent fired
[AE_SETSIZE]; /* Fired events */
    aeTimeEvent
*timeEventHead;
    
int stop;
    void
*apidata; /* This is used for polling API specific data */
    aeBeforeSleepProc
*beforesleep;
} aeEventLoop;

   aeCreateEventLoop

  aeCreateEventLoop函数首先分配aeEventLoop结构体的空间,然后调用ae_epoll.c文件中的aeApiCreate函数。aeApiCreate函数分配aeApiState结构的空间,其中的两个字段:epfd 存放从epoll_create函数返回的epoll文件描述符;event字段是一个Linux epoll库定义的epoll_event结构类型。event字段的用处将会在后续说明。

  接下来是ae.c文件中的aeCreateTimeEvent。但是在这之前,initServer函数调用anet.c文件中anetTcpServer函数,该函数返回一个_监听的文件描述符(listening descriptor)_。这个描述符默认是在*6379端口*监听。返回的_监听的文件描述符_存放在inserver.fd字段中。

  aeCreateTimeEvent

  aeCreateTimeEvent函数接收如下参数:

  ①eventLoop:也就是redis.c文件中的server.el。

  ②miliseconds:定时器过期之后距离现在的毫秒数。

  ③proc:函数指针。定时器过期之后将要调用的函数。

  ④clientData:大部分时间都是NULL。

  ⑤finalizerProc:当一个已计时事件从计时事件列表中被移走之前调用的函数。

0
相关文章