[Switch] High Performance Network Programming threading model

Transfer from https://mp.weixin.qq.com/s/jDeA4zayOnF0GxgRci7oaA

 

In the article, " the article read high-performance network programming I / O model ", the article describes how server-based I / O model for managing connections, access to input data, are described below based on process / thread model, servers how to handle requests.

 

It should be noted that the specific choice of thread or process, more is platform and programming language.

 

Such as C language using threads and processes can (for example using Nginx process, Memcached using threads), Java language in general use threads (eg Netty), for the convenience of description, the following uses threads to describe.

 

1, 1 threading model: the traditional blocking I / O model service


<ignore_js_op>  
Features:

  • 1) blocking I / O model acquiring input data;

  • 2) Each connection requires a separate thread to complete data entry, service processing, the data returned to full operation.


Problems:

  • 1) When the number of concurrent large, you need to create a large number of threads to handle connections, system resource consumption;

  • 2) After the connection is established, if the current thread is temporarily no data to read, the thread will block on the Read operation, resulting in waste of resources thread.

 

2, threading model 2: Reactor mode

 

2.1 General Introduction

 

Traditional blocking I / 2 O drawback service model, more common are the following solutions: 

  • 1) based on I / O multiplexing pattern: a plurality of connection objects share a blocking, application only needs to wait on a blocking objects, without having to wait for all connection blocking. When a new data connection strip can be processed, the operating system informs the application program, the thread returns from blocking, service processing is started;

  • 2) Based on a thread pool thread multiplexing resources: no longer need to create a thread for each connection, connect the business after the completion of processing tasks assigned to the processing thread, a thread can handle multiple connections business.

I / O multiplexing binding thread pool, which is the basic design Reactor pattern, as shown below:


<ignore_js_op> 

Reactor pattern, refers to one or more inputs simultaneously transmitted to the service processor of the service request event driven processing model. 

 

服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor 模式也叫 Dispatcher 模式。

 

即 I/O 多了复用统一监听事件,收到事件后分发(Dispatch 给某进程),是编写高性能网络服务器的必备技术之一。

Reactor 模式中有 2 个关键组成:

 

  • 1)Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。 它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人;

  • 2)Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。

 

根据 Reactor 的数量和处理资源池线程的数量不同,有 3 种典型的实现:

  • 1)单 Reactor 单线程;

  • 2)单 Reactor 多线程;

  • 3)主从 Reactor 多线程。


下面详细介绍这 3 种实现方式。

2.2单 Reactor 单线程

 

<ignore_js_op>



 

其中,Select 是前面 I/O 复用模型介绍的标准网络编程 API,可以实现应用程序通过一个阻塞对象监听多路连接请求,其他方案示意图类似。

方案说明:

  • 1)Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发;

  • 2)如果是建立连接请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后的后续业务处理;

  • 3)如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应;

  • 4)Handler 会完成 Read→业务处理→Send 的完整业务流程。

 

优点:模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成。

 

缺点:性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈。

 

可靠性问题,线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。

 

使用场景:客户端的数量有限,业务处理非常快速,比如 Redis,业务处理的时间复杂度 O(1)。

 

2.3单 Reactor 多线程


<ignore_js_op>

方案说明:

  • 1)Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发;

  • 2)如果是建立连接请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后续的各种事件;

  • 3)如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应;

  • 4)Handler 只负责响应事件,不做具体业务处理,通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理;

  • 5)Worker 线程池会分配独立的线程完成真正的业务处理,如何将响应结果发给 Handler 进行处理;

  • 6)Handler 收到响应结果后通过 Send 将响应结果返回给 Client。

 

优点:可以充分利用多核 CPU 的处理能力。

 

缺点:多线程数据共享和访问比较复杂;Reactor 承担所有事件的监听和响应,在单线程中运行,高并发场景下容易成为性能瓶颈。

 

2.4主从 Reactor 多线程

 

<ignore_js_op>

针对单 Reactor 多线程模型中,Reactor 在单线程中运行,高并发场景下容易成为性能瓶颈,可以让 Reactor 在多线程中运行。

