Netty

1. Netty概述

1.1 什么是Netty

        Netty是由JBOSS提供的一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可扩展的网络服务器和客户端应用。它基于Java的NIO模型,提供了简单而强大的抽象,使得网络编程变得更加容易和高效。

        以下是Netty的一些主要特性:

        1、使用简单:Netty封闭了 Java 原生 NIO 类库繁琐的 API,使用起来更加高效。

        2、功能强大: 预置多种编码能力,支持多种主流协议。同时通过 ChannelHandler 可以进行灵活的拓展,支持很强的定制能力。

        3、高性能:与其它业界主流 NIO 框架相比,Netty综合更优。主要体现在吞吐量更高、延迟更低、减少资源消耗以及最小化不必要的内存复制。

        4、社区活跃: 版本更新周期短,BUG 修复速度快,让开发者可以专注业务本身。

1.2 为什么需要Netty

        1、高度优化的协议实现:通用协议或其实现有时不能很好地满足特定需求,例如大文件传输、近实时消息等。Netty提供了高度优化的专用协议实现,可以针对特定目的进行定制和优化。

        2、快速开发:Netty是一个异步事件驱动的网络应用程序框架,通过提供简单易用的API,可以快速轻松地开发协议服务器和客户端等网络应用程序。它简化了网络编程,例如TCP和UDP套接字服务器开发,使开发者能够更快地实现自定义协议。

        3、高性能和可扩展性:Netty经过精心设计和优化,基于多个协议的实现经验。它提供了高性能和可扩展性,可以处理大量并发连接和高吞吐量的数据传输。

        4、支持多种协议:Netty支持多种协议的实现,包括FTP、SMTP、HTTP以及各种基于二进制和文本的遗留协议。这使得开发者能够更轻松地处理遗留系统的互操作性问题,同时保持应用程序的性能和稳定性。

1.3 Netty的应用案例

        Netty被许多知名的开源项目和大型企业广泛使用,如RocketMQ、Elasticsearch、Dubbo等。通过其强大的性能和灵活的设计,Netty成为了Java网络编程的首选框架之一。

        1、RocketMQ:RocketMQ是一个开源的分布式消息队列系统,它使用了Netty作为底层网络通信框架。根据官方的性能测试数据,RocketMQ在一台4核8线程的机器上,通过Netty框架每秒可以处理超过200万个消息。

        2、Elasticsearch:Elasticsearch是一个分布式搜索和分析引擎,也是基于Netty的。Elasticsearch通过Netty处理节点间的通信和数据传输。根据官方的基准测试数据,Elasticsearch在具有数百个节点和数百万条文档的集群中,通过Netty可以实现每秒数千次的搜索和索引操作。

        3、Dubbo:Dubbo是一个高性能的分布式服务框架,它也使用了Netty进行网络通信。Dubbo的性能测试数据显示,在具有数百个节点和数千个并发连接的场景下,通过Netty可以实现每秒数万次的远程调用。

1.4 Netty的组件

        以下是Netty的核心组件:

        1、ByteBuf:是Netty中用于存储数据的缓冲区,类似于JDK中的ByteBuffer。ByteBuf提供了一系列的方法来读取、写入和操作数据。

        2、Channel(通道):Channel是Netty的基本抽象,代表了一个打开的连接,可以进行数据的读写。它提供了异步的I/O操作,可以通过不同的传输方式(如TCP、UDP、本地文件传输)进行数据的读写。

        3、ChannelHandler(通道处理器):ChannelHandler是用于处理I/O事件和执行业务逻辑的组件。它可以通过注册到ChannelPipeline中,以对Channel的入站和出站事件进行处理。Netty提供了多个内置的ChannelHandler,也可以自定义实现来满足具体的需求。

        4、ChannelPipeline(通道管道):ChannelPipeline是一个拦截和处理事件的处理器链。它包含一系列的ChannelHandler,用于按顺序处理入站和出站事件。当数据进入或离开通道时,会依次经过各个ChannelHandler的处理,进行数据的编解码、业务逻辑的处理等操作。

        5、ChannelHandlerContext:是一个ChannelHandler上下文对象,用于传递事件和操作。它提供了与Channel和ChannelHandler的交互接口,可以通过ChannelHandlerContext发送数据、触发事件和获取相关信息。

        6、EventLoop(事件循环):EventLoop是Netty的核心部分,负责处理所有的I/O事件和任务。它会不断地从事件队列中获取事件,并调度执行相应的操作。一个EventLoop通常会关联一个或多个Channel,并在整个生命周期内处理它们的所有I/O操作。

        7、EventLoopGroup:是一组EventLoop的集合,用于管理和调度事件的处理。它可以包含一个或多个EventLoop,用于处理连接的接受和处理以及数据的读写等操作。

        8、Bootstrap(引导程序):Bootstrap是Netty的启动辅助类,用于简化网络应用程序的启动过程。它负责配置和启动客户端或服务器端的Channel,设置相关的参数和事件处理器。

