Redis事件驱动库结构

标签: Redis Event Library 源码 | 发表时间:2011-08-14 18:54 | 作者:nosqlfan zffl
出处:http://blog.nosqlfan.com

本文翻译自Redis官方对事件驱动库的结构描述,英文原文点这里,由Day Day Up博客原创,文章写的时间已经比较长了,今天才被NoSQLFan挖出来,实属难得。

下面就是其原文:

文章地址:blog.ddup.us

这是一篇翻译文章,原文见这里。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:当一个已计时事件从计时事件列表中被移走之前调用的函数。

initServer函数调用aeCreateTimeEvent函数来添加一个计时事件到server.el的timeEventHead字段中。timeEventHead是一个指向计时事件的链表。redis.c文件中initServer函数调用aeCreateTimeEvent函数形式如下:

aeCreateTimeEvent(server.el /*eventLoop*/, 1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);

redis.c文件中的serverCron会进行一些列的操作来保证Redis正常运行。

aeCreateFileEvent

调用aeCreateFileEvent函数的目的是执行epoll_ctl系统调用,以便将由anetTcpServer函数创建的监听描述符加入到EPOLLIN事件队列中。同时将它和aeCreateEventLoop函数调用生成的epoll描述符相关连。

下边详细解释了当initServer调用aeCreateFileEvent函数时的工作,initServer传递接下来的参数给aeCreateFileEvent函数:

  • server.el:aeCreateEventLoop建立的事件循环。epoll描述符从server.el中获得。
  • server.fd:负责监听的描述符,同时作为访问相关的文件事件结构体的索引。
  • AE_READABLE:标志server.fd必须被监视EPOLLIN
  • 事件。
  • acceptHandler:当监视的事件到达时要执行的函数。函数指针存储在eventLoop->events[server.fd]->rfileProc。

这样就完成了Redis的事件循环。

处理事件循环

redis.c文件中的main函数调用ae.c中的aeMain,处理前一阶段初始化完毕的事件循环。
ae.c文件中的aeMain函数调用ae.c文件中的aeProcessEvent函数,在一个循环中处理时间到期和文件事件。

aeProcessEvents

aeProcessEvents函数调用aeSearchNearestTimer函数来查询事件循环中最先要过期的事件。我们的事例中只有一个事件那就是通过调用aeCreateTimeEvent函数建立的。

记住,如果将超时时间设定为1毫秒,那么通过aeCreateTimeEvent函数建立的定时器事件很可能会被忽略。
和事件循环相关连的tvp结构体被传递给ae_epoll.c文件中的aeApiPoll函数。aeApiPoll函数在epoll描述符上进行epoll_wait,同时想下边描述的方式激发eventLoop->fired表。

  • fd:根据掩码值此时准备好读/写的描述符。
  • mask:读/写操作可以在对应的描述符上进行。

aeApiPoll函数返回准备好的文件描述符个数。现在我们总结一下,当有客户端请求到来时候,aeApiPoll函数会发现并且使用一个正在监听的描述符实体和AE——READABLE掩码激发eventLoop->fired表格。

现在aeProcessEvents函数调用redis.c文件中已经被注册为回调函数的acceptHandler函数。acceptHandler函数在正在监听的描述符上执行accpet操作,返回一个已经和客户端建立连接的描述符。createClient函数通过调用aeCreateFileEvent函数向已经连接的描述符上添加一个文件事件。如下所示:

if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
readQueryFromClient, c) == AE_ERR) {
freeClient(c);
return NULL;
}

代码中的c指的是redisClient结构类型的变量,c->fd就是已经建立连接的描述符。然后aeProcessEvent函数调用processTimeEvents函数。

processTimeEvents

processTimeEvents从时间事件列表开始处eventLoop->timeEventHead开始迭代。

对于每一个到期的时间事件,processTimeEvents调用相应的已注册的回调函数。本例中仅有一个已注册的回调函数,也就是redis.c文件中的serverCron函数。这个函数返回毫秒数,指示这个回调函数过多长时间再次调用。这写更改可以通过调用aeAddMilliSeconds函数记录,而且会在下一次循环中处理。

技术传播,需要你我共同努力!    

相关文章:

Redis String类型实现原理

Redis源码分析-内存分配

Redis与CouchDB的对比

Redis4You:Redis云存储服务商

Redis内存存储结构分析
无觅

相关 [redis 事件驱动 结构] 推荐:

Redis事件驱动库结构

