韩顺平netty学习笔记

I/O 型基本说明

1) I/O 型简单的理解 就是 用什么样的通 行数据的发送和接收,很 大程度上决定 序通信的
2) Java共支持3种网络编程 /IO 模式: BIO NIO AIO
3) Java BIO : 同步并阻 ( 传统阻塞型 ) 服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开 简单示意图
4) Java NIO 同步非阻塞 ,服务器实现模式为一个线程处理多个请求 ( 连接 ) ,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求就进行处理 简单示意图
5) Java AIO(NIO.2) 异步非阻塞 AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用
 

BIONIOAIO适用场景分析

1) BIO 方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中, JDK1.4 以前的唯一选择,但程 序简 单易理解
2) NIO 方式适用于 连接数目多且连接比较短 (轻操作)的架构,比如聊天服务器 幕系统,服务器间通讯等。编 程比较复杂, JDK1.4 开始支持
3) AIO 方式使用于 连接数目多且连接比较长 (重操作)的架构,比如相册服务器,充分调用 OS 参与并发操作,编程比较复杂, JDK7 开始支持
 
l Java NIO 基本介绍
1) Java NIO 全称 java non-blocking IO ,是指 JDK 提供的新 API 。从 JDK1.4 开始, Java 提供 了一 系列改进的输入 / 输出的新特性,被统称为 NIO( New IO ) ,是 同步非阻塞
2) NIO 相关类都被放在 java.nio 包及子包下,并且对原 java.io 包中的很多类进行改写
3) NIO 有三大核心部分: Channel( 通道 ) Buffer( 缓冲区 ) , Selector( 选择器 )
4) NIO 是 面 冲区 ,或者面向 编程的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使 用它可以提供 非阻塞 式的高伸缩性网
5)Java NIO的非阻塞模式,使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而 不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。【 后面有案例说明
6) 俗理解: NIO 是可以做到用一个线程来处理多个操作的。假设有 10000 个请求过来 , 根据实际情况,可以分配 50 或者 100 个线程来处理。不像之前的阻塞 IO 那样,非得分配 10000
7) HTTP2.0 使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比 HTTP1.1 大了好几个数量级。
 
l NIO BIO 的比较
1) BIO 以流的方式处理数据,而 NIO 以块的方式处理数据 , I/O 的效率比流 I/O 高很
2) B IO 是阻 塞的, NIO 是非 阻塞
3) BIO 字节流和字符流 进行操作,而 NIO 基于 Channel( 通道 ) Buffer( 缓冲区 ) 进行操作,数 据总 是从通道读取到缓冲区中,或者从缓冲区写入到通道中。 Selector( ) 用于监听多个 通道 的事件(比如:连接请求,数据到达等),因此使用 单个线程就可以监听多个客户端
 
Buffer 基本介绍
1) Buffer 就是一个内存块 , 层是有一个数组
2) 据的读取写入是通过 Buffer, 这个和 BIO , BIO 中要么是输入流,或者是 出流 , 不能双向,但是 NIO Buffer 是可以读也可以写 , 需要 flip 方法 换channel 是双向的 , 可以返回底层操作系统的情况 , 比如Linux , 底层的操作系统通道就是双向的 .

冲区(Buffer):缓冲区本质上是一个可读写据的内存块,可以理解成是一个器对象(含数组),该对象提供了一组方法,可以更轻松地使用内存块,,缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。Channel 提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由 Buffer如图:  【后面举例说明

l(Channel) 

1)NIO的通道类似于流,但有些区别如下:
     •通道可以同时进行读写,而流只能读或者只能写
     •通道可以实现异步读写数据
     •通道可以从缓冲读数据,也可以写数据到缓冲
2)BIO 中的 stream 是单向的,例如 FileInputStream 对象只能进行读取数据的操作,而 NIO 中的通道(Channel)是双向的,可以读操作,也可以写操作。
3)Channel在NIO中是一个接口
public interface Channel extends Closeable{}
4)常用的 Channel 类有:FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel。【ServerSocketChanne 类似 ServerSocket , SocketChannel 类似 Socket】
5)FileChannel 用于文件的数据读写,DatagramChannel 用于 UDP 的数据读写,ServerSocketChannel 和 SocketChannel 用于 TCP 的数据读写。