1.5 Netty入门示例

        本案例通过编写一个客户端与服务端通信的案例,演示Netty的编程入门案例。整体步骤如下:

        1、在项目中添加Netty的依赖。

        2、拷贝Netty的官方示例代码。

        3、查看并修改服务端代码。

        4、查看并修改客户端代码。

        5、对案例进行测试。

        以下是具体操作。

        1、在项目中添加Netty的依赖

        在maven项目的pom.xml文件中添加如下依赖,并刷新Maven。

<!-- netty的依赖 -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.42.Final</version>
</dependency>
<!-- netty官方示例的依赖-->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-example</artifactId>
    <version>4.1.42.Final</version>
</dependency>

        2、拷贝Netty的官方示例代码

        在IDEA中的External Libraries下找到Maven: io.netty:netty-example:4.1.42.Final的依赖,并在io.netty.example.echo包下找到echo示例的4个类。

        复制这4个类,拷贝到项目的src/main/java目录中。

        3、查看并修改服务端代码

        首先,查看EchoServerHandler类,该类继承ChannelInboundHandlerAdapter,Adapter类实现了ChannelInboundHandler接口。ChannelInboundHandler提供了用户可以覆盖的各种事件处理程序方法。一般情况下,扩展ChannelInboundHandlerAdapter接口就足够了,不需要自己实现处理程序接口。

        我们在这里重写channelRead()事件处理程序方法。每当从客户端接收到新数据时,都会使用接收到的消息调用此方法。在本例中,接收到的消息类型为ByteBuf。

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf byteBuf=(ByteBuf)msg;
        System.out.println("客户端发来的消息:"+byteBuf.toString(CharsetUtil.UTF_8));
    }

        然后,我们重写channelReadComplete()方法,用于通知处理器在Channel的读取操作完成后进行处理,本例中用于向客户端发送一个消息。

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(Unpooled.copiedBuffer("你好,我是服务端",CharsetUtil.UTF_8));
    }

        接下来,查看EchoServer类,本案例中不需要对该类中的代码进行修改,仅需要了解该类中代码的含义即可。

        NioEventLoopGroup是一个处理 I/O 操作的多线程事件循环。Netty为不同类型的传输提供了多种EventLoopGroup实现。在此示例中,我们正在实现一个服务器端应用程序,因此NioEventLoopGroup将使用两个服务器端应用程序。第一个通常称为“boss”,接受传入连接。第二个通常称为“worker”,一旦 boss 接受连接,就会处理已接受连接的流量,并将已接受的连接注册到worker。使用多少个线程以及它们如何映射到创建的Channel线程取决于EventLoopGroup实现,一些实现支持通过构造函数进行配置。

        ServerBootstrap是一个设置服务器的辅助类。

        本案例中指定使用NioServerSocketChannel用于实例化新的类Channel来接受传入连接。

        4、查看并修改客户端代码

        首先,查看EchoClientHandler类,该类同样继承ChannelInboundHandlerAdapter。

        重写channelActive()方法,该方法将在连接建立好并准备产生流量时调用。

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        // ctx.writeAndFlush(firstMessage);
        ctx.writeAndFlush(Unpooled.copiedBuffer("你好,我是Netty客户端", CharsetUtil.UTF_8));
    }

        重写channelRead()方法,当数据抵达Channel时,该方法会被调用。

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf byteBuf=(ByteBuf)msg;
        System.out.println("服务端发来消息:"+byteBuf.toString(CharsetUtil.UTF_8));
    }

        接下来,查看EchoClient类,本案例中不需要对该类中的代码进行修改,仅需要了解该类中代码的含义即可。

        5、对案例进行测试

        首先,运行EchoServer类中的main方法,启动服务端程序。

        然后,运行EchoClient类中的main方法,启动客户端程序。

        分别查看客户端控制台和服务端控制台,查看是否正确收到彼此发送的消息。

