Netty的底层原理

目录

Netty简介

BIO的Acceptor线程模型

AIO的Proactor模型

NIO的I/O多路复用模型

基于buffer

Netty线程模型

事件驱动模型


Netty简介

Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。

JDK原生NIO程序的问题

JDK原生也有一套网络应用程序API,但是存在一系列问题,主要如下:

 

  • NIO的类库和API繁杂,使用麻烦,你需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等
  • 需要具备其它的额外技能做铺垫,例如熟悉Java多线程编程,因为NIO编程涉及到Reactor模式,你必须对多线程和网路编程非常熟悉,才能编写出高质量的NIO程序
  • 可靠性能力补齐,开发工作量和难度都非常大。例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常码流的处理等等,NIO编程的特点是功能开发相对容易,但是可靠性能力补齐工作量和难度都非常大
  • JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。官方声称在JDK1.6版本的update18修复了该问题,但是直到JDK1.7版本该问题仍旧存在,只不过该bug发生概率降低了一些而已,它并没有被根本解决

 

Netty主要特点有:

  • 设计优雅
  • 使用方便
  • 高性能
  • 安全
  • 社区活跃,不断更新

 

BIO的Acceptor线程模型

同步阻塞IO

服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。如果是基于多线程的模式来的话,就是Acceptor线程模型

 

AIO的Proactor模型

异步非阻塞IO

服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理

 

NIO的I/O多路复用模型

同步非阻塞IO

 

 

Netty的IO线程NioEventLoop由于聚合了多路复用器Selector,可以同时并发处理成百上千个客户端连接。当线程从某客户端Socket通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道

 

由于读写操作都是非阻塞的,这就可以充分提升IO线程的运行效率,避免由于频繁I/O阻塞导致的线程挂起,一个I/O线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞I/O一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

 

基于buffer

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

在NIO中, 抛弃了传统的 I/O流, 而是引入了Channel和Buffer的概念. 在NIO中, 只能从Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel。

基于buffer操作不像传统IO的顺序操作, NIO 中可以随意地读取任意位置的数据

public class FileChannelDemo1 {

  public static void main(String[] args) throws Exception {
    
    // 构造一个传统的文件输出流
    FileOutputStream out = new FileOutputStream("F:\\development\\tmp\\hello.txt");
    
    // 通过文件输出流获取到对应的FileChannel,以NIO的方式来写文件
    FileChannel  channel  = out.getChannel();
     
    // 将数据写入到Buffer中
    ByteBuffer  buffer  = ByteBuffer.wrap("hello world".getBytes());
    
    // 通过FileChannel管道将Buffer中的数据写到输出流中去,持久化到磁盘中去
    channel.write(buffer);
    channel.close();
    out.close();
  
   }
  
}

 

Netty线程模型

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

  • MainReactor负责客户端的连接请求,并将请求转交给SubReactor
  • SubReactor负责相应通道的IO读写请求
  • 非IO请求(具体逻辑处理)的任务则会直接写入队列,等待worker threads进行处理

这里引用Doug Lee大神的Reactor介绍:Scalable IO in Java里面关于主从Reactor多线程模型的图

 

事件驱动模型

通常,我们设计一个事件处理模型的程序有两种思路

  • 轮询方式

线程不断轮询访问相关事件发生源有没有发生事件,有发生事件就调用事件处理逻辑。

  • 事件驱动方式

发生事件,主线程把事件放入事件队列,在另外线程不断循环消费事件列表中的事件,调用事件对应的处理逻辑处理事件。事件驱动方式也被称为消息通知方式,其实是设计模式中观察者模式的思路。

 

参考文章:

https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247485766&idx=1&sn=eb1358a67aa342fcb9f641d3e9867489&chksm=fba6e145ccd1685317508361e4a3802232fe3765bda8028e04a9c533599aa0858e28f0e329c3&mpshare=1&scene=23&srcid=#rd

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值