事件
redis服务器是一个事件驱动程序,主要处理两类事件:文件事件和时间事件。
文件事件
文件事件处理器使用I/O多路复用的程序来同时监听多个套接字,虽然redis的文件事件处理器以单线程方式运行,但通过io多路复用监听多个套接字,这样实现了高性能的网络通讯模型,又可以很好地让redis以单线程的方式运行,保持了单线程设计的简单性。(这是redis单线程还能那么快的原因之一)
文件事件的构成
由四个组成部分:套接字,io多路复用程序,文件事件分派器以及事件处理器。
image-20200825161924824当套接字变得可读(客户端对套接字执行write操作或者执行close操作)的时候,或者有新的可应答套接字出现时,套接字产生AE_READABLE事件。
当套接字变得可写时(客户端对套接字执行read操作),套接字产生AE_WRITABLE事件。
- 一次完整的连接通讯流程是怎么样子的?
假设一个redis服务器正在运作,这个时候服务器的监听套接字的AE_READABLE事件处于监听情况下。
这时有个redis客户端向服务器发起连接,那么监听套接字将产生AE_READABLE事件,触发连接应答处理器执行。
连接处理器应答之后会创建客户端套接字,客户端状态,并将客户端套接字的AE_READABLE事件与命令请求处理器进行关联。
然后假设客户端向主服务器发送一个命令请求,那么客户端套接字将产生AE_READABLE事件,引发命令请求处理器执行,处理器读取相关的命令内容,传给相关的程序执行。
之后命令会产生相关的恢复,为了将这个回复给客户端,服务器会将客户端套接字的AE_WRITABLE事件与命令回复处理器关联。当客户端尝试读取命令回复的时候,客户端套接字会产生AE_WRITABLE事件,触发命令回复处理器执行,当命令回复处理器将命令回复全部写入到套接字后,服务器就会解除客户端 套接字的事件和关联。
image-20200825182326976时间事件
redis的时间事件是用周期性事件(让一个程序每隔指定时间就执行一次)
主要有三个属性组成,id(唯一标识号),when(时间事件的到达时间),timeProc(时间事件处理函数)
- 那具体是怎么实现的?
redis服务器将所有的时间事件都放在一个无序列表中,事件执行器会去遍历这些节点,如果发现时间到达,就会执行对应的时间事件。
- 这样实现不会很耗费资源吗?
不会 ,因为redis的时间事件很少,正常模式下只有serverCron一个事件。
- serverCron函数是干嘛的?
主要工作有:
- 更新服务器的各类统计消息,比如时间,内存占用,数据库占用等。
- 清理数据库中的过期键值对。
- 关闭和清理链接失效的客户端。
- 尝试进行AOF或RDB持久化操作。
- 如果服务器是主服务器,那么对服务器进行定期同步。
- 如果处于集群模式,对集群进行定期同步和连接测试。
调度
- 因为服务器存在文件事件和时间事件,他们是怎么调度执行的?
很简单,ae.c/aeProcessEvents负责,如果有时间事件要处理,就不阻塞去处理时间事件,如果没有时间时间,会阻塞一下,来等待文件事件,然后执行文件事件,执行时间事件,然后不停死循环执行。
客户端
redis保存了客户端当前的状态信息,以及执行相关功能时需要用到的数据结构,其中包括:
- 客户端的套接字描述符(伪客户端是-1,在aof恢复用到,否则大于1,每个客户端都是唯一的)。
- 客户端的名字。(通过setname设置)
- 客户端的标识符。(标识客户端的角色(从服务器,微客户端)和客户端的状态(执行monitor命令等))
- 客户端正在使用的数据库的指针,已经该数据库的号码。
- 客户端当前要执行的命令,命令的参数,命令参数的个数,以及指向命令实现函数的指针。(从缓存区分析的到的命令内容)
- 客户端的输入缓冲区和输出缓冲区。(缓存了客户端的命令以及服务端的输出)
- 客户端的复制状态信息,以及进行复制所需的数据结构。
- 客户端执行BRPOP,BLPOP等列表阻塞命令时使用的数据结构。
- 客户端的事务状态,以及执行WATCH命令时用到的数据结构。
- 客户端执行发布与订阅功能用到的数据结构。
- 客户端的身份验证标志。
- 客户端的创建时间,最后一次通信时间。
是通过链表把多个客户端状态记录到服务器中。
- 客户端的关闭时机是什么时候?
- 客户端退出。
- 客户端发送了不符合协议内容的数据。
- 服务端调用CLIENT KILL
- 服务端设置了timeout配置,那么客户端空转太长就会被关闭。
- 客户端的命令大小超过1G。
- 输出缓冲区大于限制大小会被关闭。
服务器
命令执行器是如何工作的?
命令执行器首先根据argv[0]的值,在命令表中找到对应的redisCommand对象。
这个对象记录了命令相关的细节,比如允许参数多少,实现函数指针,对该命令的标识符,以及一些统计信息。
image-20200826114220363服务器先利用这些对命令进行检查,如果检查失败了,则返回一个错误,如果打开了监视器,就会把要执行的命令和参数等消息发给监视器。
检查完毕之后,就调用执行命令的相关函数,得到回复之后会保存在客户端状态的输出缓冲区里面。
执行结束之后还有一些特殊任务,有统计慢查询,修改链接的统计信息,aof写入到AOF缓冲区里面,复制命令到其它从服务器。
最后套接字变为可写状态的时候,把输出缓冲区里面的数据返回给客户端。
- serverCron函数详细作用?
- 更新缓存服务器的lruclock时钟,算每个key的lru值并不是实时的,而是这个值减去每个key的lru的值。
- info中的一些统计信息。
- 处理sigterm信号,在退出redis之前做相关的操作,比如RDB持久化。
- 关闭无用客户端连接。
- 抽查部分key,并删除过期的部分key。
- 将延迟的FGREWRITEAOF执行。
- 将AOF缓冲区的内容写入AOF文件。
网友评论