2. Netty原理

2.1 Netty性能好的原因

        Netty作为一个高性能的网络通信框架,性能是它的重要优势。Netty中主要做了以下事情来全方面的提升Netty的性能。

        1、非阻塞I0模型:Netty采用了IO多路复用技术,让多个IO的阻塞复用到一个select线程阻塞上,能够有效的应对大量的并发请求。

        2、高效的Reactor线程模型:支持多种Reactor线程模型,可以根据业务场景的性能诉求,自行选择。

        3、零拷贝:尽量减少不必要的内存拷贝。

        4、内存池设计:使用直接内存,并且可重复利用。

        5、无锁串行化设计:避免使用锁带来的额外开销。

        6、高性能序列化协议:支持 protobuf 等高性能序列化协议。

2.2 什么是零拷贝

        在操作系统中,零拷贝(Zero-copy)是一种优化技术,旨在减少数据在内存和设备之间的多次拷贝操作,从而提高数据传输的效率和性能。

        传统的数据传输方式涉及多个步骤和数据拷贝:

        1、应用程序将数据从用户空间拷贝到内核空间的缓冲区。

        2、操作系统将数据从内核空间的缓冲区拷贝到设备驱动程序的缓冲区。

        3、设备驱动程序将数据从设备缓冲区拷贝到实际设备(如网络适配器)。

        上述过程在接收数据时也适用,只是拷贝方向相反。

        这些拷贝操作会带来额外的CPU开销、内存带宽消耗和延迟。而零拷贝技术通过减少或避免这些拷贝操作,提高数据传输的效率。

2.3 Netty中的零拷贝

        Netty中的零拷贝模型和操作系统中的零拷贝模型并不完全相同。他主要指的是在操作数据时,不需要将缓存数据从一个内存区域拷贝到另一个内存区域。减少一次内存的拷贝,CPU的效率就得到的提升。

        Netty的零拷贝主要体现在以下 5 个方面:

        1、直接使用堆外内存,避免JVM 堆内存到堆外内存的数据拷贝。

        2、CompositeByteBuf类,可以组合多个Buffer对象合并成一个逻辑上的对象,避免通过传统内存拷贝的方式将几个Buffer合并成一个大的Buffer。

        3、通过 Unpooled.wrappedBuffer可以将 byte 数组包装成 ByteBuf 对象,包装过程中不会产生内存拷贝。

        4、ByteBuf.slice 操作与 Unpooled.wrappedBuffer相反,slice操作可以将一个ByteBuf对象切分成多个ByteBuf 对象,切分过程中不会产生内存拷贝,底层共享一个 byte 数组的存储空间。

        5、使用 FileRegion 实现文件传输,FileRegion 底层封装了 FileChannel#transferTo()方法,可以将文件缓冲区的数据直接传输到目标 Channel,避免内核缓冲区和用户态缓冲区之间的数据拷贝,这属于操作系统级别的零拷贝。

