Redis 的高可用 很大程度上要归功于其 为 事件驱动服务工具,采用
Reactor 模式
使得其 拥有高性能 IO 操作
首先我们先科普一下什么叫 Reactor 模式
,即 事件驱动机制,应用程序提供相应的接口并注册到 Reactor 上,如果相应的事件发生,Reactor 将主动调用之前注册的接口,而这些接口又称为 回调函数
我们知道最最原始的网络编程的思想就是一个 while 循环,比如针对 端口连接套接字,那么就是 循环监听 端口套接字是否有连接事件发生,如果有的话就调用事件处理接口,这种方式最大的问题就是没有并发能力,因为 accept 是堵塞的,而且 如果 事件处理接口一直没有处理完毕,后面端口监听事件也就只能一直被阻塞
后来,有大牛就想到了使用多线程进行并发事件监控,Tomcat 早期的版本就是使用这个思路进行 并发连接的处理,这样一来确实能解决一定量的并发业务,提高了服务器的吞吐量,每个线程里面的 accept 阻塞不能影响其他连接的处理,但是缺点也比较明显,每次 线程的 新建-销毁 确实很耗费资源,并发数受系统资源的限制比较厉害;而且我们可以注意到 每次整个连接业务都是整体由一个线程负责,如果把 业务分开(接受连接、业务处理)呢?
所以就有了现在普遍使用的方式:IO 多路复用模型
(IO 模型方面感兴趣的童鞋可以去 Google 一下,或者等我后面 IO 模型专题 文章 ^v^,手动挖坑~),将阻塞的 accept 部分业务放到 一个主线程里面 监听,如果有 连接过来,回调事件接口,分发给 子线程进行业务处理,也就是 线程池的概念;当然这里的 线程池实现方式 在不同软件中也可能是由 进程池 取代;不同的系统提供了不同的 IO多路复用 实现方式(select
、poll
、epoll
等),之前我们讲解的 渐进式解析 memcached 源码 - 线程机制 这篇有提到,不过 memcached 使用的是 libevent 库
,libevent 将不同系统的实现方式进行了封装,被应用程序调用的时候会根据系统选择更优的实现方式;
Redis 的文件事件 在实现 Reactor 的时候,采用了自己封装 各个系统中的 IO 多路复用 的方式,而不是像 memcached 一样使用第三方库
Redis 事件
Redis 中事件主要有两种类型:
文件事件 ( file event )
Redis 文件事件一般都是 套接字的 读写状态监控,然后回调相应接口进行处理时间事件 ( time event )
时间事件 则是维护一个定时器,每当满足预设的时间要求,就将该时间事件标记为待处理,然后在 Redis 的事件循环中进行处理。Redis 对于这两种事件的处理优先级是 文件事件优先于时间事件
文件事件
文件事件的结构体为
就绪的文件事件结构体为
我们上面提到过 Redis 封装了 select、epoll、evport、kqueue 多个 IO 多路复用实现方式,根据不同系统选择不同的实现方式,这个判断是由 宏定义决定
我们也可以通过 info server
命令的 multiplexing_api
属性查看具体的 多路复用选择
时间事件
时间事件的结构体为
时间事件为一个双向链表
事件状态
事件池状态结构体为
比如我们常用的 epoll 库,*apidata
存储的数据结构如下
源码解析
由于有些方法里的代码量比较大,我们这里按照 典型的代码片段进行解析,同志们可以根据文章提示的代码位置 和 代码里面的关键词 在源码中搜素,可能数据结构一些元素 看不太懂什么意思,没关系,先混个脸熟,后面看完回头再看过来就明白了
向 Redis 事件表 aeEventLoop
的 event 注册一个事件,epoll 对应的是 epoll_ctl
函数,ae 事件库函数为 aeApiAddEvent()
函数 aeApiPoll()
调用底层 IO 复用函数 epoll_wait
来获取准备好的事件描述符
就绪事件的循环遍历处理我们之前已经分析过了,不知道大家是否还记得,详见 REDIS 服务器 源码分析中的 事件处理器部分,也可以搜索 aeProcessEvents() 函数
就绪事件循环中最终还是为了 回调函数的处理,比如 acceptTcpHandler()
而时间事件的添加函数为 aeCreateTimeEvent()
,逻辑比较简单,主要是将事件的 时间等属性加入 aeEventLoop 事件表中,比如我们常见的 serverCron
循环事件;由 processTimeEvents()
函数进行循环处理,类似上面的 aeProcessEvents() 函数的逻辑
以上为比较经典的函数逻辑解析,另外我从 其他资料找到了 一些 API 的详解,大家可以将就看看
本文作者: wettper
本文链接: http://www.web-lovers.com/redis-source-ae.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!