前言
Redis系列博客为对黄健宏老师《Redis设计与实现》一书内容的整理
第12章 事件
本章关键词:Reactor模式、I/O多路复用程序
Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件:
* 文件事件:Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。 服务器与客户端的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作。
* 时间事件:Redis服务器中的一些操作(例如serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对这类定时操作的抽象。
套接字说明链接:什么是套接字(Socket)_luzhensmart的专栏-优快云博客_套接字
文件事件
Redis基于Reactor模式开发了自己的网络事件处理器,这个处理器被称为文件事件处理器(file event handler):
* 文件事件处理器使用I/O多路复用程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
* 当被监听的套接字准备好执行连接应答、读取、写入、关闭等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行,但通过使用I/O多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与Redis服务器中其他同样以单线程运行的模块进行对接,者保持了Redis内部单线程设计的简单性。
文件事件处理器的构成
文件事件是对套接字操作的抽象,当一个套接字准备好执行连接应答、写入、读取、关闭等操作时,就会产生一个文件事件, 所以多个文件事件有可能并发的出现。
IO多路复用程序总是会将所有产生事件的套接字都放到一个队列里面,然后通过这个队列,以有序、同步(synchronously)、每次一个套接字的方式向文件事件分派器传送套接字。当上一个套接字产生的时间被处理完毕,IO多路复用程序才会继续向文件事件分派器传送下一个套接字。
串行执行保证有序性
文件事件分派器接收套接字并根据套接产生的事件类型,调用相应的事件处理器。
I/O多路复用程序的实现
IO多路复用程序的实现
Redis在I/O多路复用程序的实现源码中用#include宏定义了相应的规则,程序会在编译时自动选择系统中性能最高的I/O多路复用函数库来作为Redis的I/O多路复用程序的底层实现。
不是同时使用,而是四选一使用。
文件事件的类型
IO多路复用程序可以监听多个套接字的AE_READABLE事件和AE_WRITABLE事件。
* 当客户端对套接字进行write操作或者close操作或者客户端对服务器的监听套接字发出connect请求,套接字里会有内容变得可读,产生AE_READABLE事件,IO多路复用程序需要阅读里面的内容
* 当客户端对套接字进行read操作,套接字里变得可写,需要有内容便会发出AE_WRITABLE事件,IO多路复用程序需要往套接字里写内容。
如果一个套接字可读又可写时,服务器将先读套接字,后写套接字。
文件事件的处理器
-
连接应答处理器:对连接服务器的各个客户端进行应答;
-
命令请求处理器:接收客户端传来的命令请求;
-
命令回复处理器:向客户端返回命令的执行结果;
-
复制功能编写的复制处理器:主服务器和从服务器进行复制操作;
时间事件
Redis的时间事件分为以下两类:
定时事件:让一段程序在指定的时间之后执行依次。比如说,让程序X在当前时间的30ms后执行一次。
周期性事件:让一段程序每隔指定时间就执行一次。比如说,让程序Y每隔30ms就执行一次。
一个时间事件主要由以下三个属性组成:
-
id:服务器为时间事件创建的全局唯一ID(标识号),顺序递增;
-
when:毫秒精度的UNIX时间戳,记录了时间事件的到达时间;
-
timeProc:时间事件处理器函数,时间事件到达后,服务器调用此函数处理事件。
根据timeProc返回的值来判断是定时事件还是非定时事件。
时间事件应用示例:serverCron函数
Redis服务器一般只进行serverCron操作,其工作包括:
* 更新服务器的各类统计信息
* 清理数据库中的过期键值对
* 关闭和清理连接失败的客户端
* 尝试进行AOF或RDB持久化操作
* 如果服务器是主服务器,那么对从服务器进行定期同步
* 如果处于集群模式,对集群进行定期同步和连接测试
事件的调度和执行
-
循环判断
-
获取到达时间离当前时间最接近的时间事件;
-
计算最接近的时间事件距离到达还有多少毫秒;
-
如果事件已到达,设置标识remaind_ms=0,并创建相应结构timeval;
-
根据remaind_ms阻塞并等待文件事件;
-
-
处理所有文件事件;
-
处理所有时间事件;
Reactor模式
Reactor模式称为反应器模式或应答者模式,是基于事件驱动的设计模式,拥有一个或多个并发输入源,有一个服务处理器和多个请求处理器,服务处理器会同步的将输入的请求事件以多路复用的方式分发给相应的请求处理器。
Reactor设计模式是一种为处理并发服务请求,并将请求提交到一个或多个服务处理程序的事件设计模式。当客户端请求抵达后,服务处理程序使用多路分配策略,由一个非阻塞的线程来接收所有请求,然后将请求派发到相关的工作线程并进行处理的过程。
在事件驱动的应用中,将一个或多个客户端的请求分离和调度给应用程序,同步有序地接收并处理多个服务请求。对于高并发系统经常会使用到Reactor模式,用来替代常用的多线程处理方式以节省系统资源并提高系统的吞吐量。
核心优势:一个线程里可以处理多个IO请求
异步阻塞IO