Netty实现原理分析

简介: Netty实现原理分析

Netty简介


  • Netty是高性能、异步事件驱动的NIO框架 基于Java NIO提供的API实现
  • 提供了对TCP、UDP和文件传输的支持
  • Netty所有IO操作都是异步非阻塞的 通过Future-Lisener机制 用户可以方便的主动获取或者通过通知机制获得IO操作结果
  • 广泛应用互联网领域、大数据分布式计算领域、游戏行业、通信行业


Netty线程模型


Netty结合Java NIO的Selector和Reactor模式设计了高效的线程模型


Reactor模式


image.png


基于事件驱动

  • 有一个或多个并发输入源
  • 一个Server Handler
  • 多个Request Handlers


每当一个事件输入到Service Handler之后,该Service Handler会主动根据不同的Evnent类型将其分发给对应的Request Handler来处理


Reactor模式实现


Reactor单线程模型

image.png


1、一个线程可以独立处理所有的IO操作
2、既负责多路分离套接字又Accept新连接又并分发请求到处理链中
3、一些小容量应用场景,可以使用到单线程模型

但对于高负载,大并发的应用却不合适 原因是

  • 当一个NIO线程同时处理成百上千的链路,性能上无法支撑,即使NIO线程的CPU负荷达到100%,也无法完全处理消息
  • 当NIO线程负载过重后,处理速度会变慢,会导致大量客户端连接超时,超时之后往往会重发,更加重了NIO线程的负载。
  • 可靠性低,一个线程意外死循环,会导致整个通信系统不可用


Reactor多线程模型


image.png


该模型可以解决上述问题
该模型在处理链部分采用了多线程(线程池)
绝大多数场景下,该模型都能满足性能需求
但在一些特殊的应用场景下,如服务器会对客户端的握手消息进行安全认证
这类场景下,单独的一个Acceptor线程可能会存在性能不足的问题
为了解决这些问题,产生了第三种Reactor线程模型


Reactor主从模型


image.png

a、Reactor分成两部分 mainReactor负责监听server socket、accept新连接
   并将建立的socket分派给subReactor
b、subReactor负责多路分离已连接的socket
c、worker线程池完成读写网络数据,对业务处理功能
d、subReactor个数上可与CPU个数等同

弊端

  • 当系统在运行过程中,频繁的进行线程上下文切换,会带来额外的性能损耗
  • 要考虑多线程安全问题


Netty模型


Netty线程模型去掉了Reactor主从模型中线程池

为了解决上述问题 
Netty采用了串行化设计理念
从消息的读取、编码以及后续Handler的执行
始终都由IO线程EventLoop负责
这就意外着整个流程不会进行线程上下文的切换
数据也不会面临被并发修改的风险


核心组件


Selector

Selector即为NIO中提供的SelectableChannel多路复用器
充当着demultiplexer的角色


EventLoopGroup/EventLoop

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

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


ChannelPipeline

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

  • ChannelPipeline的默认实现是DefaultChannelPipeline,
  • DefaultChannelPipeline本身维护着一个用户不可见的tail和head的ChannelHandler,他们分别位于链表队列的头部和尾部。tail在更上层的部分,而head在靠近网络层的方向
  • 在Netty中关于ChannelHandler有两个重要的接口,ChannelInBoundHandler和ChannelOutBoundHandler
  • inbound可以理解为网络数据从外部流向系统内部而outbound可以理解为网络数据从系统内部流向系统外部
  • 用户实现的ChannelHandler可以根据需要实现其中一个或多个接口,将其放入Pipeline中的链表队列中,ChannelPipeline会根据不同的IO事件类型来找到相应的Handler来处理,同时链表队列是责任链模式的一种变种,自上而下或自下而上所有满足事件关联的Handler都会对事件进行处理
  • ChannelInBoundHandler对从客户端发往服务器的报文进行处理,一般用来执行半包/粘包,解码,读取数据,业务处理等
  • ChannelOutBoundHandler对从服务器发往客户端的报文进行处理,一般用来进行编码,发送报文到客户端


Buffer

  • ByteBuf读写指针
在ByteBuffer中,读写指针都是position
而在ByteBuf中,读写指针分别为readerIndex和writerIndex
直观看上去ByteBuffer仅用了一个指针就实现了两个指针的功能,节省了变量
但是当对于ByteBuffer的读写状态切换的时候必须要调用flip方法而当下一次写之前,必须要将Buffe中的内容读完,再调用clear方法
每次读之前调用flip,写之前调用clear,这样无疑给开发带来了繁琐的步骤
而且内容没有读完是不能写的,这样非常不灵活
相比之下我们看看ByteBuf
读的时候仅仅依赖readerIndex指针,写的时候仅仅依赖writerIndex指针
不需每次读写之前调用对应的方法
而且没有必须一次读完的限制
  • 零拷贝