2.4 Reactor线程模型

        Reactor线程模型是一种用于处理高并发网络编程的设计模式,它基于事件驱动和异步非阻塞的原则,通过合理的线程管理和事件分发机制,实现高效的并发处理。

        Reactor线程模型基于以下几个关键概念:

        1、Reactor:Reactor是一个事件处理器,负责监听和分发事件。它使用一个或多个线程来监听输入事件,并将这些事件分派给相应的处理器进行处理。

        2、Handlers:Handlers是事件的具体处理者,它们负责执行实际的业务逻辑。当Reactor接收到事件后,会将事件分发给相应的处理器进行处理。

        3、Event:Event是指在应用程序中发生的具体事件,例如连接事件、读写事件等。当事件发生时,Reactor会监听到该事件并进行处理。

        Reactor线程模型的基本流程如下:

        1、应用程序通过Reactor注册感兴趣的事件类型和相应的处理器。

        2、Reactor启动,开始监听事件。

        3、当事件发生时,Reactor会触发事件的处理器进行相应的处理。处理器可以是同步的,也可以是异步的。

        4、处理器执行完毕后,可以通过Reactor返回处理结果,或者继续监听新的事件。

        Reactor线程模型的优势在于它的高效性和可伸缩性:

        1、高效性:Reactor线程模型通过事件驱动的方式,避免了传统的阻塞式IO模型中线程的等待和轮询,提高了系统的吞吐量和响应速度。

        2、可伸缩性:Reactor线程模型可以使用多个线程同时处理多个事件,提高了系统的并发处理能力。同时,它还支持多个Reactor的配置,可以更好地利用多核处理器的资源。

2.5 Netty中的线程模型

        Netty通过 Reactor 模型基于多路复用器接收并处理用户请求。

        Netty的线程模型并不是一成不变的,它实际取决于用户的启动参数配置。通过设置不同的启动参数,Netty支持三种模型,分别是Reactor单线程模型、Reactor多线程模型、Reactor主从多线程模型。

        1、Reactor单线程模型

        这是最简单的Reactor模型,当有多个客户端连接到服务器的时候,服务器会使用Reactor线程和客户端建立连接。Reactor内部有一个dispatch (分发器),会根据事件的类型(如连接事件,读事件,写事件)进行分发给具体的Handler进行处理。

  • 此时一个Reactor线程既负责处理连接请求,也要负责处理读写请求
  • 处理具体的读写请求就要涉及字节的复制,相对慢很多,会造成其他请求的等待
  • 通过一个Reactor线程,只能对应一个CPU,发挥不出来多核CPU的优势

        所以,一个Reactor线程可以处理简单的小容量场景,但是对于高负载来说,还需要进一步升级。

        2、Reactor多线程模型

        为了利用多核CPU的优势,也为了防止在Reactor线程等待读写事件时候浪费CPU,所以可以增加一个Worker的线程池,由此升级为单Reactor多线程模式。

        当多个客户端进入服务器后,Reactor线程会监听多种事件(如连接事件,读事件,写事件)。

  • 如果监听到连接事件,则把该事件分配给acceptor处理
  • 如果监听到读事件,那么则会发起系统调用,将数据写入内存,之后再把数据交给工作线程池进行业务处理

        这个时候我们会发现,业务处理的逻辑已经变成多线程处理了。不过一个Reactor既要负责连接事件,又要负责读写事件,同时还要负责数据准备的过程,工作量依旧很大。

        3、主从Reactor模型

        在主从Reactor模型中,主Reactor线程只负责连接事件的处理,它把读写事件全部交给了子Reactor线程。这样即使在数据准备阶段子线程被阻塞,主Reactor还是可以处理连接事件。巧妙的解决了高负载下的连接问题。

