Netty基础

183 阅读6分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

IO基础

IO请求分成两个阶段, 分别是

  • 调用阶段, 用户进程向内核发起系统调用
  • 执行阶段, 内核等待I/O请求处理完成返回, 分为两个过程, 首先等待数据就绪,并写入内核缓冲区, 随后将内核缓冲区数据拷贝到用户态缓冲区

五种IO

同步阻塞I/O (BIO)

应用进程向内核发起I/O 请求, 发起调用的线程等待内核返回结果, 一次完整的I/O 请求称为BIO, 实现异步只能通过多线程模型

同步非阻塞I/O(NIO)

应用进程向内核发起I/O 请求, 请求后不再同步等待结果,而是立即返回, 通过轮询的方式获取请求结果,NIO相比BIO大幅提升性能, 但轮询过程中大量的系统调用导致上下文切换很大, 单独使用非阻塞I/O 效率并不高,并发量提升, 非阻塞I/O 存在严重的性能浪费

多路复用

多路复用实现了一个线程处理多个I/O句柄操作, 多路指的是多个数据通道, 复用指使用一个或多个固定线程来处理每一个socket, select,poll, epoll都是I/O多路复用的具体实现, 线程一次select调用可以获取内核态中多个数据通道的数据状态。解决了同步阻塞I/O和同步非阻塞I/O的问题。

信号驱动I/O

半异步的I/O模型, 数据准备就绪时,内核通过发送SIGIO信号通知应用进程

异步I/O

从内核缓冲区拷贝数据到用户缓冲区的过程也是系统异步完成,进程只需要在指定的数组中引用数据即可。信号驱动I/O 由内核通知何时可以开始一个I/O操作, 异步I/O由内核通知I/O操作何时已经完成。

Netty的I/O模型基于非阻塞I/O,底层依赖Selector, 一个多路复用器Selector可以同时轮询多个Channel,多路复用场景下,当有数据处于就绪状态,一个事件分发器(Event Dispatcher) 将读写事件分发给对应的读写事件处理器(Event Handler)。 事件分发器有两种Reactor(同步I/O)和Proactor(异步I/O)。

Netty相比NIO优势

易用性 稳定性 可扩展性

更低的资源消耗: 对象池复用技术, 零拷贝技术

相比Tomcat

Tomcat是HTTP Server, 解决Http协议层传输, Netty还支持SSH, TLS/SSL应用层协议, 而且可以自定义应用层协议

整体架构

Core核心层

提供了底层网络通信的通用抽象和实现。包括可扩展的事件模型, 通用的通信API, 支持零拷贝的ByteBuf。

Protocol Support 协议支持层

协议支持层覆盖了主流协议的编解码实现,HTTP, SSL, Protobuf, 压缩, 大文件传输, WebSocket, 文本,二进制等主流协议,自定义应用层协议。

Transport Service 传输服务层

提供了网络传输能力的定义和实现方法,支持Socket, HTTP隧道, 虚拟机管道等传输方式,对TCP,UDP等做了抽象和封装。

逻辑架构

网络通信层

执行网络I/O操作, 支持多种网络协议和I/O 模型的连接操作, 当网络数据读取到内核缓冲区后, 会触发各种网络事件, 事件会分发给事件调度层处理

核心组件包含BootStrap, ServerBootStrap, Channel三个组件

  • BootStrap & ServerBootStrap

    继承AbstractBootstrap,两者之间的区别是BootStrap可用于连接远程服务器,只绑定一个EventLoop, 而ServerBootStrap用于服务端启动绑定本地端口,会绑定两个EventLoopGroup, 通常称为Boss和Worker。 Boss不停地接收连接, 然后将连接分配给一个个Worker处理连接

  • Channel

    提供了基本API用于网络I/O 操作, 常用的Channel实现类:

    • NIOServerSocketChannel 异步TCP服务端
    • NIOSocketChannel 异步TCP客户端
    • OioServerSocketChannel 同步TCP服务端
    • OioSocketChannel 同步TCP客户端
    • NioDatagramChannel 异步UDP连接
    • OioDatagramChannel 同步UDP连接

    状态和事件回调

    事件说明
    ChannelRegisteredChannel 创建后被注册到EventLoop
    ChannelUnRegisteredChannel创建后未注册或从EventLoop取消注册
    ChannelActiveChannel 处于就绪状态,可以被读写
    ChannelInactiveChannel处于非就绪状态
    ChannelReadChannel可以从远程读取到数据
    ChannelReadCompleteChannel读取数据完成

事件调度层

通过Reactor线程模型对各类事件进行聚合处理,通过Selector主循环线程集成多种事件(I/O, 信号,定时), 实际的业务处理逻辑交由服务编排层中的Handler完成

核心组件: EventLoopGroup , EventLoop

  • EventLoopGroup & EventLoop

    EventLoopGroup本质是一个线程池, 主要负责接收I/O请求,并分配线程执行处理请求

    一个EventLoopGroup包含一个或多个EventLoop。EventLoop用于处理Channel生命周期内的所有I/O事件, 如accept, connect, read,write等I/O 事件

    EventLoop同一时间会与一个线程绑定, 每个EventLoop负责多个Channel

    每新建一个Channel, EventLoopGroup会选择一个EventLoop与其绑定, Channel在生命周期内可以对EventLoop进行多次绑定和解耦

    EventLoop是EventLoopGroup的子接口,EventLoopGroup的实现类是NioEventLoopGroup, NioEventLoopGroup继承MultithreadEventLoopGroup,Netty通过创建不同的EventLoopGroup参数配置,支持Reactor的三种线程模型

    • 单线程模型: EventLoopGroup只包含一个EventLoop,Boss和worker使用同一个EventLoopGroup
    • 多线程模型: EventLoopGroup包含多个EventLoop, Boss和Worker使用一个EventLoop
    • 主从多线程模型, EventLoopGroup包含多个EventLoop, Boss是主Reactor, Worker是从Reactor, 分别使用不同的EventLoopGroup, 主Reactor负责新的网络连接Channel创建, 然后把Channel注册到从Reactor

事件编排层

负责组装各类服务,核心处理链,实现网络事件的动态编排和有序传播

核心组件: ChannelPipeline, ChannelHandler, ChannelHandlerContext

  • ChannelPipeline

    组装各种ChannelHandler, ChannelHandler的实例双向列表, IO事件触发,ChannelPipeline会依次调用ChannelHandler列表对Channel数据进行拦截和处理

    ChannelPipeline线程安全,每一个新的Channel都会绑定一个新的ChannelPipeline, 一个ChannelPipeline关联一个EventLoop, 一个EventLoop仅会绑定一个线程

    ChannelInboundHandler和ChannelOutboundHandler两种处理器

  • ChannelHandler & ChannelHandlerContext

    ChannelHandlerContext用于保存ChannelHandler上下文, 通过 ChannelHandlerContext 可以知道 ChannelPipeline 和 ChannelHandler 的关联关系。ChannelHandlerContext 可以实现 ChannelHandler 之间的交互,ChannelHandlerContext 包含了 ChannelHandler 生命周期的所有事件,如 connect、bind、read、flush、write、close 等