Netty原理及高性能

1. Netty原理

Netty是一个基于Java的异步事件驱动的网络应用框架,他用于快速开发高性能、高可靠性的网络服务器和客户端应用。Netty的原理涉及多个方面,包括 Reactor模式、核心组件、编解码、线程模型以及TCP粘包和拆包处理等

1.1 Reactor模式

Reactor模式是一种经典的事件驱动编程模型,Reactor模式的基本思想是将一个或者多个线程作为IO事件的处理线程,这些线程负责监听、分发和执行IO事件。Netty中的Reactor线程实现分为单线程模式和多线程模式,以适应不同的应用场景。

1.2 核心组件

Netty的核心组件包括

  • Channel: 表示一个和远程对端的连接,他是Netty对Java NIO中的Channel的抽象和封装。
  • EventLoop:事件循环器,处理事件的执行和IO操作,每个Channel都绑定一个EventLoop,并且所有的操作都是在EventLoop中执行的。
  • ChannelFuture: 异步IO操作结果的封装类,可以用来处理异步操作。例如,在Netty中,写操作是异步的,会立即返回一个ChannelFuture,通过它可以检查操作是否完成、是否成功,以及注册回调。
  • ChannelPipeline:通道处理器的中间件,处理数据的所有处理器都被包含在ChannelPipeline,可以通过ChannelPipeline编排数据的处理流程。
  • ChannelHandler:消息的处理器,将数据的读写和消息的处理独立开来,方便扩展。

1.3 编解码

Netty提供了通用的编解码框架——ChannelHandler,可以根据需要自定义数据的编解码方式。支持多种数据格式的编解码,如字符串、二进制数据、对象等。

1.4 线程模型

Netty的线程模型具有很好的可伸缩性和可扩展性,可以适应不同的应用场景和需求。

  • 单线程模型:一个线程处理所有IO事件,适用于负载不高、并发不强的场景。
  • 多线程模型:通过线程池处理IO事件,提高并发度和系统稳定性。
  • 主从多线程模型:主线程接收连接请求并建立连接,将连接分派给从线程对应处理,增加处理连接的线程数,提高系统的并发度。
  • 多Reactor多线程模型:每个Reactor都有独立的线程池,进一步提高并发度和系统可靠性。

2. Netty高性能

在IO编程过程中,当需要同时处理多个客户端连接请求时,可以利用多线程或者IO多路复用技术进行处理。IO多路复用技术通过把多个IO阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下可以处理多个客户端连接。与传统的多线程/多进程模型相比,IO多路复用的最大优势是系统开销小。

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

2.1 多路复用通信方式

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

2.2 异步通信NIO

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

2.3 零拷贝(Direct Buffers使用堆外直接内存)

在Netty中,零拷贝技术被广泛应用以提高网络数据传输的效率,零拷贝指的是在数据传输过程中,减少或者避免CPU的拷贝次数,从而加快数据传输速度,降低CPU负载。
在Netty中,零拷贝主要通过以下几种方式实现:

  1. 直接使用堆外内存
  • 堆外直接内存是指JVM堆内存之外的内存,通常由操作系统的物理内存直接映射。Netty默认情况下使用堆外直接内存来创建缓冲区,这样做的好处是可以减少JVM堆内存的使用,降低垃圾回收压力,并且可以提高网络传输的效率。因为数据在传输过程中,可以直接从操作系统的网络缓冲区传输到Netty的缓冲区,无需经过JVM堆内存。
  1. 组合ByteBuf(CompositeByteBuf)
  • CompositeByteBuf是一个特殊的缓冲区,可以将多个ByteBuf实例组合成一个逻辑上的ByteBuf,但实际物理内存仍然是分散的,这种方式在需要将多个小的缓冲区合并为一个大的缓冲区进行传输时非常有用,因为他避免了数据的拷贝和合并。
  1. FileRegion
  • FileRegion允许Netty将文件的一部分直接映射到内存(mmap)或者通过操作系统的页面缓存直接发送到网络通道,从而避免了将文件内容先拷贝到JVM堆内存,再发送出去的传统方式。

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