- zffl - NoSQLFan
本文翻译自Redis官方对事件驱动库的结构描述,英文原文点这里,由Day Day Up博客原创,文章写的时间已经比较长了,今天才被NoSQLFan挖出来,实属难得. 文章地址:blog.ddup.us. 这是一篇翻译文章,原文见这里. Redis实现了它自己的事件库. 要弄明白Redis事件库是如何工作的最好的方法就是弄明白Redis是如何使用它的.

Redis内存存储结构分析

- 小丑鱼 - 搜索技术博客-淘宝
Redis 内存存储结构. 本文是基于 Redis-v2.2.4 版本进行分析.. 1.1 Redis 内存存储总体结构. Redis 是支持多key-value数据库(表)的,并用 RedisDb 来表示一个key-value数据库(表). redisServer 中有一个 redisDb *db; 成员变量, RedisServer 在初始化时,会根据配置文件的 db 数量来创建一个 redisDb 数组.

redis数据结构缓存运用

- - 企业架构 - ITeye博客
之前redis已经描述了redis 的基本作用与用处, 这一篇主要讲述redis运用场景以及分片,和spring整合. redis 存储数据结构大致5种,String 普通键值对,用的比较多. HASH针对 key 唯一标识 hashmap 键值对运用也比较多 list set 当然是集合运用 sortedSet 排序集合使用.

十五分钟介绍 Redis数据结构

- chao - NoSQLFan
下面是一个对Redis官方文档《A fifteen minute introduction to Redis data types》一文的翻译,如其题目所言,此文目的在于让一个初学者能通过15分钟的简单学习对Redis的数据结构有一个了解. Redis是一种面向“键/值”对类型数据的分布式NoSQL数据库系统,特点是高性能,持久存储,适应高并发的应用场景.

Redis中5种数据结构的使用场景介绍

- - 企业架构 - ITeye博客
这篇文章主要介绍了Redis中5种数据结构的使用场景介绍,本文对Redis中的5种数据类型String、Hash、List、Set、Sorted Set做了讲解,需要的朋友可以参考下. 一、redis 数据结构使用场景. 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码.

再谈EDA事件驱动架构

- - 人月神话的BLOG
EDA事件驱动架构首先不是对于传统的面向业务流程,数据等各种架构模式的完全否定,而是解决传统架构下无法很好解决的一些问题. 传统模式里面更加关注业务流程和业务对象,而EDA模式下将更加关注在整个业务流程中的关键状态点,已经由关键状态点触发的有明确业务含义的业务事件. EDA架构的核心仍然是基于消息的发布订阅模式,消息的特定就是准实时,异步和彻底解耦.

事件驱动架构避坑指南

- - DockOne.io
事件驱动架构非常强大,非常适合分布式微服务环境. 通过引入代理中介,事件驱动架构提供了更好的解耦架构、更容易的可扩展性和更高程度的弹性. 请求应答模式 (client-server) vs. 事件流模式 (pub-sub). 但与请求应答客户端-服务器类型架构相比,事件流模式的搭建更复杂. 在Wix过去的几年里,我们逐渐的将我们不断增长的微服务集(目前为 2300 个)从请求-应答模式迁移到事件驱动架构模式.

Redis 负载监控——redis-monitor

- - ITeye资讯频道
redis-monitor是一个Web可视化的 redis 监控程序. 使用 Flask 来开发的,代码结构非常简单,适合移植到公司内网使用. redis 服务器信息,包括 redis 版本、上线时间、 os 系统信息等等. 实时的消息处理信息,例如处理 command 数量、连接总数量等. 内存占用、 cpu 消耗实时动态图表.

反向Ajax,第5部分:事件驱动的Web开发

- Taozi - 译言-电脑/网络/数码科技
到目前为止你已经了解了创建通过事件来通信的组件,在本系列的最后一部分内容中,我们把事件驱动开发的原则应用到实践中,构建一个示例性的事件驱动web应用. 你可以下载本文中使用的源代码. 理想情况下,要充分体会本文的话,你应该对JavaScrpit和Java有一定的了解,并且要有一些web开发经验. 若要运行本文中的例子,你还需要最新版本的Maven和JDK(参见参考资料).

[译] 当提到 “事件驱动” 时,我们在说什么?

- - IT瘾-dev
文/Martin Fowler. 去年年底(译者注:2016年底),我和ThoughtWorks同事一起参加了一个研讨会,讨论“事件驱动”的本质. 在过去的几年里,我们构建的很多系统都大量使用了事件. 对于这些系统,人们常常赞誉有加,但批评的声音也不绝于耳. 我们的北美办公室组织了一次峰会,来自世界各地的ThoughtWorks资深开发者出席会议并分享了他们的想法.