Netty框架

Netty框架:Reactor 模式的一种实现

Netty是一个高性能、事件驱动的NIO框架,基于JAVA NIO提供的API实现。它提供了对TCP、UDP和文件传输的支持,Netty的所有IO操作都是非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

 

Reactor模式首先是事件驱动的,有一个或者多个并发输入源,有一个Server Handler和多个Request Handlers,这个Service Handler会同步的将输入的请求多路复用的分发给相应的Request Handler。

Reator模式的实现:单线程模型、多线程模型、主从模型。

在web服务中涉及的基本操作:read request、decode request、process service、encod reply、send reply等。

 

 

Netty的线程模型是Reactor模型的变种,那就是去掉线程池的第三种形式的变种,这也是Netty NIO的默认模式。Netty中Reactor模式的参与者主要有下面一些组件:

1)Selector

2)EventLoopGroup/EventLoop

3)ChannelPipeline

Selector即为NIO中提供的SelectableChannel多路复用器,充当着demultiplexer信号分离器的角色。

 

EventLoopGroup/EventLoop

Netty采用了串行化设计理念,从消息的读取、编码以及后续Handler的执行,始终都由IO线程EventLoop负责,这就意味着整个流程不会进行线程上下文的切换,数据也不会面临被并发修改的风险。这也解释了为什么Netty线程模型去掉了Reactor主从模型中线程池。

 

EventLoopGroup是一组EventLoop的抽象,EventLoopGroup提供next接口,可以总一组EventLoop里面按照一定规则获取其中一个EventLoop来处理任务,在Netty服务器编程中需要BossEventLoopGroup和WorkerEventLoopGroup两个EventLoopGroup来进行工作。通常一个服务端口即一个ServerSocketChannel对应一个Selector和一个EventLoop线程,也就是说BossEventLoopGroup的线程数参数为1。BossEventLoop负责接收客户端的连接并将SocketChannel交给WorkerEventLoopGroup来进行IO处理。

EventLoop的实现充当Reactor模式中的分发(Dispatcher)的角色。

 

ChannelPipeline

ChannelPipeline其实是担任着Reactor模式中的请求处理器角色。

ChannelPipeline的默认实现是DefaultChannelPipeline,DefaultChannelPipeline本身维护着一个用户不可见的tail和head的ChannelHandler,他们分别位于链表队列的头部和尾部。ChannelHandler有两个重要的接口,ChannelInBoundHandler和ChannelOutBoundHandler。

ChannelInBoundHandler对从客户端发往服务器的报文进行处理,一般用来执行半包/粘包,解码,读取数据,业务处理等;ChannelOutBoundHandler对从服务器发往客户端的报文进行处理,一般用来进行编码,发送报文到客户端。

ChannelPipeline会根据不同的IO事件类型来找到相应的Handler来处理,同时链表队列是责任链模式的一种变种,自上而下或自下而上所有满足事件关联的Handler都会对事件进行处理。

 

 

Netty中buffer的特点:

1)读写指针分离。在ByteBuffer中,读写指针都是position,而在ByteBuf中,读写指针分别为readerIndex和writerIndex。

2)零拷贝

  • Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。
  • Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象,用户可以像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。

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

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

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

  • Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。

3)引用计数与池化技术

  • 在Netty中,Netty自己根据引用计数法去实现了内存的管理。Netty对于Buffer的使用都是基于直接内存(DirectBuffer)实现的,大大提高I/O操作的效率,然而DirectBuffer和HeapBuffer相比之下除了I/O操作效率高之外还有一个天生的缺点,即对于DirectBuffer的申请相比HeapBuffer效率更低,因此Netty结合引用计数实现了PolledBuffer,即池化的用法,当引用计数等于0的时候,Netty将Buffer回收致池中,在下一次申请Buffer的某个时刻会被复用。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值