大数据、分布式都用到了的Netty,小甲鱼数据结构百度云

  1. 传输:用什么样的通道将数据发送给对方,BIO、NIO 或者 AIO,IO 模型在很大程度上决定了框架的性能。

  2. 协议:采用什么样的通信协议,HTTP 或者内部私有协议。协议的选择不同,性能模型也不同。相比于公有协议,内部私有协议的性能通常可以被设计的更优。

  3. 线程:数据报如何读取?读取之后的编解码在哪个线程进行,编解码后的消息如何派发, Reactor 线程模型的不同,对性能的影响也非常大。

2.2. Netty 高性能之道

2.2.1. 异步非阻塞通信

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

JDK1.4 提供了对非阻塞 IO(NIO)的支持,JDK1.5_update10 版本使用 epoll 替代了传统的 select/poll,极大的提升了 NIO 通信的性能。

JDK NIO 通信模型如下所示:

与 Socket 类和 ServerSocket 类相对应,NIO 也提供了 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现。这两种新增的通道都支持阻塞和非阻塞两种模式。阻塞模式使用非常简单,但是性能和可靠性都不好,非阻塞模式正好相反。开发人员一般可以根据自己的需要来选择合适的模式,一般来说,低负载、低并发的应用程序可以选择同步阻塞 IO 以降低编程复杂度。但是对于高负载、高并发的网络应用,需要使用 NIO 的非阻塞模式进行开发。

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

客户端通信序列图如下:

Netty 的 IO 线程 NioEventLoop 由于聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端 Channel,由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率,避免由于频繁 IO 阻塞导致的线程挂起。另外,由于 Netty 采用了异步通信模式,一个 IO 线程可以并发处理 N 个客户端连接和读写操作,这从根本上解决了传统同步阻塞 IO 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。

2.2.2. 零拷贝技术

很多用户都听说过 Netty 具有“零拷贝”功能,但是具体体现在哪里又说不清楚,本小节就详细对 Netty 的“零拷贝”功能进行讲解。

Netty 的“零拷贝”主要体现在如下三个方面:

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

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

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

下面,我们对上述三种“零拷贝”进行说明,先看 Netty 接收 Buffer 的创建:

每循环读取一次消息,就通过 ByteBufAllocator的ioBuffer 方法获取 ByteBuf 对象,下面继续看它的接口定义:


当进行 Socket IO 读写的时候,为了避免从堆内存拷贝一份副本到直接内存,Netty 的 ByteBuf 分配器直接创建非堆内存避免缓冲区的二次拷贝,通过“零拷贝”来提升读写性能。

下面我们继续看第二种“零拷贝”的实现 CompositeByteBuf,它对外将多个 ByteBuf 封装成一个 ByteBuf,对外提供统一封装后的 ByteBuf 接口,它的类定义如下:


通过继承关系我们可以看出 CompositeByteBuf 实际就是个 ByteBuf 的包装器,它将多个 ByteBuf 组合成一个集合,然后对外提供统一的 ByteBuf 接口,相关定义如下:

添加 ByteBuf,不需要做内存拷贝,相关代码如下:

最后,我们看下文件传输的“零拷贝”:

Netty 文件传输 DefaultFileRegion 通过 transferTo 方法将文件发送到目标 Channel 中,下面重点看 FileChannel 的 transferTo 方法,它的 API DOC 说明如下:

对于很多操作系统它直接将文件缓冲区的内容发送到目标 Channel 中,而不需要通过拷贝的方式,这是一种更加高效的传输方式,它实现了文件传输的“零拷贝”。

2.2.3. 内存池

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

Netty 提供了多种内存管理策略,通过在启动辅助类中配置相关参数,可以实现差异化的定制。

下面通过性能测试,我们看下基于内存池循环利用的 ByteBuf 和普通 ByteBuf 的性能差异。

用例一,使用内存池分配器创建直接内存缓冲区:

用例二,使用非堆内存分配器创建的直接内存缓冲区:

各执行300万次,性能对比结果如下所示:

性能测试表明,采用内存池的 ByteBuf 相比于朝生夕灭的 ByteBuf,性能高23倍左右(性能数据与使用场景强相关)。

下面我们一起简单分析下 Netty 内存池的内存分配:

继续看 newDirectBuffer 方法,我们发现它是一个抽象方法,由 AbstractByteBufAllocator 的子类负责具体实现,代码如下:

代码跳转到 PooledByteBufAllocator 的 newDirectBuffer 方法,从 Cache 中获取内存区域 PoolArena,调用它的 allocate 方法进行内存分配:

PoolArena 的 allocate 方法如下:

我们重点分析 newByteBuf 的实现,它同样是个抽象方法,由子类 DirectArena 和 HeapArena 来实现不同类型的缓冲区分配,由于测试用例使用的是堆外内存,

因此重点分析 DirectArena 的实现:如果没有开启使用 sun 的 unsafe,则

执行 PooledDirectByteBuf 的 newInstance 方法,代码如下:

通过 RECYCLER 的 get 方法循环使用 ByteBuf 对象,如果是非内存池实现,则直接创建一个新的 ByteBuf 对象。从缓冲池中获取 ByteBuf 之后,调用 AbstractReferenceCountedByteBuf的setRefCnt 方法设置引用计数器,用于对象的引用计数和内存回收(类似 JVM 垃圾回收机制)。

2.2.4. 高效的 Reactor 线程模型(重点)

常用的 Reactor 线程模型有三种,分别如下:

  1. Reactor 单线程模型;

  2. Reactor 多线程模型;

  3. 主从 Reactor 多线程模型(很重点)

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

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

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

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

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

Reactor 单线程模型示意图如下所示:

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

如何获取免费架构学习资料?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

准备两个月,面试五分钟,Java中高级岗面试为何越来越难?

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以戳这里即可免费获取哦

img-Vu36t1Co-1628439689235)]

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以戳这里即可免费获取哦

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值