redis的事件模型详解(结合Reactor设计模式)

        文章基于redis-4.0.1源码详细介绍一下redis的事件模型。

      一、redis事件模型概览

        redis是一个事件驱动的服务程序,在redis的服务程序中存在两种类型的事件,分别是文件事件和时间事件。文件事件是对网络通信操作的统称,时间事件是redis中定时运行的任务或者是周期性的任务(目前redis中只有serverCron这一个周期性时间事件,并没有定时时间事件)。对于事件驱动类的程序,非常适合使用Reactor模式进行设计(如果要详细了解Reactor模式,请参考超链接中的博客)。redis也不例外,在文件事件处理的设计中采用了Reactor设计模式。

        下面对应于链接博客中Reactor模式图仔细讲解一下redis如何使用Reactor模式实现高效的文件事件模型。为了方便,首先将Reactor设计模式图作为图1放在本文中。

图 1 Reactor设计模式图

        Reactor模式包含四部分,分别是Handle(对于系统资源的一种抽象,在redis中就是监听描述符或者是连接描述符)、Synchronous Event Demultiplexer(同步事件分离器,在redis中对应于IO多路复用程序)、Event Handler(事件处理器,在redis中对应于连接应答处理器、命令请求处理器以及命令回复处理器、事件处理器等)和Initiation Dispatcher(事件分派器,在redis中对应于ae.c/aeProcessEvents函数)。

        在redis中将感兴趣的事件及类型(读、写)通过IO多路复用程序注册到内核中并监听每个事件是否发生。当IO多路复用程序返回的时候,如果有事件发生,redis在封装IO多路复用程序时,将所有已经发生的事件及该事件的类型封装为aeFiredEvent类型,放到aeEventLoop的fired成员中,形成一个队列。通过这个队列,redis以有序、同步、每次一个套接字事件的方式向文件事件分派器传送套接字,并处理发生的文件事件。redis处理事件(无论是文件事件还是时间事件)都是以原子的方式进行的,中间不存在事件之间的抢占。这很容易理解,redis是单线程模型,不存在处理上的并发操作。

        最后需要说明的是redis首先处理发生的文件事件,然后才会处理时间事件,这点我们在介绍redis源码aeProcessEvents的时候会详细注释和介绍。

      二、redis实现事件模型使用的数据结构

        redis表示事件模型的数据结构是对该事件标识、事件类型和事件处理函数的一种抽象,就是Reactor模式中的Handle和Event Handle的集合。redis使用了四种数据结构描述redis中的事件,前三种数据结构是对redis中某种特定类型事件的一种抽象,最后一种数据结构aeEventLoop是redis管理所有事件的一种抽象。aeTimeEvent中的id成员、aeFiredEvent中的fd成员都是Reactor模式中所说的Handle的具体表现,但是好像aeFileEvents并没有对应的handle。其实,redis在aeEventLoop的events成员中使用每一个描述符fd作为下标,该下标的对应值为aeFileEvent成员,由此将描述符fd与对该fd感兴趣的事件类型以及处理函数相关联,对应于Reactor中Handle与Event Handler的关联。当通过aeEventLoop中的fired获取到已经发生的事件fd及其类型mask的时候,由fd和mask在aeEventLoop的events成员中获取对应的事件处理器,处理已经发生的事件。也就是说,文件事件的处理是联合使用了fired和events两个成员变量;时间事件的处理使用aeTimeEvent变量。

        文件事件数据结构。

/* 文件事件 */
  typedef struct aeFileEvent {
      /* 套接字发生的事件,读事件或者写事件其中的一种 */
      int mask; /* one of AE_(READABLE|WRITABLE) */
      /* 读事件处理器,回调函数 */
      aeFileProc *rfileProc;
      /* 写事件处理器,回调函数 */
      aeFileProc *wfileProc;
      /* 客户端数据 */
      void *clientData;
  } aeFileEvent;

        时间事件数据结构。

  typedef struct aeTimeEvent {
      /* 时间事件,每个时间事件通过id唯一标识 */
      long long id;
      /* 时间事件应该触发的时间,单位:s */
      long when_sec;
      /* 时间事件被触发的时间,单位:ms */
      long when_ms;
      /* 时间事件处理函数 */
      aeTimeProc *timeProc;
      aeEventFinalizerProc *finalizerProc;
      /* 客户端数据 */
      void *clientData;
      /* 时间事件形成的链条 */
      struct aeTimeEvent *next;
  } aeTimeEvent;

        已经发生的文件事件数据结构。

  /* 已经发生的文件事件 */
  typedef struct aeFiredEvent {
      int fd;
      int mask;
  } aeFiredEvent;

        redis中时间管理结构体,包含了文件事件、时间事件、已发生的文件事件等相关信息。

  /* redis中的事件管理结构体 */
  typedef struct aeEventLoop {
      /* 当前IO程序追踪的最大的文件描述符,大于此值的setsize范围内的值,没有意义
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值