Netty中的内存池是一种高效的内存管理方式,旨在减少内存分配和回收次数,降低垃圾回收压力,从而提高性能。

  1. 内存池的基本概念
  • 内存池是一种内存管理机制,他 预先分配一定大小的内存块,并将这些内存块存储在一个池中,当需要内存时,直接从池中取出,使用完毕后再放回池中,而不是每次都从操作系统申请或者释放内存。这种方式可以减少内存碎片,提高内存利用率,并降低内存分配和回收的开销。
  1. Netty内存池的特点
  • 使用Jemalloc算法:Netty内存池使用Jemalloc算法进行内存管理和分配,Jemalloc是一种高效的内存分配器,能够减少内存碎片,提高内存分配和回收效率。
  • 分层管理:Netty的内存池被分为多个层级,如small、normal、huge,每个层级对应不同大小的内存块。这种分层管理的方式可以更好的适应不同大小的内存请求,提高内存分配的灵活性。
  • ThreadLocal缓存:Netty使用ThreadLocal方式为每个使用内存池的线程个管理一个PoolThreadCache,作为内存片段的缓存,这样可以避免多线程竞争,提高内存分配的速度。
  • 内存规整化:Netty在分配内存时,会对申请的大小进行规整化处理,确保分配内存的大小是2的幂次方或特定倍数,这样可以减少内存碎片,提高内存利用率。
  1. Netty内存池的工作流程
  • 内存申请:当需要内存时,首先检查ThreadLocal缓存中是否有可用的内存片段,如果有,则直接从缓存中取出;如果没有,则向全局内存池申请。
  • 内存分配:全局内存池根据申请的内存大小,从small、normal、huge中选择合适的内存块进行分配,如果层级内没有足够的内存,可能会向操作系统申请更多的内存。
  • 内存使用:分配到的内存片段被用于存储数据或者其他对象,在Netty中,这些内存片段通常被封装为ByteBuf对象,用于网络传输或者处理数据。
  • 内存回收:当内存片段不再需要时,他会被放回ThreadLocal缓存或者全局内存池中,以便后续重用。如果ThreadLocal缓存已满,则可能会将内存片段放回全局内存池或进行其他处理。

2.5 高效的Reactor线程模型

Netty是一个高性能、异步事件驱动的网络编程框架。他基于NIO提供了一套丰富的API,使得开发者可以轻松的构建可伸缩、可扩展的网络应用。Netty线程模型是其核心特性之一,定义了Netty如何处理网络请求和响应,对应用程序的可伸缩性和性能有着重要影响。

  1. 单Reactor单线程模型
  • 特点: 所有IO操作(连接、接收、发送)都有一个线程来处理。
  • 使用场景:适用于并发连接数较小且业务处理简单的场景。
  • 优缺点:模型简单、没有线程上下文切换开销;但是一个线程处理所有IO操作,容易成为性能瓶颈。
  1. 单Reactor多线程模型
  • 特点:Reactor负责监听和分发事件,但不在处理具体的业务。业务逻辑处理由多个线程组成的线程池来完成。
  • 使用场景:适用于并发连接数较多但业务处理逻辑不是非常复杂的场景。
  • 优缺点:通过多线程处理业务逻辑,提高了系统的并发处理能力;但是Reactor仍然是一个潜在的性能瓶颈,特别是在高并发场景下。
  1. 主从Reactor多线程模型(Boss-Worker模型)
  • 特点:Netty主要基于这种模型,并做了一定的改进,他包含一个或者多个主Reactor和多个从Reactor。主Reactor负责监听和接收客户端的连接请求,并将接收到的连接分配给从Reactor处理。从Reactor负责具体的IO操作和业务逻辑处理。
  • 使用场景:适用于高并发、高负载的场景。
  • Netty实现:
    a. Boss Group:专门负责客户端连接,包含多个NioEventLoop(事件循环),每个 NioEventLoop负责监听和接收连接请求。
    b. Worker Group: 专门负责网络读写,包含多个NioEventLoop,每个NioEventLoop负责处理分配给他的连接上的IO事件,并通过ChannelPipeline中的ChannelHandler进行业务逻辑处理。
  • 优点:通过分离连接处理和IO操作,提高了系统的并发处理能力;灵活可扩展,可以根据需要调整线程池的大小。
    总结: Netty的线程模型是其高性能和可扩展的关键所在,通过合理选择线程模型,并根据应用场景调整线程池的大小,可以充分利用多核CPU的计算能力,提高系统的并发处理能力和吞吐量。在实际应用中,建议根据应用的具体需求和预期负载情况选择合适的线程模型。

2.6 无锁设计、线程绑定

