Netty介绍


介绍Netty前我们先介绍一下BIO、NIO、AIO

IO模型

1、BIO

同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
在这里插入图片描述

BIO通信模型的服务端,通常由一个独立的 Acceptor线程负责监听客户端的连接,多个客户端连接会启动多个线程处理。
在 Java 虚拟机中,线程是宝贵的资源,线程的创建和销毁成本很高,除此之外,线程的切换成本也是很高的。如果并发访问量增加会导致线程数急剧膨胀可能会导致线程堆栈溢出、创建新线程失败等问题,最终导致进程宕机或者僵死,不能对外提供服务。

2、NIO

NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架
在这里插入图片描述
NIO 包含下面几个核心的组件
• Channel(通道)
NIO 通过Channel(通道) 进行读写。
通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。

• Buffer(缓冲区)

在这里插入图片描述
IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。
在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。

• Selector(选择器)
NIO有选择器,而BIO没有。
选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。线程之间的切换对于操作系统来说是昂贵的。 因此,为了提高系统效率选择器是有用的。

3、AIO

AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。

总结
BIO与NIO一个比较重要的不同,是我们使用BIO的时候往往会引入多线程,每个连接一个单独的线程;而NIO则是使用单线程或者只使用少量的多线程,多个连接共用一个线程。
在这里插入图片描述
AIO与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。

事件驱动模型

• 轮询方式,线程不断轮询访问相关事件发生源有没有发生事件,有发生事件就调用事件处理逻辑。
• 事件驱动方式,发生事件,主线程把事件放入事件队列,在另外线程不断循环消费事件列表中的事件,调用事件对应的处理逻辑处理事件。事件驱动方式也被称为消息通知方式,其实是设计模式中观察者模式的思路。
在这里插入图片描述
主要包括 4 个基本组件:
• 事件队列(event queue):接收事件的入口,存储待处理事件。
• 分发器(event mediator):将不同的事件分发到不同的业务逻辑单元。
• 事件通道(event channel):分发器与处理器之间的联系渠道。
• 事件处理器(event processor):实现业务逻辑,处理完成后会发出事件,触发下一步操作。

可以看出,相对传统轮询模式,事件驱动有如下优点:
• 可扩展性好,分布式的异步架构,事件处理器之间高度解耦,可以方便扩展事件处理逻辑。
• 高性能,基于队列暂存事件,能方便并行异步处理事件

线程模型

1、线程模型1:传统阻塞 I/O 服务模型

在这里插入图片描述
特点:
• 1)采用阻塞式 I/O 模型获取输入数据;
• 2)每个连接都需要独立的线程完成数据输入,业务处理,数据返回的完整操作。

存在问题:
• 1)当并发数较大时,需要创建大量线程来处理连接,系统资源占用较大;
• 2)连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在 Read 操作上,造成线程资源浪费。

2、线程模型2:Reactor 模式

针对传统阻塞 I/O 服务模型的 2 个缺点,比较常见的有如下解决方案:
• 1)基于 I/O 复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理;
• 2)基于线程池复用线程资源:不必再为每个连接创建线程,将连接完成后的业务处理任务分配给线程进行处理,一个线程可以处理多个连接的业务。
I/O 复用结合线程池,这就是 Reactor 模式基本设计思想,如下图:
在这里插入图片描述
Reactor 模式,是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。

Reactor 模式中有 2 个关键组成:
• 1)Reactor:Reactor 在一个单独的线程中运行,负责监听和分发事件,分发给适当的处理程序来对 IO 事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人;
• 2)Handlers:处理程序执行 I/O 事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际官员。Reactor 通过调度适当的处理程序来响应 I/O 事件,处理程序执行非阻塞操作。
根据 Reactor 的数量和处理资源池线程的数量不同,有 3 种典型的实现:

• 1)单 Reactor 单线程;
• 2)单 Reactor 多线程;
• 3)主从 Reactor 多线程。

