您当前的位置:首页 > 电脑百科 > 数据库 > Redis

Redis 事件机制详解

时间:2019-08-05 11:25:17  来源:  作者:

redis 采用事件驱动机制来处理大量的网络IO。它并没有使用 libevent 或者 libev 这样的成熟开源方案,而是自己实现一个非常简洁的事件驱动库 ae_event。

 

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

  • 文件事件(file event):用于处理 Redis 服务器和客户端之间的网络IO。
  • 时间事件(time eveat):Redis 服务器中的一些操作(比如serverCron函数)需要在给定的时间点执行,而时间事件就是处理这类定时操作的。

事件驱动库的代码主要是在src/ae.c中实现的,其示意图如下所示。

Redis 事件机制详解

 

aeEventLoop 是整个事件驱动的核心,它管理着文件事件表和时间事件列表,不断地循环处理着就绪的文件事件和到期的时间事件。下面我们就先分别介绍文件事件和时间事件,然后讲述相关的 aeEventLoop 源码实现。

文件事件

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

Redis 使用的IO多路复用技术主要有: select 、 epoll 、 evport 和 kqueue等。每个IO多路复用函数库在 Redis 源码中都对应一个单独的文件,比如ae select.c,ae epoll.c, ae_kqueue.c等。Redis 会根据不同的操作系统,按照不同的优先级选择多路复用技术。事件响应框架一般都采用该架构,比如 netty 和 libevent。

架构师经典总结:Redis 事件机制详解

 

如下图所示,文件事件处理器有四个组成部分,它们分别是套接字、I/O多路复用程序、文件事件分派器以及事件处理器。

架构师经典总结:Redis 事件机制详解

 

文件事件是对套接字操作的抽象,每当一个套接字准备好执行 accept、read、write和 close 等操作时,就会产生一个文件事件。因为 Redis 通常会连接多个套接字,所以多个文件事件有可能并发的出现。

I/O多路复用程序负责监听多个套接字,并向文件事件派发器传递那些产生了事件的套接字。

尽管多个文件事件可能会并发地出现,但I/O多路复用程序总是会将所有产生的套接字都放到同一个队列(也就是后文中描述的 aeEventLoop 的 fired 就绪事件表)里边,然后文件事件处理器会以有序、同步、单个套接字的方式处理该队列中的套接字,也就是处理就绪的文件事件。

架构师经典总结:Redis 事件机制详解

 

所以,一次 Redis 客户端与服务器进行连接并且发送命令的过程如上图所示。

  • 客户端向服务端发起建立 socket 连接的请求,那么监听套接字将产生 AE READABLE 事件,触发 连接应答处理器 执行。处理器会对客户端的连接请求进行应答,然后创建客户端套接字,以及客户端状态,并将客户端套接字的 AE READABLE 事件与 命令请求处理器 关联。
  • 客户端建立连接后,向服务器发送命令,那么客户端套接字将产生 AE_READABLE 事件,触发 命令请求处理器 执行,处理器读取客户端命令,然后传递给相关程序去执行。
  • 执行命令获得相应的命令回复,为了将命令回复传递给客户端,服务器将客户端套接字的 AEWRITEABLE 事件与 命令回复处理器 关联。当客户端试图读取命令回复时,客户端套接字产生 AE WRITEABLE 事件,触发命令 回复处理器 将命令回复全部写入到套接字中。

时间事件

Redis 的时间事件分为以下两类:

  • 定时事件:让一段程序在指定的时间之后执行一次。
  • 周期性事件:让一段程序每隔指定时间就执行一次。

Redis 的时间事件的具体定义结构如下所示。

一个时间事件是定时事件还是周期性事件取决于时间处理器的返回值:

  • 如果返回值是 AE_NOMORE,那么这个事件是一个定时事件,该事件在达到后删除,之后不会再重复。
  • 如果返回值是非 AE_NOMORE 的值,那么这个事件为周期性事件,当一个时间事件到达后,服务器会根据时间处理器的返回值,对时间事件的 when 属性进行更新,让这个事件在一段时间后再次达到。

Redis 将所有时间事件都放在一个无序链表中,每次 Redis 会遍历整个链表,查找所有已经到达的时间事件,并且调用相应的事件处理器。

介绍完文件事件和时间事件,我们接下来看一下 aeEventLoop 的具体实现。

创建事件管理器

Redis 服务端在其初始化函数 initServer 中,会创建事件管理器 aeEventLoop 对象。

函数 aeCreateEventLoop 将创建一个事件管理器,主要是初始化 aeEventLoop 的各个属性值,比如 events 、 fired 、 timeEventHead 和 apidata :

  • 首先创建 aeEventLoop 对象。
  • 初始化未就绪文件事件表、就绪文件事件表。 events 指针指向未就绪文件事件表、 fired指针指向就绪文件事件表。表的内容在后面添加具体事件时进行初变更。
  • 初始化时间事件列表,设置 timeEventHead 和 timeEventNextId 属性。
  • 调用 aeApiCreate 函数创建 epoll 实例,并初始化 apidata 。

