Redis服务器是一个事件驱动程序,服务器需要处理一下两类事件
- 文件事件:Redis服务器通过套接字与客户端进行连接,而文件事件就是服务器对套接字操作的抽象
- 时间事件:Redis服务器中的一些操作需要在给定时间点执行,而时间事件就是这类定时操作的抽象
文件事件
Redis基于Reactor模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器。
- 文件事件处理器使用I/O多路复用程序来同时监听多个套接字,并根据套接字目前执行的任务来关联不同事件处理器
- 当被监听的套接字准备好执行连接应答、读取、写入、关闭等操作时,相应文件事件就会产生。这时就会调用相应事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行,但通过使用I/O多路复用既实现了高性能的网络通信模型。又可以与Redis其他同样以单线程方式运行的模块进行对接,保持了Redis内部单线程设计的简单性。
文件事件处理的构成
尽管多个文件事件可能会并发的出现,但I/O多路复用程序总是会将所有产生事件的套接字都放在一个队列里面,然后通过这个队列以有序同步的执行。
事件的类型
- AE_READABLE事件:套接字可读
- AE_WRITABLE事件:套接字可写
一个套接字又可读又可写时,服务器先读套接字,后写套接字
文件事件的处理器
- 连接应答处理器
- 命令请求处理器
- 命令回复处理器
- 复制处理器
- .......
客户端和服务端的通信过程
时间事件
- 定时执行:在指定时间之后执行一次
- 周期性执行:每隔指定时间执行一次
目前版本的Redis只使用周期性事件,而没有使用定时事件
实现
- id:服务器为时间事件创建的全局唯一ID,从小到大顺序递增
- when:毫秒精度的unix时间戳,记录时间事件到达时间(周期性时间事件,根据处理器返回值,更新该值)
- timeProc:时间处理器,当时间事件到达时,服务器会调用相应处理器来处理事件
服务器所有时间事件都放在一个无序列表(指没有按when属性排序)中,每当时间事件执行器运行时,遍历整个链表,查找到所有已到达的时间事件,并调用相应的事件处理器。
ServerCron函数
-
更新服务器各类统计信息,时间,内存占用、数据库占用等
-
清理数据过期键值对
-
关闭清理连接失效的客户端
-
尝试进行AOF或RDB持久化操作
-
如果是主服务器,对从服务器进行定期同步
-
如果处于集群模式,对集群进行定期同步和连接测试
Redis2.8开始,可以通过修改hz选项调整serverCron每秒执行次数。
事件的调度与执行
- 等待文件事件产生的最大阻塞时间由到达时间最接近当前时间的时间事件决定,既避免服务器对时间事件进行频繁的轮询,也可以确保函数不会阻塞过长时间。
- 文件事件和时间事件的处理都是同步、有序、原子的执行的,服务器不会中途中断事件处理,也不会对事件进行抢占。因此,不管文件事件处理器、还是时间事件处理器,它们都会尽可能的减少程序阻塞时间,并在有需要的时,主动让出执行权,降低造成事件饥饿的可能性。比如:命令回复处理,如果写入字节数超过预设常量,命令回复处理器会主动break跳出写入循环,将余下的数据留到下次在写。时间事件也会将非常耗时的持久化操作放到子线程或者子进程执行(Bgsave命令)
- 通常时间事件实际处理时间比设定时间稍晚执行