七叶笔记 » 数据库 » Redis中事件驱动模型示例详解

Redis中事件驱动模型示例详解

再看 Redis 对文件事件,封装epoll向上提供的接口:

所以看看这个ae_peoll.c 如何对 epoll 进行封装的:

aeApiCreate() 是对 epoll.epoll_create() 的封装。 aeApiAddEvent()和aeApiDelEvent() 是对 epoll.epoll_ctl()的封装。 aeApiPoll() 是对 epoll_wait()的封装。

这样 Redis 的利用 epoll 实现的 I/O 复用器就比较清晰了。

再往上一层次我们需要看看 ea.c 是怎么封装的?

首先需要关注的是事件处理器的数据结构:

mask 就是可以理解为事件的类型。

除了使用 ae_peoll.c 提供的方法外,ae.c 还增加 “增删查” 的几个 API。

增:aeCreateFileEvent 删:aeDeleteFileEvent 查: 查包括两个维度 aeGetFileEvents 获取某个 fd 的监听类型和aeWait等待某个fd 直到超时或者达到某个状态。

事件分发器(dispatcher)

Redis 的事件分发器 ae.c/aeProcessEvents 不但处理文件事件还处理时间事件,所以这里只贴与文件分发相关的出部分代码,dispather 根据 mask 调用不同的事件处理器。

可以看到这个分发器,根据 mask 的不同将事件分别分发给了读事件和写事件。

文件事件处理器的类型

Redis 有大量的事件处理器类型,我们就讲解处理一个简单命令涉及到的三个处理器:

acceptTcpHandler 连接应答处理器,负责处理连接相关的事件,当有client 连接到Redis的时候们就会产生 AE_READABLE 事件。引发它执行。 readQueryFromClinet 命令请求处理器,负责读取通过 sokect 发送来的命令。 sendReplyToClient 命令回复处理器,当Redis处理完命令,就会产生 AE_WRITEABLE 事件,将数据回复给 client。

文件事件实现总结

我们按照开始给出的 Reactor 模型,从上到下讲解了文件事件处理器的实现,下面将会介绍时间时间的实现。

时间事件

Reids 有很多操作需要在给定的时间点进行处理,时间事件就是对这类定时任务的抽象。

先看时间事件的数据结构:

看见 next 我们就知道这个 aeTimeEvent 是一个链表结构。看图:

注意:这是一个按照id倒序排列的链表,并没有按照事件顺序排序。

processTimeEvent

Redis 使用这个函数处理所有的时间事件,我们整理一下执行思路:

记录最新一次执行这个函数的时间,用于处理系统时间被修改产生的问题。 遍历链表找出所有 when_sec 和 when_ms 小于现在时间的事件。 执行事件对应的处理函数。 检查事件类型,如果是周期事件则刷新该事件下一次的执行事件。 否则从列表中删除事件。

综合调度器(aeProcessEvents)

综合调度器是 Redis 统一处理所有事件的地方。我们梳理一下这个函数的简单逻辑:

以上的伪代码就是整个 Redis 事件处理器的逻辑。

我们可以再看看谁执行了这个 aeProcessEvents:

然后我们再看看是谁调用了 eaMain:

我们在 Redis 的 main 方法中找个了它。

这个时候我们整理出的思路就是:

Redis 的 main() 方法执行了一些配置和准备以后就调用 eaMain() 方法。 eaMain() while(true) 的调用 aeProcessEvents()。

所以我们说 Redis 是一个事件驱动的程序,期间我们发现,Redis 没有 fork 过任何线程。所以也可以说 Redis 是一个基于事件驱动的单线程应用。

总结

在后端的面试中 Redis 总是一个或多或少会问到的问题。

读完这篇文章你也许就能回答这几个问题:

为什么 Redis 是一个单线程应用? 为什么 Redis 是一个单线程应用,却有如此高的性能? 如果你用本文提供的知识点回答这两个问题,一定会在面试官心中留下一个高大的形象。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对七叶笔记的支持。

相关文章