Libevent源码剖析之reactor

news/2024/10/19 20:38:08/

1 简介

    reactor 是一种事件驱动的并发处理模式,常用于网络服务器和事件循环系统中。它主要的功能是通过单线程或者多线程处理I/O操作,避免阻塞,并且能够高效处理大量并发的事件。

    one loop per thread or process,以下摘自 reactor 原文:

  • The reactor software design pattern is an event handling strategy that can respond to many potential service requests concurrently. The pattern's key component is an event loop, running in a single thread or process, which demultiplexes incoming requests and dispatches them to the correct request handler.[1]

    By relying on event-based mechanisms rather than blocking I/O or multi-threading, a reactor can handle many concurrent I/O bound requests with minimal delay.[2] A reactor also allows for easily modifying or expanding specific request handler routines, though the pattern does have some drawbacks and limitations.[1]

    With its balance of simplicity and scalability, the reactor has become a central architectural element in several server applications and software frameworks for networking. Derivations such as the multireactor and proactor also exist for special cases where even greater throughput, performance, or request complexity are necessary.[1][2][3][4]

    在此列出多路复用相关文章: 

Libevent源码剖析之iocp-CSDN博客 

Libevent源码剖析之reactor-CSDN博客

Libevent源码剖析之epoll-CSDN博客

Libevent源码剖析之poll-CSDN博客

Libevent源码剖析之select-CSDN博客

1.1 工作组件

  • 事件源:系统中会有多个事件源,例如网络套接字、文件描述符、定时器等,触发各种事件,如读、写、超时等。

  • 事件分离器 (Demultiplexer):事件分离器(通常是系统调用,如select(), poll(), 或epoll())负责监控这些事件源,并将发生事件的事件源标记出来。

  • 事件分派器 (Dispatcher):Reactor设计中的核心部分,事件分派器接收到事件分离器传来的事件后,将其分发给相应的处理器(Event Handler)处理。每个事件对应一个预定义的事件处理函数。

  • 事件处理器 (Event Handler):事件处理器包含事件处理的逻辑。当事件分派器传递某个事件时,事件处理器负责处理该事件,例如处理网络连接请求,或者读取某个套接字中的数据。

1.2 工作流程

  • 等待事件发生:reactor首先通过系统调用(如select()或epoll())等待某些I/O事件发生。
  • 事件分离:当某个I/O事件发生时,事件分离器(select()或epoll())返回一组已经就绪的事件。
  • 事件处理:事件分派器检查哪些事件已经准备好,并将这些事件交由对应的事件处理器进行处理。
  • 继续监听:事件处理结束后,reactor重新回到等待事件的状态,重复此过程。

1.3 单线程 vs 多线程

  • 单线程 reactor:适合处理简单的并发情况,整个流程都是在一个线程中进行,因此不需要考虑线程同步问题。然而,当处理时间较长的操作时,可能会阻塞其他事件的处理,开源软件比如redis缓存数据库。
  • 多线程 reactor:将I/O事件和实际事件处理分开。reactor在单线程中监听和分派事件,而将事件处理分配给工作线程(Thread Pool)。这样可以避免阻塞,提高并发处理能力,开源软件如memcached缓存数据库。

1.4 reactor 和 proactor

  • reactor同步非阻塞模型,事件循环等待事件发生,当某个事件准备好后,交给处理器进行处理。
  • proactor 则是异步模型,事件发生时由内核完成操作(如I/O操作),然后通知应用程序进行进一步处理。

2 原理

2.1 组件图

    reactor相关组件图如下:

2.2 序列图

    各组件工作序列图:

3 reactor

3.1 classic service design

    解释说明:

  • 此为同步阻塞模式;
  • 逐个处理client请求,当1个client连接成功后,read => decode => compute => encode => send,如此流程处理完毕,方可处理下一个client请求;
  • 以client为并发粒度,粒度大,并发响应延迟高,不适合高并发场景,适用于mysql这种应用场景;
  • handler可以是一个线程或进程;

3.2 single reactor per thread

     解释说明:

  •  1个线程1个reactor,1个acceptor,所有client的IO事件收集&分发&处理,均在此线程处理;
  • 此线程持有1个acceptor,专门用来并发处理client的connect请求;
  • 所有的IO操作计算任务,均在此reactor线程处理;
  • 并发粒度为event,而非client,并发粒度低,并且能很好的解决数据乱序问题,但不能发挥多CPU核心优势,适用于redis这种内存数据库;
  • 若设计为multiple single reactor per thread,如此便可解决此模式的缺陷,既能发挥多CPU核心优势,又能适用于IO密集型,非常灵活,但若是多进程下需解决accept惊群问题,如nginx;

