1.引言
Redis服务器是一个事件驱动程序,服务器需要处理以下两类事件:
1)文件事件(file event):Redis服务器通过套接字与客户端(或者 其他Redis服务器)进行连接,而文件事件就是服务器对套接字操作的抽象。服务器与客户端(或者其他服务器)的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作
2)·时间事件(time event):Redis服务器中的一些操作(比如 serverCron函数)需要在给定的时间点执行,而时间事件就是服务器对 这类定时操作的抽象
2.文件事件
背景:reactor:Reactor 模式也叫做反应器设计模式,是一种为处理服务请求并发提交到一个或者多个服务处理器的事件设计模式。当请求抵达后,通过服务处理器将这些请求采用多路分离的方式分发给相应的请求处理器。Reactor 模式主要由 Reactor 和处理器 Handler 这两个核心部分组成,如下图所示,它俩负责的事情如下:
Reactor:负责监听和分发事件,事件类型包含连接事件、读写事件;
Handler :负责处理事件,如 read -> 业务逻辑 (decode + compute + encode)-> send;
redis的文件事件特性:
虽然文件事件处理器以单线程方式运行,但通过使用I/O多路复用 程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模 型,又可以很好地与Redis服务器中其他同样以单线程方式运行的模块 进行对接,这保持了Redis内部单线程设计的简单性
2.1文件事件处理器的构成
图解一:展示了文件事件处理器的四个组成部分,它们分别是套接字、I/O多路复用程序、文件事件分派器(dispatcher),以及事件处理器
解析:
1)文件事件是对套接字操作的抽象,每当一个套接字准备好执行连接 应答(accept)、写入、读取、关闭等操作时,就会产生一个文件事 件。因为一个服务器通常会连接多个套接字,所以多个文件事件有可能 会并发地出现
2)I/O多路复用程序负责监听多个套接字,并向文件事件分派器传送 那些产生了事件的套接字。
尽管多个文件事件可能会并发地出现,但I/O多路复用程序总是会 将所有产生事件的套接字都放到一个队列里面,然后通过这个队列,以 有序(sequentially)、同步(synchronously)、每次一个套接字的方式 向文件事件分派器传送套接字。当上一个套接字产生的事件被处理完毕 之后(该套接字为事件所关联的事件处理器执行完毕),I/O多路复用程序才会继续向文件事件分派器传送下一个套接字
3)文件事件分派器接收I/O多路复用程序传来的套接字,并根据套接 字产生的事件的类型,调用相应的事件处理器
4)服务器会为执行不同任务的套接字关联不同的事件处理器,这些处 理器是一个个函数,它们定义了某个事件发生时,服务器应该执行的动作
3.文件事件的实现
3.1 I/0多路复用程序实现
Redis的I/O多路复用程序的所有功能都是通过包装常见的select、 epoll、evport和kqueue这些I/O多路复用函数库来实现的,每个I/O多路复 用函数库在Redis源码中都对应一个单独的文件
因为Redis为每个I/O多路复用函数库都实现了相同的API,所以I/O 多路复用程序的底层实现是可以互换的
图解二:
解析:
1.select函数:户通过3个参数分别传人感兴趣的可读、可写及异常等事件,内核通过对这些参数的在线修改来反馈其中的就绪事件。这使得用户每次调用select都要重置这3个参数0(n)
2.epoll:它在内核中维护一个事件表,并提供了一个独立的系统调用epoll_ctl来控制往其中添加、删除、修改事件。这样,每次 epoll_wait调用都直接从该内核事件表中取得用户注册的事件,而无须反复从用户空间读入这些事件。epoll_wait系统调用的events参数仅用来返回就绪的事件,这使得应用程序索引就绪文件描述符的时间复杂度达到O( 1)(回调)
参考:LinuxI高性能服务器之I/O复用(13)_
3.2事件类型
I/O多路复用程序可以监听多个套接字的ae.h/AE_READABLE事件 和ae.h/AE_WRITABLE事件
AE_READABLE事件:当套接字变得可读时(客户端对套接字执行write操作,或者执行 close操作),或者有新的可应答(acceptable)套接字出现时(客户端 对服务器的监听套接字执行connect操作),套接字产生 AE_READABLE事件。
AE_WRITABLE:当套接字变得可写时(客户端对套接字执行read操作),套接字产生AE_WRITABLE事件
总结: I/O多路复用程序允许服务器同时监听套接字的AE_READABLE事件和AE_WRITABLE事件,如果一个套接字同时产生了这两种事件,那 么文件事件分派器会优先处理AE_READABLE事件,等到 AE_READABLE事件处理完之后才处理AE_WRITABLE事件
3.3文件事件的处理器
·为了对连接服务器的各个客户端进行应答,服务器要为监听套接 字关联连接应答处理器。 ·
为了接收客户端传来的命令请求,服务器要为客户端套接字关联 命令请求处理器。
·为了向客户端返回命令的执行结果,服务器要为客户端套接字关 联命令回复处理器。
·当主服务器和从服务器进行复制操作时,主从服务器都需要关联 特别为复制功能编写的复制处理器
3.3.1连接应答处理器
当Redis服务器进行初始化的时候,程序会将这个连接应答处理器 和服务器监听套接字的AE_READABLE事件关联起来,当有客户端用 sys/socket.h/connect函数连接服务器监听套接字的时候,套接字就会产 生AE_READABLE事件,引发连接应答处理器执行,并执行相应的套接字应答操作
图解三:
3.3.2命令处理器
当一个客户端通过连接应答处理器成功连接到服务器之后,服务器会将客户端套接字的AE_READABLE事件和命令请求处理器关联起来, 当客户端向服务器发送命令请求的时候,套接字就会产生 AE_READABLE事件,引发命令请求处理器执行,并执行相应的套接字 读入操作
图解四:
3.3.3命令回复处理器
当服务器有命令回复需要传送给客户端的时候,服务器会将客户端 套接字的AE_WRITABLE事件和命令回复处理器关联起来,当客户端准 备好接收服务器传回的命令回复时,就会产生AE_WRITABLE事件,引发命令回复处理器执行
图解五
3.3.4总结
举例1:图解六.一次完整的客户端与服务器连接事件示例
1) 如果这时有一个Redis客户端向服务器发起连接,那么监听套接字 将产生AE_READABLE事件,触发连接应答处理器执行。处理器会对客 户端的连接请求进行应答,然后创建客户端套接字,以及客户端状态, 并将客户端套接字的AE_READABLE事件与命令请求处理器进行关联, 使得客户端可以向主服务器发送命令请求
2)假设客户端向主服务器发送一个命令请求,那么客户端套接 字将产生AE_READABLE事件,引发命令请求处理器执行,处理器读取 客户端的命令内容,然后传给相关程序去执行
3)执行命令将产生相应的命令回复,为了将这些命令回复传送回客户 端,服务器会将客户端套接字的AE_WRITABLE事件与命令回复处理器 进行关联。当客户端尝试读取命令回复的时候,客户端套接字将产生 AE_WRITABLE事件,触发命令回复处理器执行,当命令回复处理器将 命令回复全部写入到套接字之后,服务器就会解除客户端套接字的 AE_WRITABLE事件与命令回复处理器之间的关联