设计良好的网路服务器&Reactor模型

317 阅读5分钟

一、设计良好的网络服务器

在这个多核时代,服务端网络编程如何选择线程模型呢?
赞同libevent作者的观点:one loop per thread is usually a good model,这样多线程服务端编程的问题就转化为如何设计一个高效且易于使用的event loop,然后每个线程run一个event loop就可以了。(当然线程间的同步、互斥少不了,还有其他的耗时事件需要起另外的线程来做)

event loop是non-blocking网络编程的核心,在现实生活中,non-blocking几乎总是和IO-multiplexing一起使用,原因有两点:

  • 没有人真的会用轮询(busy-pooling)来检查某个non-blocking IO操作是否完成,这样态浪费CPU资源了
  • IO-multiplexing一般不能和blocking IO用在一起,因为blocking IO中read()/write()/accept()/connect()都有可能阻塞当前线程,这样线程就没办法处理其他socket上的IO事件了。

所以,当我们提到non-blocking的时候,实际上指的是non-blocking+IO-multiplexing,单用其中任何一个都没有办法很好的实现功能。

epoll+fork不如epoll+pthread?

强大的nginx服务器采用了epoll+fork模型作为网络模块的架构设计,实现了简单好用的负载方法,使各个网络fork进程不会忙的越忙、闲的越闲,并且通过引入一把乐观锁解决了该模型导致的服务器惊群的现象,功能十分强大。

二、Reactor模型

反应器设计模式是用于处理服务请求的事件处理模式由一个或多个输入并发地交付给服务处理程序。服务处理程序然后将传入的请求解复用,并将它们同步地分发到相关的请求处理程序。

1. Single Reactor模型

重要组件:Event事件、Reactor反应堆、Demultiplex事件分发器、Evanthandler事件处理器

image.png

在整个的基于Reactor模型的网络服务请在交互的时候,首先,我们把事件注册到反应堆上,也就是说,应用程序对这个事件感兴趣,请求反应堆帮忙来监听它所感兴趣的事件,并且在这个事件发生的时候调用相应的预置的回调Handler,向反应堆注册事件,就是把这个事件event和对应的handler(一个event对应一个Evanthandler) 都给到reactor反应堆。反应堆存储着事件event事件以及事件处理的集合,可以添加更多选项,比如说,事件添加的时间,事件响应的时间等等。Reactor反应堆就维护了event及handler集合。
reactor反应堆根据epoll_ctrl对事件分发器进行事件的设置,调整,添加新的事件,修改已有的事件,删除添加的事件,然后启动反应堆,反应堆的后端就会驱动事件分发器的启动,多路复用,就是在开启epoll__wait,因为事件分发器在开启epoll_wait之前,reactor已经调用相应的方法把应用程序注册过来的事件进行添加,调整,删除,多路复用开启,epoll_wai开始,整个服务器处于阻塞的状态等待新用户的连接,或者是已连接用户的读写事件。
如果epoll_wait有监听到新的事件的产生,那么多路复用分发器就会把这个分发的事件给反应堆返回,因为事件发生了,在reactor模型里,就要调用事件的处理器。
多路复用分发器在监听到事件分发的时候,不知道事件对应的处理器在哪,都是在反应堆维护的,所以就把分发的事件返回给反应堆。
reactor就会找到event对应的Evanthandler(一般用map表),调用具体的event handler,来读取read用户的请求,然后进行解码,因为在通信的时候数据是有序列化反序列化的,然后进行处理、计算,然后进行打包、编码,也就是数据的序列化,send发送到网络上给用户响应。

总结:

  • Event时间:包含了我们在编写网络程序的时候,具体的fd、读或者写、或者其他的信息,然后handler注册到Reactor上
  • Reactor反应堆:维护了Event与Handler集合,然后通过相应的方法可以给多路复用分发器添加、调整、删除事件
  • Demultiplex事件分发器:反应堆的启动就会驱动事件分发器的启动来监听线程事件,事件发生以后会把事件链表返回给Reactor,Reactor就会在map表里面找到对应的eventhandler事件处理器来调用。
  • eventhandler事件处理器: 读取用户事件的请求read,反序列化(解码),业务逻辑处理计算,对处理的结果编码序列化,send给用户返回一个响应。

2. muduo库的Multiple Reactors模型

image.png 在这里边,相当于是:图中所谓的反应堆reactor,实际上都是代表着Demultiplex事件分发器,由他们监听具体事件的发生,调用相应事件的回调。

image.png reactor主要存储的是事件和事件的处理器,仅此而已。
但是这张图上的reactor实际上是reactor和Demultiplex事件分发器的合二为一。
多路事件分发器想象成epoll,mainreactor相当于I/O线程的eventloop,主要做的是新用户的连接accept,listen fd有事件写入,就accept取出已连接用户的fd,然后派送到具体的工作线程上。

subreactor线程专门做已连接用户的读写事件处理
如果再有耗时的I/O操作,比如说传输文件,就单独再起一个线程去处理耗时的I/O操作