当前位置: 首页 > article >正文

netty基础知识梳理和总结

目录标题

    • 由来
    • netty整体结构
        • 核心功能
          • 可扩展的事件模型
          • 统一的通信 API
          • 零拷贝机制与字节缓冲区
        • 传输服务
        • 协议支持
    • netty的IO模型
    • netty核心组件
        • Channel
        • EventLoop、EventLoopGroup
        • ChannelHandler
        • ChannelPipeline
        • Bootstrap
        • Future
    • netty的bytebuf
      • bytebuf的内部构造
      • bytebuf的使用模式
      • ByteBuf的释放
    • netty的零拷贝
      • Kafka的零拷贝
      • **1. Kafka 的零拷贝**
        • **定义**
        • **实现原理**
        • **优点**
        • **缺点**

由来

Netty是由JBOSS公司提供的一个java开源框架
是一个基于NIO的客户、服务器端编程框架,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

netty整体结构

在这里插入图片描述

核心功能
可扩展的事件模型
  • 提供灵活且可扩展的事件处理机制,适应多种应用场景。
统一的通信 API
  • 统一接口:无论是 HTTP 还是 Socket,均使用统一的 API,简化了操作流程。
  • 易用性:通过一致的接口设计,降低了开发复杂度。
零拷贝机制与字节缓冲区
  • 高效数据传输:采用零拷贝机制,减少数据在内存中的拷贝次数,提升性能。
  • 字节缓冲区:优化数据存储和读取效率。
传输服务
  • Socket,基于TCP
  • Datagram(数据报),基于UDP
  • HTTP 协议
  • In-VM Pipe(管道协议)
协议支持
  • HTTP 与 WebSocket:支持标准的 HTTP 和 WebSocket 协议。
  • SSL 安全套接字协议:提供安全的通信保障。
  • Google Protobuf:支持高效的序列化框架。
  • 压缩支持
    • 支持 zlibgzip 压缩,优化传输效率。
  • 大文件传输:支持高效的大文件传输能力。
  • RTSP(实时流传输协议):支持 TCP/IP 协议体系中的应用层协议,适用于实时流媒体场景。
  • 二进制协议支持:支持自定义二进制协议,并提供完整的单元测试。

netty的IO模型

Netty就是使用Java的NIO实现了Reactor线程模型是其实现高性能的一个核心点。
Netty是基于NIO2的IO模型(IO多路复用模型,非循环进行read的系统调用的原始NOBlock IO模型)。

  • 常见的Reactor线程模型有三种
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

Netty就是结合了NIO的特点,应用了Reactor线程模型所实现的。

在这里插入图片描述

  • 在Netty模型中,负责处理新连接事件的是BossGroup,负责处理其他事件的是WorkGroup。Group就是线程池的概念。
  • NioEventLoop表示一个不断循环的执行处理任务的线程,用于监听绑定在其上的读/写事件。NioEventLoop就是Group里面的工作线程。
  • 通过Pipeline(管道)执行业务逻辑的处理,Pipeline中会有多个ChannelHandler,真正的业务逻辑是在ChannelHandler中完成的。

netty核心组件

Channel

可以理解为是socket连接,在客户端与服务端连接的时候就会建立一个Channel。
常用的 Channel 类型:

  • NioSocketChannel,NIO的客户端 TCP Socket 连接。
  • NioServerSocketChannel,NIO的服务器端 TCP Socket 连接。
  • NioDatagramChannel, UDP 连接。
  • NioSctpChannel,客户端 Sctp 连接。
  • NioSctpServerChannel,Sctp 服务器端连接,这些通道涵盖了 UDP 和 TCP 网络 IO 以及文件IO。
EventLoop、EventLoopGroup
  • 在 Netty 中每个 Channel 都会被分配到一个 EventLoop。一个 EventLoop 可以服务于多个 Channel。
  • 每个 EventLoop 会占用一个 Thread,同时这个 Thread 会处理 EventLoop 上面发生的所有 IO 操作和事件
  • EventLoopGroup 是用来生成 EventLoop 的
ChannelHandler

ChannelHandler对使用者而言,可以说是最重要的组件了,因为对于数据的入站和出站的业务逻辑的编写都是在ChannelHandler中完成的。
在这里插入图片描述

  • ChannelInboundHandler 入站事件处理器
  • ChannelOutBoundHandler 出站事件处理器

