首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Netty的模型演进及快速入门

BIO模型

Demo

这种模式存在的问题:

客户端的并发数与后端的线程数成1:1的⽐例,线程的创建、销毁是⾮常消耗系统资源的,随着并发量增⼤,服务端性能将显著下降,甚⾄会发⽣线程堆栈溢出等错误。

当连接创建后,如果该线程没有操作时,会进⾏阻塞操作,这样极⼤的浪费了服务器资源。

NIO模型

NIO,称之为New IO 或是 non-block IO (⾮阻塞IO),这两种说法都可以,其实称之为⾮阻塞IO更恰当⼀些。

NIO相关的代码都放在了java.nio包下,其三⼤核⼼组件: Buffer(缓冲区) 、 Channel(通道) 、Selector(选择器/多路复⽤器)

Buffer

在NIO中,所有的读写操作都是基于缓冲区完成的,底层是通过数组实现的,常⽤的缓冲区是

ByteBuffer,每⼀种java基本类型都有对应的缓冲区对象(除了Boolean类型),如:

CharBuffer、 IntBuffer、 LongBuffer等。

Channel

在BIO中是基于Stream实现,⽽在NIO中是基于通道实现,与流不同的是,通道是双向的,

既可以读也可以写。

Selector

Selector是多路复⽤器,它会不断的轮询注册在其上的Channel,如果某个Channel上发⽣读

或写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey获

取就绪Channel的集合,进⾏IO的读写操作。

可以看出, NIO模型要优于BIO模型,主要是:

通过多路复⽤器就可以实现⼀个线程处理多个通道,避免了多线程之间的上下⽂切换导致系统开销过⼤。

NIO⽆需为每⼀个连接开⼀个线程处理,并且只有通道真正有有事件时,才进⾏读写操作,这样⼤⼤的减少了系统开销。

Demo

AIO模型

AIO是asynchronous I/O的简称,是异步IO,该异步IO是需要依赖于操作系统底层的异步IO实现。

AIO的基本流程是:⽤户线程通过系统调⽤,告知kernel内核启动某个IO操作,⽤户线程返回。 kernel内核在整个IO操作(包括数据准备、数据复制)完成后,通知⽤户程序,⽤户执⾏后续的业务操作。

⽬前AIO模型存在的不⾜:

需要完成事件的注册与传递,这⾥边需要底层操作系统提供⼤量的⽀持,去做⼤量的⼯作。

Windows 系统下通过 IOCP 实现了真正的异步 I/O。但是,就⽬前的业界形式来说, Windows 系统,很少作为百万级以上或者说⾼并发应⽤的服务器操作系统来使⽤。

⽽在 Linux 系统下,异步IO模型在2.6版本才引⼊,⽬前并不完善。所以,这也是在 Linux 下,实现⾼并发⽹络编程时都是以 NIO 多路复⽤模型模式为主。

Reactor线程模型

Reactor线程模型不是Java专属,也不是Netty专属,它其实是⼀种并发编程模型,是⼀种思想,具有指导意义。⽐如, Netty就是结合了NIO的特点,应⽤了Reactor线程模型所实现的。

Reactor模型中定义的三种⻆⾊:

Reactor:负责监听和分配事件,将I/O事件分派给对应的Handler。新的事件包含连接建⽴就绪、读就绪、写就绪等。

Acceptor:处理客户端新连接,并分派请求到处理器链中。

Handler:将⾃身与事件绑定,执⾏⾮阻塞读/写任务,完成channel的读⼊,完成处理业务逻辑后,负责将结果写出channel。

Reactor单线程模型

说明:

Reactor充当多路复⽤器⻆⾊,监听多路连接的请求,由单线程完成

Reactor收到客户端发来的请求时,如果是新建连接通过Acceptor完成,其他的请求由Handler完成。

Handler完成业务逻辑的处理,基本的流程是: Read --> 业务处理 --> Send 。

这种模型的优缺点:

优点

结构简单,由单线程完成,没有多线程、进程通信等问题。

适合⽤在⼀些业务逻辑⽐较简单、对于性能要求不⾼的应⽤场景。

缺点

由于是单线程操作,不能充分发挥多核CPU的性能。

当Reactor线程负载过重之后,处理速度将变慢,这会导致⼤量客户端连接超时,超时之后往往会进⾏重发,这更加重Reactor线程的负载,最终会导致⼤量消息积压和处理超时,成为系统的性能瓶颈。

可靠性差,如果该线程进⼊死循环或意外终⽌,就会导致整个通信系统不可⽤,容易造成单

点故障。

单Reactor多线程模型

说明:

在Reactor多线程模型相⽐较单线程模型⽽⾔,不同点在于, Handler不会处理业务逻辑,只是负责响应⽤户请求,真正的业务逻辑,在另外的线程中完成。

这样可以降低Reactor的性能开销,充分利⽤CPU资源,从⽽更专注的做事件分发⼯作了,提升整个应⽤的吞吐。

但是这个模型存在的问题:

多线程数据共享和访问⽐较复杂。如果⼦线程完成业务处理后,把结果传递给主线程Reactor进⾏发送,就会涉及共享数据的互斥和保护机制。

Reactor承担所有事件的监听和响应,只在主线程中运⾏,可能会存在性能问题。例如并发百万客户端连接,或者服务端需要对客户端握⼿进⾏安全认证,但是认证本身⾮常损耗性能。

为了解决性能问题,产⽣了第三种主从Reactor多线程模型。

主从Reactor多线程模型

在主从模型中,将Reactor分成2部分:

MainReactor负责监听server socket,⽤来处理⽹络IO连接建⽴操作,将建⽴的socketChannel指定注册给SubReactor。

SubReactor主要完成和建⽴起来的socket的数据交互和事件业务处理操作。

该模型的优点:

响应快,不必为单个同步事件所阻塞,虽然Reactor本身依然是同步的。

可扩展性强,可以⽅便地通过增加SubReactor实例个数来充分利⽤CPU资源。

可复⽤性⾼, Reactor模型本身与具体事件处理逻辑⽆关,具有很⾼的复⽤性。

Netty模型

Netty模型是基于Reactor模型实现的,对于以上三种模型都有⾮常好的⽀持,也⾮常的灵活,⼀般情况,在服务端会采⽤主从架构模型

说明:

在Netty模型中,负责处理新连接事件的是BossGroup,负责处理其他事件的是WorkGroup。Group就是线程池的概念。

NioEventLoop表示⼀个不断循环的执⾏处理任务的线程,⽤于监听绑定在其上的读/写事件。

通过Pipeline(管道)执⾏业务逻辑的处理, Pipeline中会有多个ChannelHandler,真正的业务逻辑是在ChannelHandler中完成的。

Demo

服务端MyRPCServer

MyChannelInitializer

MyChannelHandler

测试⽤例

客户端

MyClientHandler

测试用例

核心组件

EventLoop、 EventLoopGroup

ChannelHandler

ChannelPipeline

Bootstrap

⼩结

------------END-----------

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20210125A02SH000?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券