Netty

作者: byamao1 | 来源:发表于2019-05-28 15:55 被阅读0次

Linux背景

流:阻塞模式、非阻塞模式
R/W方式演进:

[流在阻塞模式]
通过I/O事件来同步写入和读取进程

[非阻塞忙轮询]
流切换为非阻塞模式。
缺点:如果所有的流都没有数据,那么只会白白浪费CPU。

[非阻塞轮询]
引入select/poll代理来监听I/O事件。
在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中醒来,于是我们的程序就会轮询一遍所有的流。
缺点:O(n)的无差别轮询复杂度。处理的流越多,无差别轮询时间就越长。

[epoll] NIO
epoll会把哪个流发生了怎样的I/O事件通知我们。
复杂度降低到了O(1)。

http://www.importnew.com/24794.html

BIO NIO AIO

BIO : 同步并阻塞,服务器实现模式为一个连接一个线程
NIO : 同步非阻塞,服务器实现模式为一个请求一个线程
AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理
https://blog.csdn.net/skiof007/article/details/52873421

几种线程职责(实际中可能1个线程有多个职责)

  • 处理accept事件Thread
  • IO Thread:负责R/W数据
  • Data Handler Thread:负责对数据进一步处理

一般的处理流程

  • Socket连接请求事件(accept)处理
  • 等待客户端数据就绪
  • R/W 操作
  • handle data

首先要明确一点:一次客户端连接周期中,是可以有多次的请求。BIO与NIO的区别不是在于对于socket连接请求事件处理这步的处理上,而是在于等待客户端数据就绪这步:

BIO的阻塞与NIO的非阻塞体现在IO Thread R/W socket上:
BIO而言,在该IO Thread对socket的就绪状态获取方式是阻塞的。例如读取时,reader.readLine()包含了就绪状态获取和数据读取2步,如果没有就绪则一直处理线程是阻塞
NIO而言,selector.selectedKeys()获取有注册事件到达的channel(具体实现通过Linux的select/epoll),IO Thread处理的都是就绪状态的socket(因此IO Thread可以非阻塞读取数据)

推荐结合代码看看。

NIO一个重要的特点是:socket主要的读、写、注册和接收函数,在等待就绪阶段都是非阻塞的,真正的I/O操作是同步阻塞的(消耗CPU但性能非常高)。
NIO是一种同步非阻塞的I/O模型,也是I/O多路复用的基础。
https://www.jianshu.com/p/1ccbc6a348db

在理解了NIO的基础上,看AIO,区别在于AIO是等读写过程完成后再去调用回调函数。

NIO是同步非阻塞的
(同步指的是netty通过select/poll向IO查询数据包是否到达)
AIO是异步非阻塞的
(异步指的是操作系统通知进程,数据包被复制到哪个内存区域,去读取)
https://my.oschina.net/hosee/blog/615269

I/O流 vs Buffer

基于buffer
传统的I/O是面向字节流或字符流的,以流式的方式顺序地从一个Stream 中读取一个或多个字节, 因此也就不能随意改变读取指针的位置。

NIO中, 抛弃了传统的 I/O流, 而是引入了Channel 和 Buffer的概念. 在NIO中, 只能从Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel。
基于buffer操作不像传统IO的顺序操作, NIO 中可以随意地读取任意位置的数据
https://juejin.im/post/5bea1d2e51882523d3163657

事件分发器模式

事件分发器的两种模式称为:Reactor和Proactor。
Reactor模式是基于同步I/O的,而Proactor模式是基于异步I/O的。
https://www.jianshu.com/p/1ccbc6a348db

Reactor模型有3个变种:

  • 单Reactor单线程
  • 单Reactor多线程
  • 主从Reactor多线程

特别说明的是: 虽然Netty的线程模型基于主从Reactor多线程,借用了MainReactor和SubReactor的结构,但是实际实现上,SubReactor和Worker线程在同一个线程池中。
https://juejin.im/post/5bea1d2e51882523d3163657

Reactor模型.png
https://www.jianshu.com/p/1ccbc6a348db

Netty 与 Reactor模式对应

结构对应:
NioEventLoop ———— Initiation Dispatcher
Selector ———— Synchronous EventDemultiplexer
ChannelHandler ———— Event Handler
具体的ChannelHandler的实现 ———— ConcreteEventHandler

模式对应:
Netty服务端使用了多Reactor线程模式
mainReactor ———— bossGroup(NioEventLoopGroup) 中的某个NioEventLoop
subReactor ———— workerGroup(NioEventLoopGroup) 中的某个NioEventLoop
acceptor ———— ServerBootstrapAcceptor
ThreadPool ———— 用户自定义线程池
https://www.jianshu.com/p/1ccbc6a348db

Netty

Netty的工作架构图.png
https://juejin.im/post/5bea1d2e51882523d3163657
总结:
1个NioEventLoopGroup包含多个NioEventLoop;
每个NioEventLoop有属于自己的1个Selector和1个taskQueue
Boss Group包含1个NioEventLoopGroup
Worker Group可以包含多个NioEventLoopGroup
(修正)NioEventGroup应写为NioEventLoopGroup

有个问题:数据怎么写回客户端
A: 实际上当客户机有消息发送过来时会调用channelRead0(ChannelHandlerContext ctx, String msg)这个方法,处理完发来的数据后直接向channel(ChannelHandlerContext ctx)写回即可
https://www.jianshu.com/p/222fe9f2a564

Summary

  • 无论什么情况,read/write操作本身都是‘阻塞’的。阻塞/非阻塞区别在于read/write操作之前的就绪状态是如何得到的
  • NIO是一种同步非阻塞的I/O模型。Netty基于NIO

Main Ref

https://www.jianshu.com/p/1ccbc6a348db
https://juejin.im/post/5bea1d2e51882523d3163657
https://blog.zhenlanghuo.top/2017/05/21/IO%E4%B8%AD%E7%9A%84%E5%90%8C%E6%AD%A5%E5%BC%82%E6%AD%A5%E3%80%81%E9%98%BB%E5%A1%9E%E9%9D%9E%E9%98%BB%E5%A1%9E/

Netty源码(占小狼):
https://www.jianshu.com/p/e577803f0fb8
https://www.jianshu.com/p/6b48196b5043
https://www.jianshu.com/p/1ad424c53e80

相关文章

网友评论

      本文标题:Netty

      本文链接:https://www.haomeiwen.com/subject/cgsjqqtx.html