Redis源码解析:13Redis中的事件驱动机制

         Redis中,处理网络IO时,采用的是事件驱动机制。但它没有使用libevent或者libev这样的库,而是自己实现了一个非常简单明了的事件驱动库ae_event,主要代码仅仅400行左右。

         没有选择libevent或libev的原因大概在于,这些库为了迎合通用性造成代码庞大,而且其中的很多功能,比如监控子进程,复杂的定时器等,这些都不是Redis所需要的。

         Redis中的事件驱动库只关注网络IO,以及定时器。该事件库处理下面两类事件:

         a:文件事件(file  event):用于处理Redis服务器和客户端之间的网络IO。

         b:时间事件(time  eveat):Redis服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是处理这类定时操作的。

         事件驱动库的代码主要是在src/ae.c中实现的。

 

一:文件事件

         Redis基于Reactor模式开发了自己的网络事件处理器,也就是文件事件处理器。文件事件处理器使用IO多路复用技术,同时监听多个套接字,并为套接字关联不同的事件处理函数。当套接字的可读或者可写事件触发时,就会调用相应的事件处理函数。

         Redis使用的IO多路复用技术主要有:select、epoll、evport和kqueue等。每个IO多路复用函数库在Redis源码中都对应一个单独的文件,比如ae_select.c,ae_epoll.c, ae_kqueue.c等。

         这些多路复用技术,根据不同的操作系统,Redis按照一定的优先级,选择其中的一种使用。在ae.c中,是这样实现的:

#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
    #ifdef HAVE_EPOLL
    #include "ae_epoll.c"
    #else
        #ifdef HAVE_KQUEUE
        #include "ae_kqueue.c"
        #else
        #include "ae_select.c"
        #endif
    #endif
#endif

         注意这里是include的.c文件,因此,使用哪种多路复用技术,是在编译阶段就决定了的。

 

         文件事件由结构体aeFileEvent表示,它的定义如下:

/* File event structure */
typedef struct aeFileEvent {
    int mask; /* one of AE_(READABLE|WRITABLE) */
    aeFileProc *rfileProc;
    aeFileProc *wfileProc;
    void *clientData;
} aeFileEvent;

         其中mask表示描述符注册的事件,可以是AE_READABLE,AE_WRITABLE或者是AE_READABLE|AE_WRITABLE。

         rfileProc和wfileProc分别表示可读和可写事件的回调函数。

         clientData是用户提供的数据,在调用回调函数时被当做参数。注意,该数据是可读和可写事件共用的。

 

二:时间事件

         Redis的时间事件主要有一次性事件和周期性事件两种。一次性时间事件仅触发一次,而周期性事件每隔一段时间就触发一次。

         时间事件由aeTimeEvent结构体表示,它的定义如下:

/* Time event structure */
typedef struct aeTimeEvent {
    long long id; /* time event identifier. */
    long when_sec; /* seconds */
    long when_ms; /* milliseconds */
    aeTimeProc *timeProc;
    aeEventFinalizerProc *finalizerProc;
    void *clientData;
    struct aeTimeEvent *next;
} aeTimeEvent;

         id用于标识时间事件,id号按照从小到大的顺序递增,新时间事件的id号比旧时间事件的id号要大;

         when_sec和when_ms表示时间事件的下次触发时间,实际上就是一个Unix时间戳,when_sec记录它的秒数,when_ms记录它的毫秒数。因此触发时间是一个绝对值,而非相对值;

         timeProc是时间事件处理器,也就是时间事件触发时的回调函数;

         finalizerProc是删除该时间事件时要调用的函数;

         clientData是用户提供的数据,在调用timeProc和finalizerProc时,作为参数;

 

         所有的时间事件aeTimeEvent结构被组织成一个链表,next指针就执行链表中,当前aeTimeEvent结构的后继结点。

         aeTimeEvent结构链表是一个无序链表,也就是说它并不按照事件的触发时间而排序。每当创建一个新的时间事件aeTimeEvent结构时,该结构就插入链表的头部。因此,当监控时间事件时,需要遍历整个链表,查找所有已到达的时间事件,并调用相应的事件处理器。

         在目前版本中,正常模式下的Redis服务器只使用serverCron一个时间事件,而在benchmark

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值