例如:在 入站事件处理器中可以实现了channelRead方法,获取到客户端传来的数据
ChannelHandler只能完成编码解码处理、读写操作中的一种,所以ChannelHandler都是成组出现来完成功能。

ChannelPipeline

一个Channel包含了一个ChannelPipeline,而ChannelPipeline中维护了一个ChannelHandler的列表。
ChannelHandlerContext进行维护ChannelHandler与Channel和ChannelPipeline之间的映射关系。
在这里插入图片描述
ChannelHandler按照加入的顺序会组成一个双向链表

  • 入站事件从链表的head往后传递到最后一个ChannelHandler
  • 出站事件从链表的tail向前传递,直到最后一个ChannelHandler
  • 两种类型的ChannelHandler相互不会影响。
Bootstrap

Bootstrap是引导的意思,它的作用是配置整个Netty程序,将各个组件都串起来,最后绑定端口、启动Netty服务。
Netty中提供了2种类型的引导类,一种用于客户端(Bootstrap),而另一种(ServerBootstrap)用于服务器。
它们的区别在于:

  • ServerBootstrap 只需要绑定一个监听连接的端口,而 Bootstrap 则是需要远程节点的IP和端口
  • 客户端Bootstrap 只需要一个EventLoopGroup来实现消息的读取和写入,而ServerBootstrap则需要两个EventLoopGroup,一个来实现处理新连接事件,一个用来处理消息的读取和写入等事件。
Future

Future提供了一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符,它将在未来的某个时刻完成,并提供对其结果的访问。

netty的bytebuf

bytebuf的内部构造

ByteBuf的三个指针:

  • readerIndex(读指针)
    指示读取的起始位置, 每读取一个字节, readerIndex自增累加1。 如果readerIndex 与writerIndex 相等,ByteBuf 不可读 。
  • writerIndex(写指针)
    指示写入的起始位置, 每写入一个字节, writeIndex自增累加1。如果增加到 writerIndex 与capacity() 容量相等,表示 ByteBuf 已经不可写。
  • maxCapacity(最大容量)
    指示ByteBuf 可以扩容的最大容量, 如果向ByteBuf写入数据时, 容量不足, 可以进行扩容

当从 ByteBuf 读取时,它的 readerIndex(读索引)将会根据读取的字节数递增。
同样,当写 ByteBuf 时,它的 writerIndex(写索引) 也会根据写入的字节数进行递增。

ByteBuf内部空间结构:
在这里插入图片描述

  • byteBuf.readByte(),内部通过移动readerIndex进行读取
  • byteBuf.writeInt(i);
  • discardReadBytes(),可以将已经读取的数据进行丢弃处理,就可以回收已经读取的字节空间,可写空间就会变大
  • clear() ,重置readerIndex 、 writerIndex 为0,需要注意的是,重置并没有删除真正的内容

bytebuf的使用模式

  • 堆缓冲区(HeapByteBuf)
    • 优点:内存的分配和回收速度比较快,可以被JVM自动回收
    • 缺点:进行socket的IO读或者写时,需要额外做一次内存复制,,将堆内存对应的缓冲区复制到内核Channel中,性能下降。
  • 直接缓冲区(DirectByteBuf),非堆内存
    • 优点:它写入或从Socket Channel中读取时,由于减少了一次内存拷贝(零拷贝),速度比堆内存块
    • 缺点:内存的分配和回收速度慢,并且如果不注意内存回收,会导致内存泄漏
  • 复合缓冲区,顾名思义就是将上述两类缓冲区聚合在一起。
    • 复合缓冲区的核心思想是通过逻辑上的组合,而不是物理上的合并,来管理多个缓冲区
    • 工作原理
      • 数据的逻辑组合:通过维护一个内部的组件列表(components),记录每个子缓冲区的引用和偏移量。每个子缓冲区可以是堆缓冲区或直接缓冲区。
      • 统一的读写接口:复合缓冲区对外提供了一个统一的读写接口,用户可以通过索引访问整个缓冲区的内容,而不需要关心底层是由哪些子缓冲区组成的。
    • 使用场景:在网络协议中,可能需要将头部(通常较小,适合堆缓冲区)和负载(通常较大,适合直接缓冲区)分开存储,但又希望以统一的方式操作。