3. 总结

        1、Netty是由JBOSS提供的一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可扩展的网络服务器和客户端应用

  • 它基于Java的NIO模型,提供了简单而强大的抽象,使得网络编程变得更加容易和高效

        2、以下是Netty的一些主要特性:

  • 使用简单:Netty封闭了 Java 原生 NIO 类库繁琐的 API,使用起来更加高效
  • 功能强大: 预置多种编码能力,支持多种主流协议,同时通过 ChannelHandler 可以进行灵活的拓展,支持很强的定制能力
  • 高性能:与其它业界主流 NIO 框架相比,Netty综合更优,主要体现在吞吐量更高、延迟更低、减少资源消耗以及最小化不必要的内存复制
  • 社区活跃: 版本更新周期短,BUG 修复速度快,让开发者可以专注业务本身

        3、Netty的核心组件

  • ByteBuf:是Netty中用于存储数据的缓冲区,类似于JDK中的ByteBuffer
  • Channel(通道):Channel是Netty的基本抽象,代表了一个打开的连接,可以进行数据的读写
  • ChannelHandler(通道处理器):ChannelHandler是用于处理I/O事件和执行业务逻辑的组件
  • ChannelPipeline(通道管道):ChannelPipeline是一个拦截和处理事件的处理器链
  • ChannelHandlerContext:是一个ChannelHandler上下文对象,用于传递事件和操作
  • EventLoop(事件循环):EventLoop是Netty的核心部分,负责处理所有的I/O事件和任务
  • EventLoopGroup:是一组EventLoop的集合,用于管理和调度事件的处理
  • Bootstrap(引导程序):Bootstrap是Netty的启动辅助类,用于简化网络应用程序的启动过程

        4、Netty作为一个高性能的网络通信框架,性能是它的重要优势,Netty中主要做了以下事情来全方面的提升Netty的性能

  • 非阻塞I0模型:Netty采用了IO多路复用技术,让多个IO的阻塞复用到一个select线程阻塞上,能够有效的应对大量的并发请求
  • 高效的Reactor线程模型:支持多种Reactor线程模型,可以根据业务场景的性能诉求,自行选择
  • 零拷贝:尽量减少不必要的内存拷贝
  • 内存池设计:使用直接内存,并且可重复利用
  • 无锁串行化设计:避免使用锁带来的额外开销
  • 高性能序列化协议:支持 protobuf 等高性能序列化协议

        5、在操作系统中,零拷贝(Zero-copy)是一种优化技术,旨在减少数据在内存和设备之间的多次拷贝操作,从而提高数据传输的效率和性能

        6、Netty中的零拷贝模型和操作系统中的零拷贝模型并不完全相同,他主要指的是在操作数据时,不需要将缓存数据从一个内存区域拷贝到另一个内存区域

        7、Reactor线程模型是一种用于处理高并发网络编程的设计模式,它基于事件驱动和异步非阻塞的原则,通过合理的线程管理和事件分发机制,实现高效的并发处理

        8、Netty通过 Reactor 模型基于多路复用器接收并处理用户请求

  • Netty的线程模型并不是一成不变的,它实际取决于用户的启动参数配置
  • 通过设置不同的启动参数,Netty支三种模型,分别是Reactor单线程模型、Reactor多线程模型、Reactor主从多线程模型

相关推荐

  1. <span style='color:red;'>Netty</span>

    Netty

    2024-04-28 01:16:02      17 阅读
  2. <span style='color:red;'>Netty</span>

    Netty

    2024-04-28 01:16:02      9 阅读
  3. netty使用

    2024-04-28 01:16:02       32 阅读
  4. Netty学习

    2024-04-28 01:16:02       42 阅读
  5. Netty:AIO

    2024-04-28 01:16:02       12 阅读
  6. netty-学习

    2024-04-28 01:16:02       10 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-28 01:16:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-28 01:16:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-28 01:16:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-28 01:16:02       20 阅读

热门阅读

  1. Unity 点击无效的问题

    2024-04-28 01:16:02       12 阅读
  2. Rust的Clone

    2024-04-28 01:16:02       25 阅读
  3. 【学习心得】Pandas处理异常值的思路

    2024-04-28 01:16:02       13 阅读
  4. error while loading shared libraries: libstdc++.so.6

    2024-04-28 01:16:02       11 阅读
  5. 解释 RESTful API

    2024-04-28 01:16:02       10 阅读
  6. c++后台开发八股文遗漏复习点

    2024-04-28 01:16:02       13 阅读