Netty实战与源码剖析(三)——Netty线程模型

简介: Netty实战与源码剖析(三)——Netty线程模型

1 线程模型基本介绍


不同的线程模式,对于程序的性能有很大的影响,Netty为何具有如此高的性能,很大程度上是得益于Netty采用的线程模型。


目前主流存在的线程模型有两种:


传统阻塞IO模型

Reactor模型

然而根据Reactor的数量和处理资源线程的数量不同,又可以将Reactor模型分为三种:


单Reactor 单线程

单Reactor 多线程

主从Reactor 多线程


Netty基于主从Reactor多线程模型做了一定的改进,其中主从Reactor多线程模型有多个Reactor。


1.1 传统阻塞IO模型


工作原理图:


939c8d954d324874ac5b725a9020f470.png

模型特点:


采用阻塞IO模式获取输入的数据

每个连接都要独立的线程来完成数据的输入、业务处理、数据的输出返回

问题分析:


当并发度很大,就会创建大量的线程,占用很大的系统开销

当连接创建后,如果当前线程暂时没有数据可读,该线程会阻塞在read操作,造成线程资源的浪费


解决方案:


基于IO复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象等待,无需阻塞等待所有连接。当某个连接有数据可用时,操作系统通知应用程序,线程从阻塞状态返回,处理业务逻辑。


基于线程池复用线程资源:不必再为每个连接创建一个线程,将连接完成后的业务处理交给线程,这样可以使得线程池中的每一个线程都可以处理多个连接的业务逻辑。


1.2 Reactor模式


上述说的IO复用模型结合线程池机制,就形成了Reactor模式。


工作原理图:


image.png


模型特点:


Reactor模式是通过一个或多个输入同时传递给服务处理器的模式,基于事件驱动

服务端程序处理连接的多个请求,并把请求分派给相应的处理线程,故Reactor模式也叫Dispatcher模式

Reactor模式使用IO复用模型,监听事件,收到事件后,分发给某个线程或进程,这也是网络服务器高并发处理的关键


核心组件:


Reactor:其实就是上图中的ServiceHandler

Handler:其实就是上图中处理线程的EventHandler


1.3 单Reactor单线程模式


前面的博客中,Java NIO编程其实就是一种单Reactor单线程,Selector相当于Reactor,得到SelectKey后的操作其实就是在一个线程中完成的,这就是一个Handler。


优点:模型简单,无多线程、线程通信、上下文切换、锁竞争等问题


缺点


性能低,只用了一个线程,无法完全发挥多核CPU的性能

可用性低,线程若意外终止,或进入死循环,导致整个通信模块不可用


使用场景:客户端数量有限,业务处理快速等


1.4 单Reactor多线程模式


和单Reactor单线程模式比较类似,不同的地方在于,当Reactor收到事件,如果是连接事件,则交给一个特定的线程处理连接后的业务;如果不是连接时间,则由Reactor分发到不同的Handler,但Handler只负责相应事件,不做具体的业务处理,只是通过read读取数据后,交给worker线程池进行处理业务,worker线程池会分配一个线程来处理业务,并将结果返回给Handler,Handler再返回结果给客户端。


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


缺点


多线程数据共享和访问较为复杂,线程安全问题;

Reactor是单线程中运行的,处理所有的事件监听和相应,高并发下有性能瓶颈


1.5 主从Reactor多线程模式


Reactor主线程MainReactor对象通过select监听连接事件,收到连接事件后,则交给一个特定的线程处理连接后的业务;如果是其他事件,MainReactor会将事件分配给从线程的SubReactor对象,然后SubReactor将事件分发到不同的Handler,但Handler只负责相应事件,不做具体的业务处理,只是通过read读取数据后,交给worker线程池进行处理业务,worker线程池会分配一个线程来处理业务,并将结果返回给Handler,Handler再返回结果给客户端。


优点:父线程与子线程的数据交互简单,职责明确,父线程只需要接受新连接,子线程则完成后续的业务逻辑处理;父子线程数据交互简单,主线程只需要把非连接的事件传递给子线程,子线程无需返回数据


缺点:复杂度高


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


2 Netty线程模型


如同所示:

image.png


Netty 抽象出两组线程池:BossGroup 和 WorkerGroup,也可以叫做 BossNioEventLoopGroup 和 WorkerNioEventLoopGroup。每个线程池中都有 NioEventLoop 线程。BossGroup 中的线程专门负责和客户端建立连接,WorkerGroup 中的线程专门负责处理连接上的读写。BossGroup 和 WorkerGroup 的类型都是 NioEventLoopGroup。