3.3 single reactor + work thread poll

    解释说明:

  • 此模式在single reactor per thread基础之上,将IO操作和event业务逻辑处理分离开来,由reactor线程充当acceptor和所有IO操作职责,所有计算任务由thread poll来处理;
  • 当1个client请求过来,reactor的acceptor accept客户端的connect请求,然后read数据完毕,将fd和业务逻辑处理handler封装起来,投递到queued tasks中,从thread poll中分配1个线程来处理,处理完毕,再回到reactor线程发送给client,如此循环;
  • reactor线程thread poll通过队列来通信,前者处理IO操作,后者处理业务逻辑
  • 缺点:acceptor和所有IO操作,均由reactor线程处理,瓶颈在此;
  • 优点:将IO操作交由reactor线程业务逻辑交由thread poll,可充分发挥多CPU核心优势,也可很好的解决数据乱序问题,适用于高并发场景;
  • 可通过设计为multiple single reactor + work thread poll来解决以上问题;

3.4 multiple reactor + thread poll 

    解释说明:

  • single reactor + work thread poll不同之处在于,此模式将reactor线程根据职责,一分为二,分离出mainReactor线程subReactor线程,前者专门负责并发处理client的connect请求,后者则负责处理所有IO操作;
  • 其他均与single reactor + work thread poll模式一致,不再赘述;

4 参考文献

4.1 reactor wiki

https://en.wikipedia.org/wiki/Reactor_pattern#Structure

4.2 reactor pattern

​​​​​​Scalable IO in Java


http://www.ppmy.cn/news/1540334.html

相关文章

泛微E-Cology系统 CptInstock1Ajax SQL注入漏洞复现

0x01 产品描述: ‌ 泛微E-Cology是一款专为中大型组织设计的数字化办公系统,旨在创建高效协同的办公环境。‌ 该系统集成了智能化、平台化和全程数字化的特点,通过智能语音交互、与其他异构系统的集成以及电子印章、电子签名等技术的应用&a…

STM32--基于STM32F103C8T6的OV7670摄像头显示

本文介绍基于STM32F103C8T6实现的OV7670摄像头显示设计(完整资源及代码见文末链接) 一、简介 本文实现的功能:基于STM32F103C8T6实现的OV7670摄像头模组实时在2.2寸TFT彩屏上显示出来 所需硬件: STM32F103C8T6最小系统板、OV76…

Linux-第一章

目录 1.操作系统概述: 学习目标: Ⅰ.了解操作系统的作用: -硬件和软件: -操作系统: Ⅱ.了解常见的操作系统: 2.Linux初识: 学习目标: Ⅰ.了解Linux系统的诞生: …

Gee引擎架设教程:Gee引擎人形怪物设置,MonUseItems配置文件讲解

人形怪物设置说明:1、在Envir目录下增加MonUseItems目录,放置怪的配置文件,见MonUseItems目录2、Monster.DB范例:战士;150;19;0;198;0;100;5000;0;10;10;0;0;0;0;88;45;450;1;0;450;5000;法师;150;19;0;198;0;100;5000;0;10;10;0;…

网页前端开发之HTML入门篇:链接标签 a

链接标签 a <a>是HTML的链接标签&#xff0c;其标签内容的是链接的标题&#xff0c; 它是通过属性来设置链接的地址(URL)。 属性说明 href&#xff1a;其值是链接的地址(URL)&#xff1b;target&#xff1a;其值是指定该如何打开链接&#xff1b; 选项值_self&#xf…

nginx的负载均衡配置和重定向

upstream_check模块 配置文件详情 upstream cluster1{server 10.0.0.4:80 weight1 max_fails3 fail_timeout30s;server 10.0.0.5:80 weight1 max_fsils3 fsil_tomeout;check interval3000 rise2 fall5 timeout1000 typehttp;check interval3000 rise2 fall5 timeout1000…

CTF学习——攻防世界

查看网页源代码的方法 第一种&#xff1a;F12 第二种&#xff1a;鼠标右键→查看网页源代码 第三种&#xff1a;ctrlshiftI 第四种&#xff1a;ctrlU 第五种&#xff1a;在url前面加view-source: 第六种&#xff1a;将网页另存为.html文件&#xff0c;然后用文本编辑器打…

MySQL查看当前客户端连接数的方法

每当有客户端连接到 MySQL 时&#xff0c;MySQL 会为该连接创建一个新的线程来处理所有与该连接相关的查询和操作。所以通过查看MySQL当前的连接线程数量就可以知道有多少客户端连接到MySQL。 方法一 Threads_connected 仅显示活跃的客户端连接数 SHOW STATUS LIKE Threads_…