方案说明:

  • 1)Reactor 主线程 MainReactor 对象通过 Select 监控建立连接事件,收到事件后通过 Acceptor 接收,处理建立连接事件;

  • 2)Acceptor 处理建立连接事件后,MainReactor 将连接分配 Reactor 子线程给 SubReactor 进行处理;

  • 3)SubReactor 将连接加入连接队列进行监听,并创建一个 Handler 用于处理各种连接事件;

  • 4)当有新的事件发生时,SubReactor 会调用连接对应的 Handler 进行响应;

  • 5)Handler 通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理;

  • 6)Worker 线程池会分配独立的线程完成真正的业务处理,如何将响应结果发给 Handler 进行处理;

  • 7)Handler 收到响应结果后通过 Send 将响应结果返回给 Client。

优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。

 

父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。

 

这种模型在许多项目中广泛使用,包括 Nginx 主从 Reactor 多进程模型,Memcached 主从多线程,Netty 主从多线程模型的支持。

2.5小结

 

3 种模式可以用个比喻来理解:(餐厅常常雇佣接待员负责迎接顾客,当顾客入坐后,侍应生专门为这张桌子服务)

  • 1)单 Reactor 单线程,接待员和侍应生是同一个人,全程为顾客服务;

  • 2)单 Reactor 多线程,1 个接待员,多个侍应生,接待员只负责接待;

  • 3)主从 Reactor 多线程,多个接待员,多个侍应生。


Reactor 模式具有如下的优点:

  • 1)响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;

  • 2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;

  • 3)可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;

  • 4)可复用性,Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性。

 

3、线程模型2:Proactor 模型

 

在 Reactor 模式中,Reactor 等待某个事件或者可应用或者操作的状态发生(比如文件描述符可读写,或者是 Socket 可读写)。

 

然后把这个事件传给事先注册的 Handler(事件处理函数或者回调函数),由后者来做实际的读写操作。

其中的读写操作都需要应用程序同步操作,所以 Reactor 是非阻塞同步网络模型。

 

如果把 I/O 操作改为异步,即交给操作系统来完成就能进一步提升性能,这就是异步网络模型 Proactor。

<ignore_js_op> 
Proactor 是和异步 I/O 相关的,详细方案如下:

  • 1)Proactor Initiator 创建 Proactor 和 Handler 对象,并将 Proactor 和 Handler 都通过 AsyOptProcessor(Asynchronous Operation Processor)注册到内核;

  • 2)AsyOptProcessor 处理注册请求,并处理 I/O 操作;

  • 3)AsyOptProcessor 完成 I/O 操作后通知 Proactor;

  • 4)Proactor 根据不同的事件类型回调不同的 Handler 进行业务处理;

  • 5)Handler 完成业务处理。


可以看出 Proactor 和 Reactor 的区别:

  • 1)Reactor 是在事件发生时就通知事先注册的事件(读写在应用程序线程中处理完成);

  • 2)Proactor 是在事件发生时基于异步 I/O 完成读写操作(由内核完成),待 I/O 操作完成后才回调应用程序的处理器来进行业务处理。

 

Theoretically Proactor higher than the Reactor efficiency, asynchronous I / O more full DMA (Direct Memory Access, direct memory access) advantage.

But Proactor has the following disadvantages: 

  • 1) Programming complexity due to initialization and Event asynchronous operation flow are separated from each other is completed in time and space, and therefore more complex to develop asynchronous applications. Applications may also be due to reverse flow control becomes more difficult to Debug;

  • 2) memory usage, buffer must remain in a read or write operation period of time to live, may result in continued uncertainty, and each concurrent operations are required to have separate caches, compared Reactor mode, Socket ready to read or write before, it is not required to open up the cache;

  • 3) Operating systems supported under Windows by IOCP to achieve a true asynchronous I / O, while the Linux system, Linux 2.6 was introduced, the current asynchronous I / O is not perfect.

 

Therefore, to achieve high concurrency in network programming under Linux are based on Reactor-based model.

Guess you like

Origin www.cnblogs.com/yi-mu-xi/p/11198944.html