ByteBuf的释放

  • 手动释放,就是在使用完成后,调用ReferenceCountUtil.release(byteBuf); 进行释放
  • 自动释放
    • 入站的TailHandler:Netty的ChannelPipleline的流水线的末端是TailHandler,默认情况下如果每个入站处理器Handler都把消息往下传,TailHandler会释放掉ReferenceCounted类型的消息。
    • 继承SimpleChannelInboundHandler,类中包含一个onUnhandledInboundMessage方法,会释放缓存
    • HeadHandler的出站释放,类似于入站

netty的零拷贝

所谓的零拷贝,就是取消用户空间与内核空间之间的数据拷贝操作,应用进程每一次的读写操作,都可以通过一种方式,让应用进程向用户空间写入或者读取数据,就如同直接向内核空间写入或者读取数据一样,再通过 DMA 将内核中的数据拷贝到网卡,或将网卡中的数据 copy 到内核。

Netty零拷贝主要体现在三个方面:

  • Netty的接收和发送ByteBuffer是采用DIRECT BUFFERS,使用堆外的直接内存(内存对象分配在JVM中堆以外的内存)进行Socket读写,不需要进行字节缓冲区的二次拷贝。如果采用传统堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后写入Socket中。
  • Netty提供了组合Buffer对象,也就是CompositeByteBuf 类,可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf,避免了内存的拷贝。
  • Netty的文件传输采用了FileRegion 中包装 NIO 的 FileChannel.transferTo() 方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。(类似于kafka的零拷贝)

Kafka的零拷贝

Kafka 和 Netty 都使用了零拷贝技术,但它们的应用场景和实现方式有所不同。以下是对两者的区别、优缺点的详细分析:


1. Kafka 的零拷贝

定义

Kafka 的零拷贝是指在数据传输过程中,尽量减少数据在用户空间和内核空间之间的拷贝次数。它主要依赖于操作系统提供的 sendfile 系统调用(Linux 环境下)来实现。

实现原理
  • 当 Kafka 从磁盘读取数据并发送到网络时,传统的方式需要经过多次数据拷贝:
    1. 数据从磁盘读取到内核缓冲区。
    2. 数据从内核缓冲区拷贝到用户空间缓冲区。
    3. 数据从用户空间缓冲区再拷贝回内核缓冲区(用于网络传输)。
    4. 数据通过网络接口发送出去。
  • 使用零拷贝后:
    • 数据直接从内核缓冲区通过 sendfile 系统调用传输到网络接口,避免了用户空间的参与,减少了两次拷贝操作。
优点
  1. 性能提升:减少了数据拷贝次数和上下文切换,显著提高了吞吐量。
  2. 降低 CPU 开销:避免了用户空间和内核空间之间的数据拷贝,降低了 CPU 的负担。
  3. 适合大数据传输:特别适用于 Kafka 这种需要频繁进行大文件传输的场景。
缺点
  1. 灵活性较低:零拷贝要求数据是连续存储的,且不能对数据进行修改。如果需要对数据进行处理(如加密、压缩等),则无法直接使用零拷贝。
  2. 依赖操作系统支持:需要底层操作系统提供 sendfile 或类似机制的支持。

http://www.kler.cn/a/558082.html

相关文章:

  • 数据库面试知识点总结
  • [Android]浏览器下载的apk文件无法识别无法安装问题
  • 《AI与NLP:开启元宇宙社交互动新纪元》
  • Django 连接(sqlserver)数据库方法
  • SHELL32!Shell_MergeMenus函数分析
  • 蓝桥杯拔河问题(前缀和与差分,multiset,区间冲突)
  • 基于Transformer的语音障碍分析方法
  • MAC快速本地部署Deepseek (win也可以)
  • 工业机器视觉的“眼睛”:如何利用镜头获取精准图像
  • [含文档+PPT+源码等]精品大数据项目-Django基于机器学习实现的市区游客满意度可视化分析系统
  • 【论文阅读】SAM-CP:将SAM与组合提示结合起来的多功能分割
  • Uniapp 设计思路全分享
  • DeepSeek R1/V3满血版——在线体验与API调用
  • Error [ERR_REQUIRE_ESM]: require() of ES Module
  • MySQL的Union和OR查询
  • Vite 和 Webpack 的区别和选择
  • 靶场之路-Kioptix Level-1 mod_ssl 缓冲区溢出漏洞
  • CDefFolderMenu_MergeMenu函数分析之添加了分割线和属性菜单项两项
  • 《网络安全入门实战手册》
  • 星途汽车掉队?2024销量增速回落,“星纪元”序列后劲不足