首页 > 其他分享 >Netty

Netty

时间:2023-06-04 10:22:38浏览次数:38  
标签:Netty 异步 Selector handler 线程 连接 channel

目录

Netty概述

Java BIO编程

  • 创建ServerSocket,绑定端口,接收客户端连接请求,为每个连接都创建一个线程处理,没有数据交互时进行阻塞

Java NIO编程

  • Non-blocking IO,同步非阻塞
    • 创建ServerSocketChannel,绑定端口,设置非阻塞
    • 创建Selector,向Selector注册ServerSocketChannel,监听事件(OP_ACCEPT,用于接收请求)
    • Selector.select()进行阻塞等待连接
    • 客户端连接后select()响应处理连接请求,接收请求后,将每个请求的channel注册到Selector,监听事件(OP_READ,用于读取数据)
    • Selector有连接事件或者读数据事件时进行处理该事件(如果有多个事件到来分别处理,事件驱动)
  • 三大核心部分:Channel,Buffer,Selector
    • 一个channel对应一个buffer
    • 多个channel可以注册到一个selector上
    • 一个selector对应一个线程
  • 是面向缓冲区或块编程,数据读取到缓冲区,使用缓冲区可以提供非阻塞的高伸缩网络
  • 事件驱动

Buffer

缓存,基本类型除了boolean类型,都有对应的Buffer类

Channel

类似于流,但有以下区别:

  • 通道可以同时进行读写,流只能读或者写
  • 通道可以实现异步读写,流的读写是同步的
  • 通道可以从缓冲区读数据,也可以写数据到缓冲区

常用channel

  • FileChannel(文件读写)
  • DatagramChannel(UDP数据读写)
  • ServerSocketChannel、SocketChannel(TCP数据读写)

Selector

可以注册多个channel到selector(封装成SelectionKey),通过selector的select方法可以获取到有事件发生的channel,返回SelectionKey,进而获取到有事件发的channel

Netty

NIO问题:

  • 类库及api繁杂,使用麻烦,需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等
  • 需要具备其他的额外技能:要熟悉Java多线程编程,因为NIO编程涉及Reactor模式,需要对多线程和网络编程非常熟悉,才能写出高质量的NIO程序
  • 开发工作量和难度非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常流的处理等
  • NIO的bug:如臭名昭著的epoll bug,导致selector空轮询,最终导致cpu 100%,直到jdk1.7问题仍然存在

Netty是由JBOSS提供的一个Java开源框架,Netty提供异步的、基于事件驱动的网络应用框架,用以快速开发高性能、高可靠的网络IO程序。

Netty可以快速、简单的开发出一个网络应用,简化和流程化了NIO的开发过程。是目前最流行的NIO框架,在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,如elasticsearch、dubbo框架内部都使用了netty

线程模型

线程模型:传统阻塞IO服务模型、Reactor模型

根据reactor的数量和处理资源线程池的数量不同,有三种典型的实现:单Reactor单线程、单Reactor多线程、主从Reactor多线程(nginx、memcached、netty)

netty主要基于主从Reactor多线程模型做了一定的改进,主从Reactor有多个Reactor

Reactor:

  • 基于IO复用模型:多个连接共用一个阻塞对象,应用程序只要在一个阻塞对象等待,无序阻塞等待所有连接。当某个连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理
  • 基于线程池复用线程资源:不必为每个连接创建线程,将连接完成后的业务处理任务分配给线程处理,一个线程可以处理多个连接的业务

netty线程模型:

  • 有两个线程组,bossGroup、workGroup,前者用于处理连接,后者用于网络IO的读写
  • NioEventLoop表示一个不断循环执行处理任务的线程,每个NIOEventLoop都有一个Selector,用于监听绑定在其上的socket网络通道,内部采用串行化设计,从消息的读取、解码、处理、编码、发送,都由该线程NioEventLoop负责
  • NioEventLoopGroup下包含了多个NioEventLoop,每个NioEventLoop包含一个Selector、一个TaskQueue
  • 每个NioEventLoop的Selector上可以注册多个NioChannel,每个NioChannel只会绑定到一个NioEventLoop上(它的Selector),每个NioChannel都会绑定一个自己的ChannelPipline

异步自定义任务

  • 自定义普通任务:ctx.channle().eventLoop().execute()
  • 定时任务:ctx.channle().eventLoop().schedule()

异步模型原理

ChannelFuture,IO操作的异步结果

