欢迎访问shiker.tech

请允许在我们的网站上展示广告

您似乎使用了广告拦截器,请关闭广告拦截器。我们的网站依靠广告获取资金。

Netty中的网络通信模型
(last modified Aug 13, 2023, 7:38 PM )
by
侧边栏壁纸
  • 累计撰写 176 篇文章
  • 累计创建 61 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Netty中的网络通信模型

橙序员
2023-08-13 / 0 评论 / 0 点赞 / 229 阅读 / 1,690 字 / 正在检测百度是否收录... 正在检测必应是否收录...
文章摘要(AI生成)

Reactor模型是一种常用的网络通信框架,包括了单线程模型、线程池模型和多线程模型。在单线程模型中,每个通信对端会与一个线程绑定,该线程负责处理通信的各项操作。但在高并发场景下,会造成性能下降,因此引入了线程池模型,将单线程替换为线程池,大大提高了系统的性能。而在多线程模型中,连接操作与IO操作分开处理,并使用不同的线程池,进一步提升了系统的性能。Netty-Server采用了多线程模型,其中线程池由EventLoopGroup扮演,每个EventLoop与一个线程绑定,用于处理Channel与Server之间的操作。Netty-Client则采用了线程池模型,与Server建立连接后无需区分连接请求与IO请求。另外,Proactor模型是一种异步非阻塞I/O的网络通信模型,与Reactor模型相比,具有不同的特点。

Reactor模型

现在的网络通信框架,大多数都是基于Reactor模型进行设计和开发的,Netty也不例外。

Reactor单线程模型

Reactor单线程模型,指的是当前的Sever会为每一个通信对端形成一个Channel,而所有这些Channel都会与一个线程相绑定,该线程用于完成它们间的所有通信处理。该线程需要完成的操作有:

  • 若当前为Server,则该线程需要接收并处理Client的连接请求
  • 若当前为Client,则该线程需要向Server发起连接
  • 读取通信对端的消息
  • 向通信对端发送消息

image-20230813192335069

Reactor线程池模型

Reactor单线程模型中使用一个线程处理所有通信对端的所有请求,在高并发场景中会严重影响系统性能。

所以,就将单线程模型中的这一个线程替换为了一个线程池。大大提高了系统性能。

image-20230813192417636

Reactor多线程池模型

若请求连接的并发量是数以百万计的,且IO操作还比较耗时,此时的Server即使采用的是Reactor线程池模型,系统性能也会急剧下降。

此时,可以将连接操作与IO操作分开处理,形成Reactor的多线程模型。

当客户端通过处理连接请求的Channel连接上Server后,系统会为该客户端再生成一个子Channel专门用于处理该客户端的IO请求。这两类不同的Channel连接着两类不同的线程池。而线程池中的线程数量,可以根据需求分别设置。提高了系统性能

image-20230813192452952

Netty-Server的Reactor模型

image-20230813192701156

Netty-Server采用了多线程模型。不过线程池是由EventLoopGroup充当。EventLoopGroup中的每一个EventLoop都绑定着一个线程,用于处理该Channel与当前Server间的操作。一个Channel只能与一个EventLoop绑定,但一个EventLoop可以绑定多个Channel。即Channel与EventLoop间的关系是n:1。

Netty-Client的Reactor模型

image-20230813192737879

Netty-Client采用的是线程池模型。因为其只需要与Server连接一次即可,无需区分连接请求与IO请求。

Proactor模型

在高性能的网络通信设计中,有两个比较著名的网络通信模型Reactor和Proactor模式,其中Reactor模式属于同步非阻塞I/O的网络通信模型,而Proactor运属于异步非阻塞I/O的网络通信模型。

Reactor模型的IO

对于Reactor模型,其IO属于同步非阻塞IO。

下面以channel发起读操作请求为例来分析整个执行过程。

当channel的执行线程发起了read()调用后,其会向selector注册了OPS_READ事件,然后该线程会不停的查看该事件是否就绪。

当selector接收到这个注册后,其就会不停的查看该channel所关联的网卡缓存中是否具有了数据。当selector轮询到该channel的网卡缓存中具有了数据后,该读操作就绪。

此时该线程就查看到了就绪,会发起systemcall,将网卡缓存中的数据读取到userbuffer中。这些操作完成后,会再执行read()后面的逻辑。整个执行过程,该线程未发生阻塞。所以Reactor模型是“同步非阻塞IO”模型

Proactor模型的IO

对于Proactor模型,其IO属于异步非阻塞IO。

下面仍以channel发起读操作请求为例来分析整个执行过程。

当channel的执行线程调用了异步的read()操作后,其会继续执行read()后的逻辑。而该read()会将本次操作注册到一个Proactor实例中,注册本次操作关注的事件为ReadComplete。一个channel的所有IO操作共享一个Proactor实例。或者说,一个Proactor实例处理同一channel中所有的IO请求。这个Proactor实例是在channel创建时完成的初始化。每个Proactor实例具有一个绑定的线程,用于执行相关IO操作。

当Proactor实例接收了read()操作的注册后,其会为网络缓存注册一个监听。若网卡缓存中有了数据,则马上通过DMA控制将数据写入到userbuffer中。一旦数据写入userbuffer完成,则该IO操作完毕,产生ReadComplete事件,此时会将该事件写入到Proactor所维护的一个队列。Proactor实例会将队列中的事件发送给各个IO调用者线程,以使他们触发相应的回调。

当前read()操作的调用线程无需阻塞等待read()操作的完成,而是直接执行后面的逻辑。由于read()操作本身是由另外一个线程来执行,所以Proactor模型是“异步非阻塞IO”模型。

Reactor中的selector是一种“事件分离器”的实现。在Proactor中不存在事件分离器,但存在一个Proactor实例。该实例会根据不同的IO操作,监听不同的内容。例如,本例为网卡缓存注册了监听。

Proactor优缺点

  • Proactor在处理高耗时IO时的性能要高于Reactor,但对于低耗时IO的执行效率提升并不明显。因为Reactor的同步性(IO也是调用线程来处理)导致其处理高耗时IO时性能会极低(IO操作的后续逻辑无法执行)。但对于低耗时IO,异步也不会比同步快太多。同时异步还需要线程切换等操作,会使异步的优越性无法体现。

  • Proactor的异步性使其并发处理能力要强于Reactor。

  • Proactor的实现逻辑复杂,编码成本较Reactor要高很多。

  • Proactor的异步依赖于操作系统对于异步的支持。若操作系统对异步的支持不好,Proactor的性能还不如Reactor。

Netty为何不用AIO?

Netty4是NIO的,其网络通信模型采用的是Reactor。而Netty5是AIO的,其网络通信模型采用的是Proactor。但该版本已经被不再维护。主要原因还是Linux目前对于异步的支持不完善,导致其执行效率很低。

0

评论区