前言
对于Netty框架的学习
前置知识点:线程模型
目录
线程模型概述
在学习Netty线程模型之前,先要搞清楚各个线程模型的发展过程,再进行Netty线程模型的了解
现有的线程模型:
- 传统阻塞IO线程模型(也就是BIO)
- Reactor 模式
其中Reactor模式根据Reactor的数量和线程的数量可以分为三种:
- 单Reactor单线程
- 单Reactor多线程
- 主从Reactor多线程
Netty框架是基于主从Reactor多线程模型进行改进(多个主Reactor)
传统阻塞IO线程模型
传统阻塞IO也就是Java BIO
很简单,就是一个连接一个线程的模型
每一个连接都创建一个线程去处理,而且当完成连接,读取数据时,如果没有数据可读会阻塞线程
传统阻塞IO线程模型缺点:
- 对于高并发的环境,会创建很多线程,系统开销大
- 阻塞IO模式会造成线程浪费
Reactor基本思想
Reactor模式是对传统阻塞IO模型的一种改进
其中基本思想有两个:
-
基于 I/O 复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象等待,无需阻塞等待所有连接。当某个连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理
-
基于线程池复用线程资源:不必再为每个连接创建线程,将连接完成后的业务处理任务分配给线程进行处理,一个线程可以处理多个连接的业务。
I/O 复用模型与线程池复用线程资源(基本思想):
Reactor模式:对于多个Client请求,Reactor使用IO复用监听事件ServiceHandler处理多个请求(基于事件驱动),然后分发给某个线程
核心组件:
- Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。
它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人; - Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor
通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作
Reactor模式让我想起了Java IO 的发展:
伪异步IO就是线程池复用线程,NIO基于IO复用模型
这种思想体现在其他网络编程中
单Reactor单线程
前面写的群聊系统其实就是一个单Reactor单线程模式
我们的群聊系统中:
设置了Selector的select()方法负责监听(起到了Reactor的作用)
ServerSocketChannel监听端口号,连接实现accept方法
对于监听的事件进行了处理(使用的是方法,而不是创建对象)
handler对象中的处理方法read就是key.isReadable()判断处理事件
而且服务器仅在一个main线程中执行
优缺点:
优点:模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成
缺点:
-
性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈
-
可靠性问题,线程意外终止,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障
适用场景:客户端数目有限,业务处理快的情况
单Reactor多线程
相对于单Reactor单线程,引进了一个线程池,分出线程来处理业务,Reactor线程仅负责接收连接和响应事件,具体事件有线程池分配的线程处理
具体的步骤:
- 多个客户端发出连接请求
- Reactor主线程中Reactor对象的select方法监控客户端请求事件,再由dispatch分发事件到相应的处理对象
- 如果是请求连接事件,分发到Acceptor,Acceptor通过accept方法处理连接请求,然后创建一个handle对象处理接下来会发生的事件(类似ServerSocket)
- 如果不是请求连接事件,dispatch分发到相应的handle对象中
- handle对象仅响应事件,通过read读取数据后,分发到Worker线程池相应的线程处理业务
- Worker线程池会分配线程处理业务,然后将结果返回handle
- handle对象send结果给客户端
大致的步骤就是这样,单Reactor多线程仅多了一个线程池,将业务的处理分割开
优缺点:
优点:可以充分利用到多核CPU
缺点:多线程数据共享和访问比较复,而且对于单Reactor单线程的性能问题并没有解决, Reactor 处理所有的事件的监听和响应,一样在高并发会出现性能问题
主从Reactor多线程
主从Reactor多线程模式与单Reactor多线程的区别在与将Reactor分为Reactor主线程和Reactor子线程
它将服务器分成了3层:Reactor主线程、Reactor子线程(可以多个)、线程池
这就解决了性能问题,Reactor主线程仅负责监听连接与连接事件,其他事件的处理交给Reactor子线程
具体步骤:
- 客户端发出连接请求
- Reactor主线程的MainReactor对象通过select方法监听连接事件,当有连接事件时,通过Acceptor对象处理连接
- Acceptor处理完连接后,MainReactor将连接分配给SubReactor
- SubReactor将连接加入连接队列,select方法监听事件,并创建handle处理事件
- 当有事件发生,SubReactor调用handle对象处理事件
- handle对象通过read读取数据,分发给Worker线程池处理业务
- Worker线程池分配独立的线程处理业务,并将结果返回给handle
- handle将结果send给客户端
- 如果Client过多,MainReactor可以关联多个SubReactor
优缺点:
优点:
- 父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。
- 父线程与子线程的数据交互简单,Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。
缺点:编程复杂度较高
总结
- 线程模型可以分为传统阻塞IO模型与Reactor模型
- Reactor模型的基本思想是:IO复用模型和线程池复用线程资源
- Reactor分为3种:单Reactor单线程模型、单Reactor多线程模型、主从Reactor多线程模型
- Netty是对主从Reactor多线程模型的修改,即可以多个Reactor主线程
来源:CSDN
作者:Ctrl c+v
链接:https://blog.csdn.net/key_768/article/details/104735876