2.1单 Reactor 单线程

在这里插入图片描述
• 1)Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 Dispatch 进行分发;
• 2)如果是建立连接请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后的后续业务处理;
• 3)如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应;
• 4)Handler 会完成 Read→业务处理→Send 的完整业务流程。

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

缺点:性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致性能瓶颈。
使用场景:客户端的数量有限,业务处理非常快速,比如 Redis,业务处理的时间复杂度 O(1)。

2.2单 Reactor 多线程

在这里插入图片描述

方案说明:

• 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.3主从 Reactor 多线程

在这里插入图片描述
针对单 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、线程模型3:Proactor 模型

在 Reactor 模式中,Reactor 等待某个事件或者可应用或者操作的状态发生(比如文件描述符可读写,或者是 Socket 可读写)。
然后把这个事件传给事先注册的 Handler(事件处理函数或者回调函数),由后者来做实际的读写操作。
其中的读写操作都需要应用程序同步操作,所以 Reactor 是非阻塞同步网络模型。
如果把 I/O 操作改为异步,即交给操作系统来完成就能进一步提升性能,这就是异步网络模型 Proactor。
在这里插入图片描述
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 操作完成后才回调应用程序的处理器来进行业务处理。

理论上 Proactor 比 Reactor 效率更高,异步 I/O 更加充分发挥 DMA(Direct Memory Access,直接内存存取)的优势。
但是Proactor有如下缺点:
• 1)编程复杂性,由于异步操作流程的事件的初始化和事件完成在时间和空间上都是相互分离的,因此开发异步应用程序更加复杂。应用程序还可能因为反向的流控而变得更加难以 Debug;
• 2)内存使用,缓冲区在读或写操作的时间段内必须保持住,可能造成持续的不确定性,并且每个并发操作都要求有独立的缓存,相比 Reactor 模式,在 Socket 已经准备好读或写前,是不要求开辟缓存的;
• 3)操作系统支持,Windows 下通过 IOCP 实现了真正的异步 I/O,而在 Linux 系统下,Linux 2.6 才引入,目前异步 I/O 还不完善。
因此在 Linux下实现高并发网络编程都是以 Reactor 模型为主。

Netty

一、什么是Netty

netty是jboss提供的一个java开源框架,netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可用性的网络服务器和客户端程序。也就是说netty是一个基于nio的编程框架,使用netty可以快速的开发出一个网络应用。
1、 使用NIO的IO模型,对NIO的API进行了封装
2、 使用异步事件驱动
3、 使用主从 Reactor 多线程的线程模型(多路复用)

在这里插入图片描述
4、 零拷贝
Netty的接收和发送数据采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝
Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象进行一次操作
Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题
5、 异步处理,Netty中的IO操作是异步的,包括Bind、Write、Connect等操作会简单的返回一个channelFuture调用者并不能立刻获得结果,而是通过Future-Listener机制,用户可以方便的主动获取或通过通知机制来获得IO操作结果。

功能特性

在这里插入图片描述
Netty 功能特性如下:
• 传输服务,支持 BIO 和 NIO。
• 容器集成,支持 OSGI、JBossMC、Spring、Guice 容器。
• 协议支持,HTTP、Protobuf、二进制、文本、WebSocket 等一系列常见协议都支持。还支持通过实行编码解码逻辑来实现自定义协议。
• Core 核心,可扩展事件模型、通用通信 API、支持零拷贝的 ByteBuf 缓冲对象。

Netty应用

1、分布式系统中RPC调用,如Dubbo
2、游戏行业
3、大数据领域,经典的Hadoop 的高性能通信和序列化组件Avro的RPC框架,默认采用Netty 进行跨界点通信
4、消息队列通信,如RocketMQ

使用Netty自定义通讯协议

1、 实现一个server
2、 实现一个client
3、 实现一个encoder
4、 实现一个decoder

在这里插入图片描述
参考
https://blog.csdn.net/m0_38109046/article/details/89449305

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值