aeApiCreate 函数首先创建了 aeApiState 对象,初始化了epoll就绪事件表;然后调用 epoll_create 创建了 epoll 实例,最后将该 aeApiState 赋值给 apidata 属性。

aeApiState 对象中 epfd 存储 epoll 的标识, events 是一个 epoll 就绪事件数组,当有 epoll 事件发生时,所有发生的 epoll 事件和其描述符将存储在这个数组中。这个就绪事件数组由应用层开辟空间、内核负责把所有发生的事件填充到该数组。

创建文件事件

aeFileEvent 是文件事件结构,对于每一个具体的事件,都有读处理函数和写处理函数等。Redis 调用 aeCreateFileEvent 函数针对不同的套接字的读写事件注册对应的文件事件。

比如说,Redis 进行主从复制时,从服务器需要主服务器建立连接,它会发起一个 socekt连接,然后调用 aeCreateFileEvent 函数针对发起的socket的读写事件注册了对应的事件处理器,也就是 syncWithMaster 函数。

aeCreateFileEvent 的参数 fd 指的是具体的 socket 套接字, proc 指 fd 产生事件时,具体的处理函数, clientData 则是回调处理函数时需要传入的数据。 aeCreateFileEvent 主要做了三件事情:

  • 以 fd 为索引,在 events 未就绪事件表中找到对应事件。
  • 调用 aeApiAddEvent 函数,该事件注册到具体的底层 I/O 多路复用中,本例为epoll。
  • 填充事件的回调、参数、事件类型等参数。

如上文所说,Redis 基于的底层 I/O 多路复用库有多套,所以 aeApiAddEvent 也有多套实现,下面的源码是 epoll 下的实现。其核心操作就是调用 epoll 的 epoll_ctl 函数来向 epoll 注册响应事件。有关 epoll 相关的知识可以看一下《JAVA NIO源码分析》

事件处理

因为 Redis 中同时存在文件事件和时间事件两个事件类型,所以服务器必须对这两个事件进行调度,决定何时处理文件事件,何时处理时间事件,以及如何调度它们。

aeMain 函数以一个无限循环不断地调用 aeProcessEvents 函数来处理所有的事件。

下面是 aeProcessEvents 的伪代码,它会首先计算距离当前时间最近的时间事件,以此计算一个超时时间;然后调用 aeApiPoll 函数去等待底层的I/O多路复用事件就绪; aeApiPoll函数返回之后,会处理所有已经产生文件事件和已经达到的时间事件。

与 aeApiAddEvent 类似, aeApiPoll 也有多套实现,它其实就做了两件事情,调用 epoll_wait 阻塞等待 epoll 的事件就绪,超时时间就是之前根据最快达到时间事件计算而来的超时时间;然后将就绪的 epoll 事件转换到fired就绪事件。 aeApiPoll 就是上文所说的I/O多路复用程序。具体过程如下图所示。

架构师经典总结:Redis 事件机制详解

 

processFileEvent 是处理就绪文件事件的伪代码,也是上文所述的文件事件分派器,它其实就是遍历 fired 就绪事件表,然后根据对应的事件类型来调用事件中注册的不同处理器,读事件调用 rfileProc ,而写事件调用 wfileProc 。

而 processTimeEvents 是处理时间事件的函数,它会遍历 aeEventLoop 的事件事件列表,如果时间事件到达就执行其 timeProc 函数,并根据函数的返回值是否等于 AE_NOMORE来决定该时间事件是否是周期性事件,并修改器到达时间。

删除事件

当不在需要某个事件时,需要把事件删除掉。例如: 如果fd同时监听读事件、写事件。当不在需要监听写事件时,可以把该fd的写事件删除。

aeDeleteEventLoop 函数的执行过程总结为以下几个步骤 1、根据 fd 在未就绪表中查找到事件 2、取消该 fd 对应的相应事件标识符 3、调用 aeApiFree 函数,内核会将epoll监听红黑树上的相应事件监听取消。