l Selector ( 选择器 )

1)Java 的 NIO,用非阻塞的 IO 方式。可以用一个线程,处理多个的客户端连接,就会使用到Selector(选择器)
2)Selector 能够检测多个注册的通道上是否有事件发生(注意:多个Channel以事件的方式可以注册到同一个Selector),如果有事件发生,便获取事件然后针对每个事件进行相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求
3)只有在 连接/通道 真正有读写事件发生时,才会进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程
4)避免了多线程之间的上下文切换导致的开销

 零拷贝的再次理解

1) 们说零拷贝,是从 操作系统的角度来说的 。因为内核缓冲区之间,没有数据是重复的(只有 kernel buffer 有一份数 据)。
2) 拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势,例如更少的上下文切换,更少的 CPU 缓存伪共享以及无 CPU 校验和计算。

 

lJava AIO 基本介绍
1) JDK 7 引入了 Asynchronous I/O ,即 AIO 。在进行 I/O 编程中,常用到两种模式: ReactorProactor Java NIO 就是 Reactor 当有事件触发时,服务器端得到通知,进行相应的处理
2) AIO NIO2.0 ,叫做异步不阻塞的 IO AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用
3) 目前 AIO 还没有广泛应 用, Netty 也是基于 NIO, 而不是 AIO 此我们就不详解 AIO 了,有兴趣的同学可以参考 << Java 新一代网络编程模型 AIO 原理及 Linux 系统 AIO 介绍 >>  http :// www.52im.net/thread-306-1-1.html 
 
 

 

BIO

NIO

AIO

IO 模型

同步阻塞

同步非阻塞(多路复用)

异步非阻塞

编程难度

简单

复杂

复杂

可靠性

吞吐量

l 原生 NIO 存在的问题
1) NIO 的类库和 API 繁杂,使用麻烦 :需 要熟练掌握 Selector ServerSocketChannel SocketChannel ByteBuffer
2) 要具备其他的额外技 能: Java 多线程编程,因为 NIO 编程涉及到 Reactor 模式,你必须对多线程 网络 程非常熟悉,才能编写出高质量的 NIO 程序
3) 发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异 常流 的处理等 等。
4) JDK NIO Bug :例如臭名昭著的 Epoll Bug,它会导致 Selector 空轮询,最终导致 CPU 100% 。直 JDK 1.7 版本该问题仍旧存在 ,没 有被根本解决。

 

l Netty 的优点

Netty JDK 自带的 NIO API 进行了封装,解决了上述问题。

1) 计优雅:适用于各种传输类型的统一 API 阻塞和非阻塞 Socket ;基于灵活且可扩展的事件模型,可以清晰地分离关注点;高度可定制的线程模型 - 单线程,一个或多个线程 .
2) 使 用方便:详细记录的 Javadoc ,用户指南和示例;没有其他依赖项, JDK 5 Netty 3.x )或 6 Netty 4.x )就足够了
3) 高性能、吞吐量更高:延迟更低;减少资源消耗;最小化不必要的内存复制。
4) 全:完整的 SSL/TLS StartTLS 支持
5) 区活跃、不断更新:社区活跃,版本迭代周期短,发现的 Bug 可以被及时修复,同时,更多的新功能会被加入

 

目前存在的线程模型有:
1) Reactor 模式
2) 根据 Reactor 的数量和处理资源池线程的数量不同, 有 3 种典型的实现
单 Reactor 单线程;
•单 Reactor 多线程;
•主从 Reactor 多线程
4) Netty 线程模式 ( Netty 主要 基于主从 Reactor 多线程模型 做了一定的改进,其中主从 Reactor 多线程模型有多个 Reactor)
 

lReactor 模式

针对传统阻塞 I/O 服务模型的 2 个缺点,解决方案: 

1) 基于 I/O 复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象等待,无需阻塞等待所有连接。当某个连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理
Reactor 对应的叫法: 1. 反应器模式 2. 分发者模式(Dispatcher) 3. 通知者模式(notifier)
 
2) 基于线程池复用线程资源:不必再为每个连接创建线程,将连接完成后的业务处理任务分配给线程进行处理,一个线程可以处理多个连接的业务

