netty
2021-01-11 09:59:01 10 举报
AI智能生成
Netty思维导图
作者其他创作
大纲/内容
基础知识
IO
阻塞(Block)
往往需要等待缓冲区中的数据准备好过后才处理其他的事情,否则一直等待在那里
非阻塞(Non-Block)
当我们的进程访问我们的数据缓冲区的时候,如果数据没有准备好则直接返回,不会等待。如果数据已经
准备好,也直接返回。
准备好,也直接返回。
同步(Synchronization)
应用程序要直接参与IO 读写的操作
异步(Asynchronous)
所有的IO 读写交给操作系统去处理,应用程序只需要等待通知
5 种主要 I/O 模式
BIO
BIO 是面向流的,阻塞IO(多线程)
NIO
NIO面向缓冲区,非阻塞IO(反应堆Rector),选择器(轮询机制)
缓冲区(Buffer)
通道(Channel)
选择器(Selector)
I/O 多路复用
select、poll、epoll
信号驱动 I/O
异步 I/O
AIO
NIO 升级版本,提供了异步非阻塞的 IO 操作方式
netty的 I/O 模型
基于非阻塞 I/O 实现
底层依赖 JDK NIO 框架的多路复用器 Selector
一个多路复用器 Selector 可以同时轮询多个 Channel
采用 epoll 模式后,只需要一个线程负责 Selector 的轮询,就可以接入成千上万的客户端
事件分发器有两种设计模式:Reactor 和 Proactor,Reactor 采用同步 I/O, Proactor 采用异步 I/O
netty优势
易用性
稳定性
可扩展性
更低的资源消耗
对象池复用技术
零拷贝技术
使用netty产品
服务治理:Apache Dubbo、gRPC
大数据:Hbase、Spark、Flink、Storm
搜索引擎:Elasticsearch
消息队列:RocketMQ、ActiveMQ
架构脉络
Netty 整体结构
Core 核心层
Protocol Support 协议支持层
Transport Service 传输服务层
Netty 逻辑架构
网络通信层
BootStrap、ServerBootStrap、Channel
事件调度层
EventLoopGroup、EventLoop
服务编排层
ChannelPipeline、ChannelHandler、ChannelHandlerContext
BootStrap
服务端启动过程
配置线程池
Netty Reactor 线程模型的具体实现方式
单线程模型:EventLoopGroup 只包含一个 EventLoop,Boss 和 Worker 使用同一个EventLoopGroup
多线程模型:EventLoopGroup 包含多个 EventLoop,Boss 和 Worker 使用同一个EventLoopGroup
主从多线程模型:EventLoopGroup 包含多个 EventLoop,Boss 是主 Reactor,Worker 是从 Reactor,它们分别使用不同的 EventLoopGroup,主 Reactor 负责新的网络连接 Channel 创建,然后把 Channel 注册到从 Reactor。
Channel 初始化
设置 Channel 类型
NioServerSocketChannel 异步 TCP 服务端
NioSocketChannel 异步 TCP 客户端
OioServerSocketChannel 同步 TCP 服务端
OioSocketChannel 同步 TCP 客户端
NioDatagramChannel 异步 UDP 连接
OioDatagramChannel 同步 UDP 连接
NioSocketChannel 异步 TCP 客户端
OioServerSocketChannel 同步 TCP 服务端
OioSocketChannel 同步 TCP 客户端
NioDatagramChannel 异步 UDP 连接
OioDatagramChannel 同步 UDP 连接
端口绑定
EventLoop
主从多线程模型
连接注册
Channel 建立后,注册至 Reactor 线程中的 Selector 选择器
事件轮询
轮询 Selector 选择器中已注册的所有 Channel 的 I/O 事件
事件分发
为准备就绪的 I/O 事件分配相应的处理线程
任务处理
Reactor 线程还负责任务队列中的非 I/O 任务,每个 Worker 线程从各自维护的任务队列中取出任务异步执行
事件处理机制
事件等待和处理的程序模型,可以解决多线程资源消耗高的问题
事件执行的方式通常分为立即执行、延后执行、定期执行
epoll 空轮询的 Bug
每次执行 Select 操作之前记录当前时间 currentTimeNanos
time - TimeUnit.MILLISECONDS.toNanos(timeoutMillis) >= currentTimeNanos,如果事件轮询的持续时间大于等于 timeoutMillis,那么说明是正常的,否则表明阻塞时间并未达到预期,可能触发了空轮询的 Bug
Netty 引入了计数变量 selectCnt。在正常情况下,selectCnt 会重置,否则会对 selectCnt 自增计数。当 selectCnt 达到 SELECTOR_AUTO_REBUILD_THRESHOLD(默认512) 阈值时,会触发重建 Selector 对象
任务处理机制
普通任务:通过 NioEventLoop 的 execute() 方法向任务队列 taskQueue 中添加任务
定时任务:通过调用 NioEventLoop 的 schedule() 方法向定时任务队列 scheduledTaskQueue 添加一个定时任务,用于周期性执行该任务
尾部队列:tailTasks 相比于普通任务队列优先级较低,在每次执行完 taskQueue 中任务后会去获取尾部队列中任务执行
Pipeline
ChannelPipeline
内部结构
负责调度各种类型的 ChannelHandler
每个 Channel 会绑定一个 ChannelPipeline
每个 ChannelPipeline 包含多个 ChannelHandlerContext
所有 ChannelHandlerContext 之间组成了双向链表
每个 ChannelHandler 都对应一个 ChannelHandlerContext,所以实际上 ChannelPipeline 维护的是它与 ChannelHandlerContext 的关系
ChannelHandler
接口设计
ChannelInboundHandler
ChannelOutboundHandler
Inbound 事件和 Outbound 事件的传播方向相反,Inbound 事件的传播方向为 Head -> Tail,而 Outbound 事件传播方向是 Tail -> Head
粘包/拆包
定义应用层的通信协议
消息长度固定
特定分隔符
消息长度 + 消息内容
魔数 2byte | 协议版本号 1byte | 序列化算法 1byte | 报文类型 1byte | 状态 1byte |保留字段 4byte|数据长度 4byte| 数据内容(长度不定)
Netty 常用编码器类型
MessageToByteEncoder 对象编码成字节流
MessageToMessageEncoder 一种消息类型编码成另外一种消息类型
Netty 常用解码器类型
ByteToMessageDecoder/ReplayingDecoder 将字节流解码为消息对象
MessageToMessageDecoder 将一种消息类型解码为另外一种消息类型
常用的解码器
固定长度解码器 FixedLengthFrameDecoder
特殊分隔符解码器 DelimiterBasedFrameDecoder
长度域解码器 LengthFieldBasedFrameDecoder
堆外内存
ByteBuffer#allocateDirect
DirectByteBuffer
Unsafe#allocateMemory
分配的内存必须自己手动释放
ByteBuf
相比于 ByteBuffer的优势
容量可以按需动态扩展,类似于 StringBuffer;
读写采用了不同的指针,读写模式可以随意切换,不需要调用 flip 方法
通过内置的复合缓冲类型可以实现零拷贝
支持引用计数
支持缓存池
内部结构
废弃字节
可读字节
可写字节
可扩容字节
内存分配器 jemalloc
Netty零拷贝技术
堆外内存,避免 JVM 堆内存到堆外内存的数据拷贝
CompositeByteBuf 类可以组合多个 Buffer 对象合并成一个逻辑上的对象,避免通过传统内存拷贝的方式将几个 Buffer 合并成一个大的 Buffer
通过 Unpooled.wrappedBuffer 可以将 byte 数组包装成 ByteBuf 对象,包装过程中不会产生内存拷贝。
ByteBuf.slice 操作与 Unpooled.wrappedBuffer 相反,slice 操作可以将一个 ByteBuf 对象切分成多个 ByteBuf 对象,切分过程中不会产生内存拷贝,底层共享一个 byte 数组的存储空间
Netty 使用 FileRegion 实现文件传输,FileRegion 底层封装了 FileChannel#transferTo() 方法,可以将文件缓冲区的数据直接传输到目标 Channel,避免内核缓冲区和用户态缓冲区之间的数据拷贝,这属于操作系统级别的零拷贝
0 条评论
下一页