Netty采用了串行无锁化设计,在IO线程内部进行串行操作。避免多线程竞争导致的性能下降,从表面上看,串行化设计似乎CPU利用率不高,并发程度不够,但是 通过调整NIO线程池的线程参数,可以同时启动多个串行化的线程并行执行,这种局部无锁化的串行线程相比一个队列多个工作线程模型性能更优。(换句话说:一个NioEvent事件由一个线程处理,启动多个线程来处理不同的事件,要比一个NioEvent事件多个线程处理性能更优,因为有线程切换、同步等的开销)
在这里插入图片描述
Netty的NioEventLoop读取到消息之后,直接调用ChannelPipeline的fireChannelRead,只要用户不主动切换线程,一直会由NioEventLoop调用到用户的Handler,期间不进行线程切换,这种串行化处理方式避免了多线程操作导致的锁的竞争,从性能角度看是最优的。

2.7 高性能的序列化框架

在Netty中,Google Protobuf是一个特别受欢迎的序列化框架,因为他在编解码速度和字节码流大小方面表现优异。是一种高效的结构化数据存储格式,具有良好的兼容性和可扩展性。

  • 高效:Protobuf的编码和解码速度非常快,且生成的二进制数据体积小,有利于网络传输和存储。
  • 跨平台:支持多种编程语言,可以轻松实现跨平台的数据交换。
  • 向后兼容:Protobuf更新不会破坏已经运行的数据格式的程序。

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

“小包封大包,防止网络阻塞” 这一策略,在网络通信中,特别是TCP/IP协议栈的实现中,是一个常见的优化手段。主要涉及到的是TCP的NAGLE算法。

  1. 算法概述:
  • NAGLE算法是一种避免发送大量小数据包的TCP/IP协议优化算法,当启用NAGLE算法是,TCP会将小的数据包缓存起来,而不是立即发送他们。只有当缓存区满了,或者收到了对之前发送数据的确认之后,才会将缓存的数据包合并成一个较大的数据包发送出去。这样做的目的是减少网络中的小数据包数量,从而降低网络拥塞的可能性,提高网络传输效率。
  1. 防止网络阻塞的原理
  • 减少小数据包数量:在网络通信中,小数据包的传输效率通常较低,因为他们会占用大量的网络带宽和处理器资源来处理头部信息和进行路由选择,通过合并小数据包为大数据包,可以减少这些开销,提高网络利用率。
  • 降低网络拥塞风险:大量小数据包的发送容易导致网络拥塞,因为每个数据包都需要单独的网络资源和处理时间。而合并后的大数据包则能够更有效的利用网络资源,减少拥塞的发生。
  • 优化TCP性能:TCP协议本身具有流量控制和拥塞控制机制,但这些机制在处理大量小数据包时可能会变得不够高效,通过NAGLE算法,TCP能够更智能的管理数据包的发送,从而提高整体性能。
  1. 注意事项
  • SO_TCPNODELAY:在Socket编程中,通过设置SO_TCPNODELAY选项来关闭NAGLE算法,当SO_TCPNODELAY被设置为1时,TCP会立即发送数据,而不是等待缓冲区满或者收到ACK后再发送。
  • 时延敏感应用:虽然NAGLE算法能够提高网络传输效率,但也增加了数据包的延迟。因此,时延敏感应用中,需要关闭NAGLE算法以确保数据及时传输。

2.9 软中断和基于Hash值的CPU绑定

在linux环境下,软中断和基于Hash值的CPU绑定是提高网络吞吐量和并行处理性能的重要手段。

  1. 软中断
  • 软中断是Linux内核中用于处理中断的一种机制,特别是在网络子系统中,他用于处理接收到的网络数据包,当网络接口接收到数据包时,他会产生一个硬件中断,这个中断被内核捕获并转化为软中断来处理。软中断的好处是可以减轻CPU负担,因为他允许中断在较低的优先级上执行,而不必立即中断当前CPU上的其他任务。
  • 在Linux内核版本2.6.35及以上,如果支持RPS(Receive Packet Steering 接收包引导)功能, 可以实现基于Hash值的软中断分发。RPC根据数据包的原地址、目的地址、目的和原端口等信息,计算出一个Hash值,然后根据这个Hash值来选择处理该数据包的软中断运行的CPU,这样,每个连接或者数据包类型都可以绑定到特定的CPU上,从而实现CPU的复杂均衡和并行处理。
  1. 基于Hash值的CPU绑定
  • CPU绑定是指将特定的任务或者线程固定到某个CPU核心上运行,以减少线程在CPU之间切换的开销。

总结:在Netty高性能网络通信中,软中断和CPU绑定是提高网络吞吐量和并行处理性能的重要策略。1. 软中断通过基于Hash值的分发机制,将数据包的处理任务均衡的分配给多个CPU核心2. 而CPU绑定则通过减少线程在CPU之间的切换开销,提高特定任务或者线程的执行效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值