自学内容网 自学内容网

Libevent源码剖析之reactor

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


原文地址:https://blog.csdn.net/weixin_41255248/article/details/142914833

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!