Netty核心模块组件

  • Bootstrap、ServerBootstrap
  • Future、ChannelFuture
  • Channel,涵盖了tcp及udp网络io及文件io
    • NioSocketChannel,异步客户端tcp socket连接
    • NioServerSocketChannel,异步服务端tcp socket连接
    • NioDatagramChannel,异步udp连接
    • NIOSctpChannel,异步客户端sctp连接
    • NioSctpServerChannel,异步的sctp服务器端连接
  • Selector
    • netty基于Selector对象实现IO多路复用,通过Selector实现一个线程可以监听多个连接的channel事件
    • 向一个Selector注册channel之后,Selector内部的机制就可以自动不断的查询这些注册的channel是否有已就绪的io事件(如可读、可写、连接完成等),这样就可以很简单的使用一个线程高效的管理多个channel
  • ChannelHandler,是一个接口,处理IO事件,并将其转发到ChannelPipeline的下一个处理程序中
  • Pipeline、ChannelPipeline,ChannelPipeline是Handler的一个集合,每个Handler对应一个ChannelHandlerContext(实际实现是DefaultChannelHandlerContext)
  • Unpooled类,netty提供的一个专门用来操作缓冲区的工具类(netty的数据容器)
    • ByteBuf,不需要flip,有读写指针
      • Unpooled.buffer(10),10字节大小的缓存
      • Unpooled.copiedBuffer("hello", StandardCharsets.UTF_8),从字符串创建,实际容量大小可能比内容大

心跳机制

IdleStateHandler

WebSocket长连接

WebSocket是http协议的升级,会通过http返回101状态码进行升级协议

Protobuf

netty提供了一些编解码器:StringEncoder/StringDecoder、ObjectEncoder/ObjectDecoder(底层使用的仍然是java序列化技术,而java序列化本身效率就不高,无法跨语言、序列化后体积大,是二进制编码的5倍多,序列化性能低)

编写proto文件,使用插件生成java实体类,在handler中加入protobuf的编解码器及业务handler

Netty提供的编解码器

  • ReplayingDecoder,扩展了ByteToMessage类,使用这个类就不用调用readableBytes()方法判断字节数了,参数S指定用户状态管理的类型,Void表示不需要状态管理
    • 缺点:
      • 并不是所有的ByteBuf都支持,如果调用了一个不被支持的方法,会抛出UOE
      • 在某些情况下可能稍慢于ByteToMessageDecoder,比如当网络缓慢并且消息格式复杂时,消息会被拆分成多个碎片,速度会变慢
  • LineBasedFrameDecoder,使用行尾控制字符(\n或\r\n)
  • DelimiterBasedFrameDecoder,使用自定义的特殊字符作为消息的分隔符
  • HttpObjectDecoder,http数据的编解码器
  • LengthFieldBasedFrameDecoder,通过指定长度来标识整包消息,这样就可以自动处理粘包和半包消息

TCP粘包和拆包

tcp是面向连接的、面向流的、提供高可靠服务。收发两端都要有一一成对的socket,发送端为了提高发送效率,使用了优化算法nagle算法,将多次间隔较小且数据量小的数据合成一个大的数据块 然后进行封包。虽然提高了效率,但是接收端就很难分辨出完整的数据包了,因为面向流的通信是无消息保护边界的。

由于tcp无消息保护边界,需要在接收端处理消息边界问题,也解释粘包、拆包问题。

使用自定义协议解决

如每次发送消息先发送一个int字节的数据长度,再发送该长度字节的数据

源码分析

启动源码

  • NioEventLoopGroup的创建
  • ServerBootstrap的创建

三大核心组件

  • ChannelPipeline,ChannelHandler,ChannelHandlerContext

心跳handler

  • IdleStateHandler,ReadTimeoutHandler,WriteTimeoutHandler,检测连接有效性

IdleStateHandler,当连接的空闲时间(读或写)太长时,将会触发一个IdleStateEvent事件,可以在Inbound中重写userEventTriggered方法处理该事件

ReadTimeoutHandler,在指定的时间内,如果没有读事件就会抛出异常,并自动关闭连接

WriteTimeoutHandler,一个写操作在指定的时间内没有完成时,就会抛出异常,并关闭连接

EventLoop

线程池

  • handler中加入线程池
    ctx.channel().eventLoop().execute(),实际执行的也是当前handler的线程

  • context中添加线程池

在netty中做耗时的,不可预料的操作,比如数据库、网络请求、会严重影响netty对socket的处理速度。解决办法是将耗时任务添加到异步线程池中

  • handler中加入线程池:在handler中创建一个DefaultEventExecutorGroup,被所有handler共享
  • context中添加线程池:在创建server时,创建一个DefaultEventExecutorGroup,添加handler时指定该group,那么handler的处理会优先使用该group
    • AbstractChannelHandlerContext的invokeChannelRead方法执行时,会判断executor是不是在当前线程,如果在当前线程会直接执行,如果不在当前线程(这个handler在之前提交的group中),会异步提交到group中执行