NioEventLoopGroup 相当于一个事件循环组,这个组中含有多个事件循环,每个事件循环就是一个 NioEventLoop。


NioEventLoop 表示一个不断循环的执行事件处理的线程,每个 NioEventLoop 都包含一个 Selector,用于监听注册在其上的 Socket 网络连接(Channel)。


NioEventLoopGroup 可以含有多个线程,即可以含有多个 NioEventLoop。


每个 BossNioEventLoop 中循环执行以下三个步骤:


select:轮训注册在其上的 ServerSocketChannel 的 accept 事件(OP_ACCEPT 事件)

processSelectedKeys:处理 accept 事件,与客户端建立连接,生成一个 NioSocketChannel,并将其注册到某个 WorkerNioEventLoop 上的 Selector 上

runAllTasks:再去以此循环处理任务队列中的其他任务


每个 WorkerNioEventLoop 中循环执行以下三个步骤:


select:轮训注册在其上的 NioSocketChannel 的 read/write 事件(OP_READ/OP_WRITE 事件)

processSelectedKeys:在对应的 NioSocketChannel 上处理 read/write 事件

runAllTasks:再去以此循环处理任务队列中的其他任务


在以上两个processSelectedKeys步骤中,会使用 Pipeline(管道),Pipeline 中引用了 Channel,即通过 Pipeline 可以获取到对应的 Channel,Pipeline 中维护了很多的处理器(拦截处理器、过滤处理器、自定义处理器等)。

相关文章
|
3月前
|
编解码 网络协议 API
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
Netty运行原理问题之Netty的主次Reactor多线程模型工作的问题如何解决
|
23天前
|
并行计算 JavaScript 前端开发
单线程模型
【10月更文挑战第15天】
|
25天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
16 1
|
2月前
|
消息中间件 存储 NoSQL
剖析 Redis List 消息队列的三种消费线程模型
Redis 列表(List)是一种简单的字符串列表,它的底层实现是一个双向链表。 生产环境,很多公司都将 Redis 列表应用于轻量级消息队列 。这篇文章,我们聊聊如何使用 List 命令实现消息队列的功能以及剖析消费者线程模型 。
98 20
剖析 Redis List 消息队列的三种消费线程模型
|
1月前
|
NoSQL Redis 数据库
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快
本文解释了Redis为什么采用单线程模型,以及为什么Redis单线程模型的效率和速度依然可以非常高,主要原因包括Redis操作主要访问内存、核心操作简单、单线程避免了线程竞争开销,以及使用了IO多路复用机制epoll。
47 0
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快
|
1月前
|
安全 调度 C#
STA模型、同步上下文和多线程、异步调度
【10月更文挑战第19天】本文介绍了 STA 模型、同步上下文和多线程、异步调度的概念及其优缺点。STA 模型适用于单线程环境,确保资源访问的顺序性;同步上下文和多线程提高了程序的并发性和响应性,但增加了复杂性;异步调度提升了程序的响应性和资源利用率,但也带来了编程复杂性和错误处理的挑战。选择合适的模型需根据具体应用场景和需求进行权衡。
|
2月前
|
存储 机器人 Linux
Netty(二)-服务端网络编程常见网络IO模型讲解
Netty(二)-服务端网络编程常见网络IO模型讲解
|
1月前
|
消息中间件 NoSQL 关系型数据库
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
【多线程-从零开始-捌】阻塞队列,消费者生产者模型
23 0
|
3月前
|
编解码 NoSQL Redis
(十一)Netty实战篇:基于Netty框架打造一款高性能的IM即时通讯程序
关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的IM聊天程序。
|
3月前
|
前端开发 网络协议
Netty实战巅峰:从零构建高性能IM即时通讯系统,解锁并发通信新境界
【8月更文挑战第3天】Netty是一款高性能、异步事件驱动的网络框架,适用于开发高并发网络应用,如即时通讯(IM)系统。本文将指导你利用Netty从零构建高性能IM程序,介绍Netty基础及服务器/客户端设计。服务器端使用`ServerBootstrap`启动,客户端通过`Bootstrap`连接服务器。示例展示了简单的服务器启动过程。通过深入学习,可进一步实现用户认证等功能,打造出更完善的IM系统。
151 1