I/O 复用结合线程池,就是 Reactor 模式基本设计思想,如图:

说明:

1) Reactor 模式,通过一个或多个输入同时传递给服务处理器的模式 ( 基于事件驱动 )
2) 服务器端程序处理传入的多个请求 , 并将它们同步分派到相应的处理线程, 因此 Reactor 模式也叫 Dispatcher 模式
3) Reactor 模式使用 IO 复用监听事件 , 收到事件后,分发给某个线程 ( 进程 ), 这点就是网络服务器高并发处理关键

Reactor 模式中 核心组成:

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

 

lReactor 单线程   方案优缺点分析:

1) 优点: 模型简单,没有多线程、进程通信、竞争的问题,全部都在一个线程中完成
2) 缺点: 性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。 Handler 在处理某个连接上的业务时,整个进程无法处理其他连接事件,很容易导致 性能瓶颈
3) 缺点: 可靠性问题 ,线程意外终止,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障
4) 使用场景: 客户端的数量有限,业务处理非常快速,比如 Redis 在业务处理的时间复杂度 O(1) 的情况

 

lReactor多线程  方案优缺点分析:

1) 优点: 可以充分的利用多核 cpu 的处理能力
2) 缺点: 多线程数据共享和访问比较复杂, reactor 处理所有的事件的监听和响应,在单线程运行, 在高并发场景容易出现性能瓶颈.
l 主从 Reactor 多线程

主从:

注意下面是多个subReactor. Main也只是处理acceptor

方案优缺点说明:

1) 优点: 父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。
2) 优点: 父线程与子线程的数据交互简单, Reactor 主线程只需要把新连接传给子线程,子线程无需返回数据。
3) 缺点: 编程复杂度较高

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

Reactor 模式具有如下的优点:

1) 响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的
2) 可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程 / 进程的 切换开销
3) 扩展性好 ,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源
4 )复用性好 Reactor 模型本身与具体事件处理逻辑无关,具有很高的复用性

 

l Netty 模型

简单版

Netty 主要基于主从 Reactors 多线程模型(如图)做了一定的改进,其中主从 Reactor 多线程模型有多个 Reactor

1) BossGroup 线程维护 Selector , 只关注 Accecpt
2) 当接收到 Accept 事件,获取到对应的 SocketChannel , 封装成 NIOScoketChannel 并注册到 Worker 线程 ( 事件循环 ), 并进行维护
3) Worker 线程监听到 selector 中通道发生自己感兴趣的事件后,就进行处理 ( 就由 handler) , 注意 handler 已经加入到通道

进阶版

Netty 主要基于主从 Reactors 多线程模型(如图)做了一定的改进,其中主从 Reactor 多线程模型有多个 Reactor

详细版

1) Netty 抽象出两组线程池 BossGroup 专门负责接收客户端的连接 , WorkerGroup 专门负责网络的读写
2) BossGroup WorkerGroup 类型都是 NioEventLoopGroup
3) NioEventLoopGroup 相当于一个事件循环组 , 这个组中含有多个事件循环 ,每一个事件循环是 NioEventLoop
4) NioEventLoop 表示一个不断循环的执行处理任务的线程, 每个 NioEventLoop 都有一个 selector , 用于监听绑定在其上的 socket 的网络通讯
5) NioEventLoopGroup 可以有多个线程 , 即可以含有多个 NioEventLoop
6) 每个 Boss NioEventLoop 循环执行的步骤有 3
1. 轮询 accept 事件
2. 处理 accept 事件 , client 建立连接 , 生成 NioScocketChannel , 并将其注册到某个 worker NIOEventLoop 上的 selector
3. 处理任务队列的任务 , 即 runAllTasks

     7) 每个 Worker NIOEventLoop 循环执行的步骤

1. 轮询 read, write 事件
2. 处理 i/o 事件, 即 read , write 事件,在对应 NioScocketChannel 处理
3. 处理任务队列的任务 , 即 runAllTasks

     8) 每个Worker NIOEventLoop  处理业务时,会使用pipeline(管道), pipeline 中包含了 channel , 即通过pipeline 可以获取到对应通道, 管道中维护了很多的 处理器

 

 

 

 

 

 

 

 

 

============

 

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值