Redis的文件事件和 I/O 多路复用机制

  众所周知,Redis是一款优秀的非关系数据库,用在对访问延迟要求较高的一些项目中。得益于Redis本身的简单性和优良的设计,其在单线程条件下达到了很高的性能指标。其中最为重要的技术是Redis中的 I/O 多路复用。

Redis中的事件

  Redis中存在两种事件,一种是服务器中通过 socket 和客户端进行通信产生的文件事件。另一种是Redis服务器中需要定时执行的操作,称为时间事件。本文重点叙述Redis在处理文件事件是所采用的多路复用技术。这也是面试时的热点问题。

事件处理器的构成

  Redis 服务器为了避免多线程并发带来的开销,但是却需要同时与许多客户端保持通信。Redis 的事件驱动过程中,aeProcessEvents() 函数会在单个线程中被循环地调用。在这个函数中主要做三个事情
step 1:通过 I/O 多路复用技术产生一个活动的套接字(文件事件),传送给文件事件分派器。aeApiPoll()
step 2:执行文件事件。读的文件事件 fe->rfileProc() 或者写文件事件 fe->wfileProc()
step 3:执行时间事件 。processTimeEvents()
Alt
  如图所示,在多个文件事件并发出现的时候 I/O多路复用程序负责监听这些套接字并向文件事件分派器指出那些套接字出现了事件。

I/O多路复用程序

  Redis 的多路复用程序的功能通过包装常见的 select、epoll、evport 和 kqueue 这些I/O复用库函数来实现。在Redis编译时将优先选择当前库内性能较好的I/O复用函数库。
Alt
  Redis在事件循环结构aeEventLoop中为每一个新套接字 fd 都申请了一个aeFileEvent结构,并且放在与 events 表中fd 对应的位置,同时将套接字 fd 使用 FD_SET 加入到 I/O 多路复用程序的监听范围之内(fd_array),并且对事件和事件处理函数进行关联。aeEventLoop如下图。
Alt
  I/O复用程序处于Redis事件机制的驱动之下。每一次事件循环,都会通过多路复用程序 aeApiPoll() 选择 AE_READABLE 或者 AE_WRITABLE 的套接字对它们进行读写操作。在这个过程中,aeApiPoll() 会在指定的时间内,使用select、epoll、evport或者kqueue等I/O多路复用库函数阻塞并且等待所有被设置为监听状态的套接字产生的文件事件。如果在指定的时间内有文件事件发生,则拿到的套接字并且添加到 aeEventLoop 的就绪表 fired 中并且设置其为 AE_READABLE 或者 AE_WRITABLE 类型,随后执行先前绑定的事件处理器(包括 AE_READABLE 类型的连接应答处理器、命令请求处理器和 AE_WRITABLE 类型的命令回复处理器) 。

一次完整的客户端和服务器连接事件

  正常运行的 Redis 服务器,负责监听的套接字放在多路复用机制监控范围内。如果这时有新的客户端发起连接,那么监听套接字会产生 AE_READABLE 事件,触发连接应答处理器。然后创建客户端的套接字,以及客户端状态,并将客户端套接字的 AE_READABLE 事件与命令请求处理器进行关联,使得客户端可以向主服务器发送命令请求。
  随后客户端发送命令请求,在多客户端并发的条件下使用I/O多路复用机制 选出产生 AE_READABLE 事件的客户端套接字。处理器读取客户端命令,然后传给相关程序执行。
  执行命令产生命令回复,为了将这些命令回复传送给客户端,服务请会将客户端套接字的 AE_WRITABLE 事件和命令回复处理器相关联。当客户端试图读取命令的回复的时候,将复用机制将产生 AE_WRITABLE 事件并触发回复处理函数,当命令回复处理器将命令回复全部写到套接字后,服务器将会解除客户端套接字的 AE_WRITABLE 事件和命令回复处理器之间的关联。

发布了5 篇原创文章 · 获赞 0 · 访问量 211

猜你喜欢

转载自blog.csdn.net/bilidi/article/details/104486839
今日推荐