这是我参与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连接
状态和事件回调
事件 说明 ChannelRegistered Channel 创建后被注册到EventLoop ChannelUnRegistered Channel创建后未注册或从EventLoop取消注册 ChannelActive Channel 处于就绪状态,可以被读写 ChannelInactive Channel处于非就绪状态 ChannelRead Channel可以从远程读取到数据 ChannelReadComplete Channel读取数据完成
事件调度层
通过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 等