首页 > 其他分享 >Netty

Netty

时间:2023-06-29 12:05:38浏览次数:36  
标签:Netty Reactor 线程 IO 客户端 NIO

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

Netty高性能

在IO编程过程中,当需要同时处理多个客户端接入请求时,可以利用多线程或者IO多路复用技术进行处理。IO多路复用技术通过把多个IO的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线程/多进程模型比,I/O多路复用的最大优势是系统开销小,系统不需要创建新的额外进程或者线程,也不需要维护这些进程和线程的运行,降低了系统的维护工作量,节省了系统资源。

与Socket类和ServerSocket类相对应,NIO也提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现。

多路复用通讯方式

Netty框架按照Reactor模式设计和实现,它的服务器端通信序列图如下:

Netty_线程池

客户端通信序列图如下:

Netty_线程池_02

Netty的IO线程NioEventLoop由于聚合了多路复用器Selector,可以同时并发处理成百上千个客户端Channel,由于读写操作都是非阻塞的,这就是可以充分提供IO线程的运行效率,避免由于频繁IO阻塞导致的线程挂起。

异步通讯IO

由于Netty采用了异步通信模式,一个IO线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞IO一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

零拷贝技术

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

2.Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象,用户可以像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。

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

内存池(基于内存池的缓冲区重用机制)

随着JVM虚拟机和JIT即时编译技术的发展,对象的分配和回收是个非常轻量级的工作。但是对于缓冲区Buffer,情况稍有不同,特别是对于堆外直接内存的分配和回收,是一件耗时的操作。为了尽量重用缓冲区,Netty提供了基于内存池的缓冲区重用模型。

高效的Reactor线程模型

常用的Reactor线程模型有三种,Reactor单线程模型,Reactor多线程模型,主从Reactro多线程模型

Reactor模型

Reactor单线程模型,指的是所有IO操作都在同一个NIO线程上面完成,NIO线程的职责如下:

a.作为NIO服务端,接收客户端的TCP连接;

b.作为NIO客户端,向服务端发起TCP连接;

c.读取通信对端的请求或者应答消息;

d.向通信对端发送消息请求或应答消息。

Netty_线程池_03

由于Reactor模式使用的是异步fiel非阻塞IO,所有的IO操作都不会导致阻塞,理论上一个线程可以独立处理所有IO相关的操作。从架构层面看,一个NIO线程确实可以完成其承担的职责。例如,通过Acceptor接收客户端的TCP连接请求信息,链路建立成功之后,通过Dispatch将对应的ByteBuffer派发到指定的Handler上进行消息解码。用户handler可以通过NIO线程将消息发送给客户端。

Reactor多线程模型

Reactor多线程模型与单线程模型最大的区别就是有一组NIO线程处理IO操作。有专门一个NIO线程-Acceptor线程用于监听服务端,接收客户端的TCP连接请求;网络IO操作-读、写等由一个NIO线程池负责,线程池可以采用标准的JDK线程池实现,它包含一个任务队列和N和可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送。

Netty_线程池_04


主从Reactor多线程模型

服务端用于接收客户端连接的不再是一个单独的NIO线程,而是一个独立的NIO线程池。Acceptor接收到客户端TCP连接请求处理完成后(可能包含接入认证等),将新创建的SocketChannel注册到IO连接池(Sub reactor线程池)的某个IO线程上,由它负责SocketChannel的读写和编解码工作。Acceptor线程池仅仅只用于客户端的登录、握手和安全认证,一旦链路建立成功,就将链路注册到后端subReactor线程池的IO线程上,由IO线程负责后续的IO操作。

Netty_线程池_05

无锁设计、线程绑定

Netty采用了串行无锁化设计,在IO线程内部进行串性操作,避免多线程竞争导致的性能下降。表面上看,串行化设计似乎CPU利用率不高,并发程序不够。但是,通过调整NIO线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一个队列-多个工作线程模型性能更优。

Netty_nety_06

Netty的NioEventLoop读取到消息之后,直接调用ChannelPipline的fireChannelRead(Object msg),只要用户不主动切换线程,一直会由NioEventLoop调用到用户的Handler,期间不进行线程切换,这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看那是最优的。

高性能的序列化框架

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

SO_RCVBUF和SO_SNDBUF:通常建议值为128k或256k。

小包封大包,防止网络阻塞

