redis是一个事件驱动程序
主要包含
文件事件和时间事件
文件事件:主要就是server和client进行操作产生的文件
时间事件:主要就是一些需要定时执行的事件。
文件事件:
文件事件处理器是单线程运行的,但是通过IO多路复用,可以处理多个套接字
下面是文件事件处理器的结构
文件事件处理器主要是上面四个部分构成的
文件事件其实就是对套接字操作的抽象,我们当执行读写的时候就会产生,因为文件事件处理器可以连接多个套接字,所以可能多个文件事件同时发生,但是IO多路程序会将这些文件事件都放在一个队列里面,通过文件事件分派器分配不同的处理器,每次只能分配一个,必须等上一个处理结束了才会继续处理下一个
IO多路复用的所有功能都是sselct,epoll这些库封装形成的,至于调用哪一个,完全看具体情况使用哪一个的效率
事件处理器的io多路复用可以监听多个socket的读写时间,当发生读事件的时候,产生AE_READABLE,当产生写事件的时候,发生AE_WRITABLE事件。,如果多个套接字同时产生读写时间,我们会先执行读事件,在执行写事件
文件的事件处理器:
连接应答处理器
命令请求处理器:
命令回复处理器
当client连接server的时候,会触发socket的readable执行连接应答处理器。当客户端通过连接应答处理器成功连接到server的时候,我们会将AE_READABLE和命令请求处理器关联起来,当客户端向服务器发送请求命令的时候,套接字就会产生AE_READABLE事件,并发送给命令请求处理器,结束后,当server需要回复client的时候,就会将socket和AE_WRITEABLE事件关联起来。当客户端需要read的时候就会触发这个事件。发送结束会,就会将socket和AE_WRITEABEL解除关联
一次完整的客户端与服务器连接事件示例
让我们来追踪一次 Redis 客户端与服务器进行连接并发送命令的整个过程, 看看在过程中会产生什么事件, 而这些事件又是如何被处理的。
假设一个 Redis 服务器正在运作, 那么这个服务器的监听套接字的 AE_READABLE 事件应该正处于监听状态之下, 而该事件所对应的处理器为连接应答处理器。
如果这时有一个 Redis 客户端向服务器发起连接, 那么监听套接字将产生 AE_READABLE 事件, 触发连接应答处理器执行: 处理器会对客户端的连接请求进行应答, 然后创建客户端套接字, 以及客户端状态, 并将客户端套接字的 AE_READABLE 事件与命令请求处理器进行关联, 使得客户端可以向主服务器发送命令请求。
之后, 假设客户端向主服务器发送一个命令请求, 那么客户端套接字将产生 AE_READABLE 事件, 引发命令请求处理器执行, 处理器读取客户端的命令内容, 然后传给相关程序去执行。
执行命令将产生相应的命令回复, 为了将这些命令回复传送回客户端, 服务器会将客户端套接字的 AE_WRITABLE 事件与命令回复处理器进行关联: 当客户端尝试读取命令回复的时候, 客户端套接字将产生 AE_WRITABLE 事件, 触发命令回复处理器执行, 当命令回复处理器将命令回复全部写入到套接字之后, 服务器就会解除客户端套接字的 AE_WRITABLE 事件与命令回复处理器之间的关联。
时间事件:
时间事件包括定时事件和周期性事件
定时事件就是执行一次
周期性事件都按照周期执行的
时间事件的属性有下面3个
id递增的
when:unix时间戳,表示什么时候执行
timeproc:时间事件处理器,一个函数,
实现其实就是一个链表
服务器会定期处理时间事件:
首先会遍历1所有的时间事件,看看哪个到了时间,如果时间到了的话。会判断返回值是否为AE_NOMORE,如果是的话,从server删除,不是的话,会设置返回值的时间后继续触发执行
时间事件函数:servercron函数
server会定期执行这个函数,这个函数有很多工作,比如对server资源的统计,比如内存,cpu等等
清理过期键
关闭和清理失效的客户端请求
尝试进行AOF和RBD
主从的同步
集群的定期连接测试
因为有两种事件,所以调度就是一个问题,我们需要怎么合理安排事件的调度
我们在选择的时候,经常会选择距离到达时间最近的时间事件,计算时间差,如果没有文件事件到达,可能会阻塞,等待文件事件的到来,文件事件到了之后,会先处理文件事件,等文件事件处理完了之后,在处理时间事件,所以通常时间事件的处理时间有的时候会被到来的晚一些