Tags:   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言什么是数据脱敏数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护常用脱敏规则替换、重排、加密、截断、掩码良好的数据脱敏实施1、尽...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
河南最有名的“13碗面”,吃过10种以上的一定是地道河南人,你吃过几碗?河南位于黄河中下游,优越的地理位置和条件,让河南的种植业在全国脱颖而出,被称为全国的“粮仓”。小麦是河南...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
在狗界中,有些狗狗比较凶残、霸道,今天我们就来说说被称为“犬中四煞”的4种狗,请认住它们的长相,看见了要绕路走! NO1:黑狼犬产地:中国寿命:11-12年黑狼犬是狼狗的一种,长大高大威猛...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
协议下的体面离婚 2015年1月 方晴供职于一家外企,袁亮硕士毕业后开了家公司。两人相识、恋爱后走进婚姻殿堂。 方晴和袁亮的儿子小浩出生了。本该是其乐融融的三口之家,却在一...【详细内容】
2021-12-28  Tags:   点击:(2)  评论:(0)  加入收藏
中国人神话世界五千年到一万年之前到底是一个什么样的世界?相信这个问题应该是困扰了大家许久吧!其实这些问题可以从远古时代的三皇五帝开始说起,三皇五帝对于中国人的影响就如...【详细内容】
2021-12-28  Tags:   点击:(2)  评论:(0)  加入收藏
去年有个新闻,说的是一名印度女孩自小被欧洲有钱人家收养,长大后要回来给自己出生的村子捐钱做慈善。等她回村的时候,村里人专门为女孩修了一条路。表面上看,这貌似是个暖心的故...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
日本在今年又给大家带来了一个巨大消息,日本著名的球星本田圭佑出资设立的一家公司,正式发售了飞行摩托车。 在之前可是在电视或者是电影中才能看到的,是具备了未来科幻的一个...【详细内容】
2021-12-28  Tags:   点击:(4)  评论:(0)  加入收藏
V社今日公布了2021年Steam最畅销游戏榜单,其中涵盖了本年度Steam上收入最高的100款游戏。为了得出每款游戏的总收入,Steam计算了2021年1月1日至2021年12月15日的游戏销售额、...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
“都怪我一时糊涂铸下大错,这几年为了蒙混过关,拆东墙补西墙就怕被发现,我对不起信任我的领导同事,更对不起我的家人。”内蒙古某国有合资公司原出纳员包某在庭审现场听取公诉人...【详细内容】
2021-12-28  Tags:   点击:(2)  评论:(0)  加入收藏
2021年黄金价格下跌11.3%,黄金现在已经下跌了6.5%。白银价格一度下跌19.3%,白银现在已经下跌了15%。美元通胀。白银自2020年2月份以来,五家中央银行(Fed、欧洲中央银行、日本中...【详细内容】
2021-12-28  Tags:   点击:(3)  评论:(0)  加入收藏
▌简易百科推荐
来源: my.oschina.net/xiaomu0082/blog/2990388首先说下问题现象:内网sandbox环境API持续1周出现应用卡死,所有api无响应现象刚开始当测试抱怨环境响应慢的时候 ,我们重启一下应...【详细内容】
2021-12-08  Java识堂    Tags:Redis   点击:(18)  评论:(0)  加入收藏
我不知道为什么你会选择对特定数量的“错误”(或警告)如此具体。听起来您正在寻找将要发布到 Yahoo! 的某些文章的内容。 Insider (N Foos to Blah for the BlahBlah)。那说:...【详细内容】
2021-12-07  富集云科技有限公司    Tags:Redis   点击:(14)  评论:(0)  加入收藏
目录 一、背景 二、步骤 0.理论支持 1、获取数据 2、结果 3、分析数据并评估大小 三、关于repl-backlog-size 一、背景 repl-backlog-size控制这个环形缓冲区. ​ 主从断...【详细内容】
2021-11-05  弈秋的美好生活    Tags:redis   点击:(41)  评论:(0)  加入收藏
Redis 性能测试是通过同时执行多个命令实现的。1,Redis-benchmarkRedis性能命令:redis性能命令格式: redis-benchmark [option] [option value] redis 性能测试工具可选参数如...【详细内容】
2021-11-02  川石信息    Tags:Redis   点击:(41)  评论:(0)  加入收藏
1 概述数据结构和内部编码 无传统关系型数据库的 Table 模型schema 所对应的db仅以编号区分。同一 db 内,key 作为顶层模型,它的值是扁平化的。即 db 就是key的命名空间。 key...【详细内容】
2021-11-01  JavaEdge    Tags:Redis   点击:(28)  评论:(0)  加入收藏
普通java中使用引用Java redis 驱动,即可连接:import redis.clients.jedis.Jedis; public class RedisTestJava { public static void main(String[] args) { //连...【详细内容】
2021-10-13  faesuite    Tags:Redis   点击:(34)  评论:(0)  加入收藏
Redis常用的数据结构有 string list set zset hashstringstring 是 Redis 的基本的数据类型,一个 key 对应一个 value。string 类型是二进制安全的,Redis的string可以包含任...【详细内容】
2021-10-12  语霖    Tags:Redis   点击:(36)  评论:(0)  加入收藏
列表类型可以存储一组按插入顺序排序的字符串,它非常灵活,支持在两端插入、弹出数据,可以充当栈和队列的角色。> LPUSH fruit apple(integer) 1> RPUSH fruit banana(integer)...【详细内容】
2021-09-17  深夜敲代码    Tags:Redis   点击:(54)  评论:(0)  加入收藏
Redis持久化意义 是做灾难恢复,数据恢复,也可以归类到高可用的一个环节里面去,比如你的redis整个挂了,然后redis就不可用了,你要做的事情是让redis变得可用,尽快变得可用 大量的请...【详细内容】
2021-08-12  小李说IT    Tags:Redis   点击:(77)  评论:(0)  加入收藏
当查询Redis中没有的数据时,该查询会下沉到数据库层,同时数据库层也没有该数据,当这种情况大量出现或被恶意攻击时,接口的访问全部透过Redis访问数据库,而数据库中也没有这些数据...【详细内容】
2021-07-30  随便t    Tags:缓存穿透   点击:(91)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条