Reactor模型

在Web服务中,处理Web请求时一般有两种体系,一种是多线程并发模式,服务器端每接收客户端的一个请求,就开启一个独立的线程来服务;还有一种是基于事件驱动,定义一系列事件与其对应的响应函数,并将服务器端接受连接与对事件的处理分离。而Reactor模型和Proactor模型便是事件驱动模型的两种实现方式,其中Reactor主要应用于同步I/O模式,而Proactor主要用于异步I/O模式。通过使用这样的模型,能够提高服务器处理I/O的性能,因此掌握它们的用法很有必要。在阅读本文之前,可以提前了解操作系统的I/O复用概念与Redis的基础知识。关于Reactor模型,许多著名的开源项目如Redis都使用了这一模型,接下来就先介绍Reactor是什么,以及在Redis中是如何使用的。
Reactor模型是应对高并发网络I/O请求的一种技术处理方案,主要用于处理客户端和服务器端的交互过程。在这一模型中,有三类事件,简要概括为:

  • 连接事件
  • 读事件
  • 写事件

即客户端与服务器端要建立连接时的连接事件,连接建立后服务器端的读、写事件。通过这三个事件,引出了该模型中的三个重要角色:

  • acceptor
  • handler
  • reactor

它们发挥的作用如下:

  • acceptor处理连接事件,在接收连接后,创建handler来处理后续读写事件;
  • 在高并发场景下,由于读、写事件可能同时发生,因此需要reactor来负责监听和分配事件。

即有连接请求时,reactor将产生的连接事件交给acceptor处理;有读、写请求时,reactor将读、写事件交由handler处理,如下图所示:

在实现上,根据是单线程还是多线程,Reactor模型又分为3类:

  • 单Reactor单线程:accept->read->处理业务逻辑->write都在一个线程中
  • 单Reactor多线程:accept/read/write在一个线程中,业务逻辑处理在另一个线程中
  • 多Reactor多线程/进程:accept在一个线程/进程,read/write/处理业务逻辑在另一个线程/进程

无论是单线程还是多线程/进程,在实现Reactor模型时,都离不开事件驱动框架。事件处理框架是实现Reactor模型时,需要实现的代码整体控制逻辑,主要包括了两部分:

  • 事件初始化
  • 事件捕获、分发、处理的主循环

事件初始化指的是在服务器程序启动时,创建需要监听的事件模型,以及该类型对应的handler。而主循环一般使用while循环,在这个循环中,需要捕获发生的事件,判断事件类型,并且根据事件类型来调用handler处理事件,如下图所示:

在Redis中,为了实现事件驱动框架,相应的定义了事件的数据结构、框架的主循环函数、事件捕获分发函数、事件和handler注册函数。
主循环函数是aeMain函数,它实现了一个while循环,只要事件停止循环标志不为true,就会一直在这个主循环中。主循环中调用了aeProcessEvents函数,该函数主要用于事件的捕获与分发,通过查看调用关系能发现,该函数底层是借助操作系统的多路IO复用机制,在Linux下,使用的就是epoll_wait函数来等待事件,并且将准备好的事件返回给aeProcessEvents函数。其调用关系如下图所示:

在aeProcessEvents函数中,根据事件类型不同,将事件交由不同的处理函数处理。

而在主循环之前,针对每个启用的IP端口,都使用使用aeCreateFileEvent函数创建对AE_READABLE事件的监听,并注册其对应的处理函数.
for (j = 0; j < sfd->count; j++) { if (aeCreateFileEvent(server.el, sfd->fd[j], AE_READABLE, accept_handler,NULL) == AE_ERR) { ... }
而aeCreateFileEvent底层实际上是由epoll_ctl函数实现。

Redis的事件驱动框架主要就是这三个函数,首先注册事件及其对应处理函数,随后监听并捕获事件,然后使用handler处理事件。
通过使用Reactor模型,Redis能使用单线程处理高并发的I/O请求,从侧面反映出Reactor模型的优越性。在个人编程项目中,也推荐使用Reactor模型,从而提升I/O请求处理的效率。

主要参考文章:
https://zhuanlan.zhihu.com/p/95662364
极客时间的《Redis源码剖析与实战》课程

posted @   Nora_Wu  阅读(702)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示