SO_TCPNODELAY:NAGLE算法通过将缓冲区内的小封包自动相连,组成较大的封包,阻止大量小封包的发送阻塞网络,从而提高网络应用效率。但是对于时延敏感的应用场景需要关闭该优化算法。

软中断Hash值和CPU绑定

软中端:开启RPS后可以实现软中端,提升网络吞吐量。RPS根据数据包的源地址,目的地址以及目的和源端口,计算出一个hash值,然后根据这个hash值来选择软中端运行的cpu,从上层来看,也就是说将每个连接和cpu绑定,并通过这个hash值,来均衡软中断在多个cpu上,提升网络并行处理性能。

标签:Netty,Reactor,线程,IO,客户端,NIO
From: https://blog.51cto.com/u_11315052/6580922

相关文章

  • Netty——4、优化
    1、扩展序列化算法序列化、反序列化主要用在消息正文的转换上:序列化时,需要将Java对象变为要传输的数据(可以是byte[],或json等,最终都需要变成byte[]);反序列化时,需要将传入的正文数据还原成Java对象,便于处理。目前的代码仅支持Java自带的序列化,反序列化机制,核心代码如......
  • 到底什么是Java AIO?为什么Netty会移除AOI?一文搞懂AIO的本质!
    本文由得物技术团队Uni分享,即时通讯网收录时有内容修订和大量排版优化。1、引言关于Java网络编程中的同步IO和异步IO的区别及原理的文章非常的多,具体来说主要还是在讨论JavaBIO和JavaNIO这两者,而关于JavaAIO的文章就少之又少了(即使用也只是介绍了一下概念和代码示例)。在深......
  • Netty实战(十六)
    (UDP广播事件(二)编写广播者和监视器)一、编写广播者Netty提供了大量的类来支持UDP应用程序的编写。下面我们列出一些要用到的类型:名称描述interfaceAddressedEnvelope<M,AextendsSocketAddress>extendsReferenceCounted定义一个消息,其包装了另一个消息并带有......
  • netty rpc个人即兴整理
    nettyrpcrpc不通过http,只是使用了tcphttp应用层tcp传输层http不同产品或者不同语言之间最佳解决浪费传输的宽带rpc为什么只用tcp就可以实现,说白了,http就是编码解码用的,我用prc可以自定义编码解码器,不需要通过http实现rpc个人理解,适用于客户端和服务端都是一个产品组开发......
  • 【Netty】「萌新入门」(二)剖析 EventLoop
    前言本篇博文是《从0到1学习Netty》中入门系列的第二篇博文,主要内容是介绍Netty中EventLoop的使用,优化及源码解析,往期系列文章请访问博主的Netty专栏,博文中的所有代码全部收集在博主的GitHub仓库中;概述事件循环对象EventLoop在Netty中,EventLoop是用于处理I/O事件的......
  • 【Netty】Netty部分源码分析(启动流程,EventLoop,accept流程,read流程)
    源码分析Netty源码中调用链特别长,且涉及到线程切换等步骤,令人头大:)1启动剖析我们就来看看netty中对下面的代码是怎样进行处理的//1netty中使用NioEventLoopGroup(简称nioboss线程)来封装线程和selectorSelectorselector=Selector.open();//2创建NioServerSo......
  • 【Netty】一个RPC实例
    Netty实现简易RPC调用总体流程:客户端发起rpc调用请求,封装好调用的接口名,函数名,返回类型,函数参数类型,函数参数值等属性,将消息发送给服务器。服务器的handler解析rpc请求,调用对应方法,并将方法结果写回客户端。客户端在主线程发送消息后,准备一个空Promise对象,用来接收结果。在......
  • 跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)
    本文由will分享,个人博客zhangyaoo.github.io,原题“基于Netty的IM系统设计与实现”,有修订和重新排版。1、引言本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯......
  • 【Netty】02-入门
    二.Netty入门1.概述1.1Netty是什么?Nettyisanasynchronousevent-drivennetworkapplicationframeworkforrapiddevelopmentofmaintainablehighperformanceprotocolservers&clients.Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、......
  • 【Netty】从0到1(二):NIO-阻塞模式与非阻塞模式
    前言本篇博文是《从0到1学习Netty》系列的第二篇博文,主要内容是通过NIO来理解阻塞模式与非阻塞模式,往期系列文章请访问博主的Netty专栏,博文中的所有代码全部收集在博主的GitHub仓库中;介绍阻塞模式在JavaNIO中,阻塞模式是一种传统的I/O处理方式,当我们试图从通道进行读取......