1、Netty的接收和发送ByteBuffer采用DIRECT BUFFERS
使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝
如果使用传统的堆内存(HEAP BUFFERS)进行Socket读写
JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中
相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。
2、Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象
用户可以像操作一个Buffer那样方便的对组合Buffer进行操作
避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer
Netty的文件传输采用了transferTo方法
它可以直接将文件缓冲区的数据发送到目标Channel
避免了传统通过循环write方式导致的内存拷贝问题。
  • 引用计数与池化技术
在Netty中,每个被申请的Buffer对于Netty来说都可能是很宝贵的资源
因此为了获得对于内存的申请与回收更多的控制权
Netty自己根据引用计数法去实现了内存的管理
Netty对于Buffer的使用都是基于直接内存(DirectBuffer)实现的
大大提高I/O操作的效率
然而DirectBuffer和HeapBuffer相比之下除了I/O操作效率高之外还有一个天生的缺点
即对于DirectBuffer的申请相比HeapBuffer效率更低
因此Netty结合引用计数实现了PolledBuffer,即池化的用法
当引用计数等于0的时候 Netty将Buffer回收致池中
在下一次申请Buffer的没某个时刻会被复用


总结


Netty其实本质上就是Reactor模式的实现Selector作为多路复用器,EventLoop作为转发器,Pipeline作为事件处理器
但是和一般的Reactor不同的是,Netty使用串行化实现,并在Pipeline中使用了责任链模式
相关文章
|
5月前
|
Java
【Netty 网络通信】Netty 工作流程分析
【1月更文挑战第9天】Netty 工作流程分析
|
5月前
|
Java Unix Linux
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
当涉及到网络通信和高性能的Java应用程序时,Netty是一个强大的框架。它提供了许多功能和组件,其中之一是JNI传输。JNI传输是Netty的一个特性,它为特定平台提供了高效的网络传输。 在本文中,我们将深入探讨Netty提供的特定平台的JNI传输功能,分析其优势和适用场景。我们将介绍每个特定平台的JNI传输,并讨论其性能、可靠性和可扩展性。通过了解这些特定平台的JNI传输,您将能够更好地选择和配置适合您应用程序需求的网络传输方式,以实现最佳的性能和可靠性。
130 7
【Netty技术专题】「原理分析系列」Netty强大特性之Native transports扩展开发实战
|
4月前
|
存储 设计模式 缓存
面试官:说说Netty对象池的实现原理?
Netty 作为一个高性能的网络通讯框架,它内置了很多恰夺天工的设计,目的都是为了将网络通讯的性能做到极致,其中「对象池技术」也是实现这一目标的重要技术。 ## 1.什么是对象池技术? 对象池技术是一种重用对象以减少对象创建和销毁带来的开销的方法。在对象池中,只有第一次访问时会创建对象,并将其维护在内存中,当再次需要使用对象时,会直接从对象池中获取对象,并在使用完毕后归还给对象池,而不是频繁地创建和销毁对象。 使用对象池技术的优点有以下几个: 1. **提高性能**:复用对象可以减少对象的创建和销毁次数,降低系统开销,提高系统性能和吞吐量。 2. **减少内存碎片**:对象池可以避免
30 0
|
11月前
netty的异常分析 IllegalReferenceCountException refCnt: 0, decrement: 1
netty的异常分析 IllegalReferenceCountException refCnt: 0, decrement: 1
172 0
|
5月前
|
前端开发 网络协议 Java
Netty | 工作流程图分析 & 核心组件说明 & 代码案例实践
Netty | 工作流程图分析 & 核心组件说明 & 代码案例实践
251 0
|
11月前
|
前端开发
Netty4 读写水位控制分析
Netty4 读写水位控制分析
72 0
|
11月前
|
运维 Java
高并发下Netty4底层bug导致直接内存溢出分析
高并发下Netty4底层bug导致直接内存溢出分析
164 0
|
编解码 前端开发 Java
源码分析Netty:核心组件及启动过程分析
本篇从实例出发,了解Netty核心组件的概念、作用及串联过程。从概念到设计原理,再到深入了解实现细节,从而能够清晰地掌握Netty的技术细节甚至存在的问题,才能最终更好地支持我们实际的各项业务。
337 0
|
存储 Java Unix
【Netty技术专题】「原理分析系列」Netty强大特性之ByteBuf零拷贝技术原理分析
【Netty技术专题】「原理分析系列」Netty强大特性之ByteBuf零拷贝技术原理分析
181 0
【Netty技术专题】「原理分析系列」Netty强大特性之ByteBuf零拷贝技术原理分析
|
网络协议 前端开发 Java
Netty服务端启动流程分析
Netty服务端启动流程分析
166 0