比较:

  • 在handler中添加异步,更加自由,比如如果需要访问数据库就异步,不需要就不异步,异步会拖长接口响应时间,因为需要将任务放入task中,如果io时间很短,task很多,可能一个循环下来,都没时间执行整个task,导致响应时间过长。
  • 在context中添加时netty的标准方式(加入到队列),这么做会将整个handler都交给设置的业务线程池,不管耗不耗时,都加入到队列,不够灵活
  • 从灵活性考虑,第一种较好

自定义协议实现RPC

  • 定义公共接口,消费者端使用代理获取服务代理,在进行rpc时连接服务端进行通信调用

标签:Netty,异步,Selector,handler,线程,连接,channel
From: https://www.cnblogs.com/bingmous/p/17396511.html

相关文章

  • Netty实战(十)
    (编解码器框架)一、什么是编解码器框架网络只将数据看作是原始的字节序列。但我们的应用程序则会把这些字节组织成有意义的信息。在数据和网络字节流之间做相互转换是最常见的编程任务之一。例如,我们可能需要处理标准的格式或者协议(如FTP或Telnet)、实现一种由第三方定义的专......
  • 【Netty实战】1~3章学习笔记
    1.Netty总体结构1.1Netty简介​ Netty是一款用于创建高性能网络应用程序的高级框架。它的基于JavaNIO的异步的和事件驱动的实现,保证了高负载下应用程序性能的最大化和可伸缩性。​ 其次,Netty也包含了一组设计模式,将应用程序逻辑从网络层解耦,简化了开发过程,同时也最大限度......
  • ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync
    EStransportclient底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用!因此,EStransportclient可以同步调用也可以异步(不过底层的socket必然是异步实现)。发送端例子对于javaclient的数据发送(这里以bulk为例),写过的人都知......
  • Netty实战(八)
    (引导)一、引导1.1什么是引导引导一个应用程序是指对它进行配置,并使它运行起来的过程。引导可以简单的认为是将分散的了ChannelPipeline、ChannelHandler和EventLoop组合起来,成为一个完成应用程序的模块。1.2Bootstrap类引导类的层次结构包括一个抽象的父类和两个具体......
  • Netty零拷贝
    传统读取IO流的操作读操作1、应用程序发起读数据操作,JVM会发起read()系统调用。2、这时操作系统OS会进行一次上下文切换(把用户空间切换到内核空间)3、通过磁盘控制器把数据copy到内核缓冲区中,这里的就发生了一次DMACopy4、然后内核将数据copy到用户空间的应用缓冲区中,发生了......
  • Netty实战(七)
    (EventLoop和线程模型)一、什么是线程模型简单地说,线程模型指定了操作系统、编程语言、框架或者应用程序的上下文中的线程管理的关键方面。在早期的Java语言中,我们使用多线程处理的主要方式无非是按需创建和启动新的Thread来执行并发的任务单元,这种在高负载下表现得很原......
  • Netty实战(六)
    (ChannelHandler和ChannelPipeline)一、ChannelHandler1.1Channel的生命周期Channel主要有四个生命周期向下表所示:状态描述ChannelUnregisteredChannel已经被创建,但还未注册到EventLoopChannelRegisteredChannel已经被注册到了EventLoopChannelActiv......
  • Netty+Nacos+Disruptor自研企业级API网关-江潭落月复西斜
    Netty+Nacos+Disruptor自研企业级API网关download:3w51xuebccom使用Netty和SpringBoot实现仿微信的示例在本文中,我们将使用Netty和SpringBoot框架来创建一个简单的聊天应用程序,类似于微信。这个应用程序将支持多用户聊天和即时消息发送。下面让我们来一步步看看如何实现。第一步......
  • Netty实战(五)
    (ByteBuf—Netty的数据容器)一、什么是ByteBuf我们前面说过,网络数据的基本单位总是字节。JavaNIO提供了ByteBuffer作为它的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐。ByteBuffer替代品是ByteBuf,一个强大的实现,既解决了JDKAPI的局限性,又为网络应用程序的开发者......
  • Netty实战(五)
    一、什么是ByteBuf我们前面说过,网络数据的基本单位总是字节。JavaNIO提供了ByteBuffer作为它的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐。ByteBuffer替代品是ByteBuf,一个强大的实现,既解决了JDKAPI的局限性,又为网络应用程序的开发者提供了更好的API。下面我......