Netty——为什么Netty性能如此之高?

  • Post author:
  • Post category:其他


Netty高性能之道


目录


Netty高性能之道


1、Netty模型


2、Netty性能高的原因


1、Netty模型


netty线程模型采用“服务端监听线程”和“IO线程”分离的方式,与多线程Reactor模型类似。

抽象出NioEventLoop来表示一个不断循环执行处理任务的线程,每个NioEventLoop有一个selector,用于监听绑定在其上的socket链路。


说明:


1) Netty抽象出两组线程池 BossGroup专门负责接收客户端的连接, Worker Group专门负责网络的读写


2) Boss Group和 Worker Group类型都是 NioEventLoopGroup


3) NioEventLoop Giroup相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环是 NioEventLoop


4) NioEventLoop表示一个不断循环的执行处理任务的线程,每个 NioEventLoop都有一个 selector,用于监听绑定在其上的 socket的网络通讯


5) NioEventLoop Group可以有多个线程,即可以含有多个 NioE:ventLoop


6)每个 Boss NioEventLoop循环执行的步骤有3步


1.轮询 accept事件


2.处理 accept事件,与 client建立连接,生成 NioScocketchannel,并将其注册到某个 worker NIOEventLoop上的 selector


3.处理任务队列的任务,即 runAllTasks


7)每个 Worker NIOEventLoop循环执行的步骤


1.轮询read, write事件


2.处理0事件,即ead,wite事件,在对应 NioScocketChannel处理


3.处理任务队列的任务,即 runAlllask


8)每个 Worker NIOE ventloop处理业务时,会使用 pipeline管道, pipeline中包含了 channel,即通过 pipeline可以获取到对应通道,管道中维护了很多的处理器

2、Netty性能高的原因


  • 非阻塞IO

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


  • 高效的Reactor线程模型

    Netty服务端采用Reactor主从多线程模型

    1. 主线程:Acceptor 线程池用于监听Client 的TCP 连接请求

    2. 从线程:Client 的IO 操作都由一个特定的NIO 线程池负责,负责消息的读取、解码、编码和发送

    3. Client连接有很多,但是NIO 线程数是比较少的,一个NIO 线程可以同时绑定到多个Client,同时一个Client只能对应一个线程,避免出现线程安全问题


  • 无锁化串行设计

    串行设计:消息的处理尽可能在一个线程内完成,期间不进行线程切换,避免了多线程竞争和同步锁的使用


  • 高效的并发编程

    Netty 的高效并发编程主要体现在如下几点

    1. volatile 的大量、正确使用

    2. CAS 和原子类的广泛使用

    3. 线程安全容器的使用

    4. 通过读写锁提升并发性能


  • 高性能的序列化框架

    Netty 默认提供了对Google Protobuf 的支持,通过扩展Netty 的编解码接口,可以实现其它的高性能序列化框架


  • 零拷贝


    1. Netty 的接收和发送ByteBuffer 采用DirectByteBuffer,使用堆外直接内存进行Socket 读写,不需要进行字节缓冲区的二次拷贝

      。如果使用传统的堆内存(HeapByteBuffer)进行Socket 读写,JVM 会将堆内存Buffer 拷贝一份到直接内存中,然后才写入Socket 中。

      相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝

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


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


  • 内存池

    基于对象池的 ByteBuf可以重用 ByteBuf对象,内部维护了一个内存池,可以循环利用已创建的 ByteBuf,提升内存的使用效率,降低由于高负载导致的频繁GC。测试表明使用内存池后的Nety在高负载、大并发的冲击下内存和GC更加平稳


  • 灵活的TCP 参数配置能力

    合理设置TCP 参数在某些场景下对于性能的提升可以起到显著的效果,例如SO_RCVBUF 和SO_SNDBUF。如果设置不当,对性能的影响是非常大的

    1. SO_RCVBUF 和SO_SNDBUF:通常建议值为128K 或者256K;

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

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



版权声明:本文为qqq3117004957原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。