netty原理

Netty简介

       Netty是一个高性能、异步事件驱动的NIO框架,基于JAVA NIO提供的API实现。它提供了对TCP、UDP文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。 作为当前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于Netty的NIO框架构建。

netty原理分析

NIO通讯服务端步骤:

1、创建ServerSocketChannel,为它配置非阻塞模式

2、绑定监听,配置TCP参数,录入backlog大小等

3、创建一个独立的IO线程,用于轮询多路复用器Selector

4、创建Selector,将之前的ServerSocketChannel注册到Selector上,并设置监听标识位SelectionKey.ACCEPT

5、启动IO线程,在循环体中执行Selector.select()方法,轮询就绪的通道

6、当轮询到处于就绪的通道时,需要进行判断操作位,如果是ACCEPT状态,说明是新的客户端介入,则调用accept方法接受新的客户端。

7、设置新接入客户端的一些参数,并将其通道继续注册到Selector之中。设置监听标识等

8、如果轮询的通道操作位是READ,则进行读取,构造Buffer对象等

9、更细节的还有数据没发送完成继续发送的问题

零拷贝技术原理

      “零拷贝”是指计算机操作的过程中,CPU不需要为数据在内存之间的拷贝消耗资源。而它通常是指计算机在网络上发送文件时,不需要将文件内容拷贝到用户空间(User Space)而直接在内核空间(Kernel Space)中传输到网络的方式。Netty的“零拷贝”主要体现在三个方面:

        1、Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝读取直接从“堆外直接内存”,不像传统的堆内存和直接内存拷贝,ByteBufAllocator 通过ioBuffer分配堆外内存

       2、Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象,用户可以像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer,Netty允许我们将多段数据合并为一整段虚拟数据供用户使用,而过程中不需要对数据进行拷贝操作,组合Buffer对象,避免了内存拷贝,ChannelBuffer接口:Netty为需要传输的数据制定了统一的ChannelBuffer接口,使用getByte(int index)方法来实现随机访问,使用双指针的方式实现顺序访问

       3、Netty主要实现了HeapChannelBuffer,ByteBufferBackedChannelBuffer,与Zero Copy直接相关的CompositeChannelBuffer类

        CompositeChannelBuffer类的作用是将多个ChannelBuffer组成一个虚拟的ChannelBuffer来进行操作为什么说是虚拟的呢,因为CompositeChannelBuffer并没有将多个ChannelBuffer真正的组合起来,而只是保存了他们的引用,这样就避免了数据的拷贝,实现了Zero Copy,内部实现。其中readerIndex既读指针和writerIndex既写指针是从AbstractChannelBuffer继承而来的。components是一个ChannelBuffer的数组,他保存了组成这个虚拟Buffer的所有子Buffer。indices是一个int类型的数组,它保存的是各个Buffer的索引值。lastAccessedComponentId是一个int值,它记录了最后一次访问时的子Buffer ID。CompositeChannelBuffer实际上就是将一系列的Buffer通过数组保存起来,然后实现了ChannelBuffer 的接口,使得在上层看来,操作这些Buffer就像是操作一个单独的Buffer一样。

         Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。Linux中的sendfile()以及Java NIO中的FileChannel.transferTo()方法都实现了零拷贝的功能,而在Netty中也通过在FileRegion中包装了NIO的FileChannel.transferTo()方法实现了零拷贝

Netty 的 Zero-copy 体现在如下几个个方面:

1、Netty 提供了 CompositeByteBuf 类, 它可以将多个 ByteBuf 合并为一个逻辑上的 ByteBuf, 避免了各个 ByteBuf 之间的拷贝。

2、通过 wrap 操作, 我们可以将byte[] 数组、ByteBuf、ByteBuffer等包装成一个 Netty ByteBuf 对象, 进而避免了拷贝操作。

3、ByteBuf 支持 slice 操作,因此可以将 ByteBuf 分解为多个共享同一个存储区域的ByteBuf, 避免了内存的拷贝。

4、通过 FileRegion 包装的FileChannel.tranferTo 实现文件传输, 可以直接将文件缓冲区的数据发送到目标 Channel, 避免了传统通过循环 write 方式导致的内存拷贝问题。

Netty的三层网络架构进行设计

第一层:Reactor通信调度层。该层的主要职责就是监听网络的连接和读写操作,负责将网络层的数据读取到内存缓冲区中,然后触发各种网络事件,例如连接创建、连接激活、读事件、写事件等,将这些事件触发到Pipeline中,再由Pipeline充当的职责链来进行后续的处理。

第二层:职责链Pipeline层。负责事件在职责链中有序的向前(后)传播,同时负责动态的编排职责链。Pipeline可以选择监听和处理自己关心的事件。

第三层:业务逻辑处理层,一般可分为两类:a. 纯粹的业务逻辑处理,例如日志、订单处理。b. 应用层协议管理,例如HTTP(S)协议、FTP协议等。

        影响网络服务通信性能的主要因素有:网络I/O模型、线程(进程)调度模型和数据序列化方式。在网络I/O模型方面,Netty采用基于非阻塞I/O的实现,底层依赖的是JDKNIO框架的Selector。在线程调度模型方面,Netty采用Reactor线程模型。

常用的Reactor线程模型有三种,分别是:

a、Reactor单线程模型:Reactor单线程模型,指的是所有的I/O操作都在同一个NIO线程上面完成。对于一些小容量应用场景,可以使用单线程模型。

b、Reactor多线程模型:Rector多线程模型与单线程模型最大的区别就是有一组NIO线程处理I/O操作。主要用于高并发、大业务量场景。

c、主从Reactor多线程模型:主从Reactor线程模型的特点是服务端用于接收客户端连接的不再是一个单独的NIO线程,而是一个独立的NIO线程池。利用主从NIO线程模型,可以解决一个服务端监听线程无法有效处理所有客户端连接的性能不足问题。Netty线程模型并非固定不变的,它可以支持三种Reactor线程模型。

在数据序列化方面,影响序列化性能的主要因素有:

a、序列化后的码流大小(网络带宽占用)。

b、序列化和反序列化操作的性能(CPU资源占用)。

c、并发调用时的性能表现:稳定性、线性增长等。

        Netty默认提供了对GoogleProtobuf二进制序列化框架的支持,但通过扩展Netty的编解码接口,可以实现其它的高性能序列化框架,例如Avro、Thrift的压缩二进制编解码框架。

netty 为啥要进行拆包粘包处理

  简单点描述,netty底层通讯是走的TCP协议,接收到的都是字节流,然后以字节字节队列的形式存在缓存堆里面。而TCP协议每一次最大接收的字节长度是1024个字节,一旦超过这个长度,那么就会出现一下各种形式

        所以在字节长度超过1024的时候,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。

netty基于以上问题也提供了一些组件,比如:

1、固定长度的拆包器 FixedLengthFrameDecoder,每个应用层数据包的都拆分成都是固定长度的大小

2、行拆包器 LineBasedFrameDecoder,每个应用层数据包,都以换行符作为分隔符,进行分割拆分

3、分隔符拆包器 DelimiterBasedFrameDecoder,每个应用层数据包,都通过自定义的分隔符,进行分割拆分

4、基于数据包长度的拆包器 LengthFieldBasedFrameDecoder,将应用层数据包的长度,作为接收端应用层数据包的拆分依据。按照应用层数据包的大小,拆包。这个拆包器,有一个要求,就是应用层协议中包含数据包的长度

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。