目录
分布式之Netty介绍与实战(一)--Java IO与NIO
分布式之Netty介绍与实战(三)--Netty线程模型解析
分布式之Netty介绍与实战(四)--Netty编解码编程实战
Netty是什么
Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序
Netty 特性
- •设计
- 统一的API,适用于不同的协议(阻塞和非阻塞)
- 基于灵活、可扩展的事件驱动模型(SEDA)
- 高度可定制的线程模型
- 可靠的无连接数据Socket支持(UDP)
- •性能
- 更好的吞吐量,低延迟
- 更省资源
- 尽量减少不必要的内存拷贝
- •安全
- 完整的SSL/ TLS和STARTTLS的支持
- •易用
- 完善的Java doc,用户指南和样例
- 仅依赖于JDK1.6(netty 4.x)
Netty 主要组件
- •Netty 主要组件:
- Transport Channel ---- 对应NIO中的channel
- EventLoop ---- 对应于NIO中的while循环
- EventLoopGroup: 多个EventLoop
- ChannelHandler和ChannelPipeline --- 对应于NIO中的客户逻辑实现handleRead/handleWrite (interceptor pattern)
- ByteBuf ---- 对应于NIO 中的ByteBuffer
- Bootstrap 和 ServerBootstrap --- 对应NIO中的Selector、ServerSocketChannel等的创建、配置、启动等
- •Netty Server启动主要流程:
- 设置服务端ServerBootStrap启动参数
- group(parentGroup, childGroup):
- channel(NioServerSocketChannel): 设置通道类型
- handler():设置NioServerSocketChannel的ChannelHandlerPipeline
- childHandler(): 设置NioSocketChannel的ChannelHandlerPipeline
- 通过ServerBootStrap的bind方法启动服务端,bind方法会在parentGroup中注册NioServerScoketChannel,监听客户端的连接请求
- 会创建一个NioServerSocketChannel实例,并将其在parentGroup中进行注册
- Netty Server执行主要流程:
- ØClient发起连接CONNECT请求,parentGroup中的NioEventLoop不断轮循是否有新的客户端请求,如果有,ACCEPT事件触发
- ØACCEPT事件触发后,parentGroup中NioEventLoop会通过NioServerSocketChannel获取到对应的代表客户端的NioSocketChannel,并将其注册到childGroup中
- ØchildGroup中的NioEventLoop不断检测自己管理的NioSocketChannel是否有读写事件准备好,如果有的话,调用对应的ChannelHandler进行处理
Netty Transport - 传输层
- •提供了统一的API,支持不同类型的传输层:
- OIO -阻塞IO
- NIO - Java NIO
- Epoll - Linux Epoll(JNI)
- Local Transport - IntraVM调用
- Embedded Transport - 供测试使用的嵌入传输
- UDS - Unix套接字的本地传输
Netty EventLoop
- EventLoopGroup
- 包括多个EventLoop
- 多个EventLoop之间不交互
- •EventLoop:
- 每个EventLoop对应一个线程
- 所有连接(channel)都将注册到一个EventLoop,并且只注册到一个,整个生命周期中都不会变化
- 每个EventLoop管理着多个连接(channel)
- EventLoop来处理连接(Channel)上的读写事件
- ServerBootstrap
- 包括2个不同类型的EventLoopGroup:
- Parent EventLoop:负责处理Accept事件,接收请求
- Child EventLoop:负责处理读写事件
- 包括2个不同类型的EventLoopGroup:
Netty Buffers - ByteBuf
- 相比JDK ByteBuffer, 更加易于使用:
- 为读/写分别维护单独的指针,不需要通过flip()进行读/写模式切换
- 容量自动伸缩(类似于 ArrayList,StringBuilder)
- Fluent API (链式调用)
- 更好的性能:
- 通过内置的CompositeBuffer来减少数据拷贝(Zero copy)
- 支持内存池,减少GC压力
- ByteBuf通过两个索引(reader index、writer index)划分为三个区域:
- reader index前面的数据是已经读过的数据,这些数据可以丢弃
- 从reader index开始,到writer index之前的数据是可读数据
- 从writer index开始,为可写区域
Netty Buffers - ByteBuf主要操作
顺序读/写:- 改变reader/writer index
- writeByte()
- writeLong()
- writeXXX() - 增加write index
- readByte()
- readLong()
- readXXX() - 增加read index
随机读/写: - 不改变read/write index
- getXXX(index)
- setXXX(index, byte)
mark/reset:
- markReaderIndex()
- markWriterIndex()
- resetReaderIndex()
- resetWriterIndex()
- writerIndex(index)
- readerIndex(index)
discardReadBytes方法 - compact
clear方法
查询方法:
- indexOf
- bytesBefore
- forEachByte(ByteBufProcessor)
Derived Buffers(衍生缓冲区):
üduplicate()
üslice()
üslice(start, stop)
üunmodifiableBuffer(...),
Derived Buffers(衍生缓冲区)
- 具有各自的index和mark
- 返回的 ByteBuf 与原ByteBuf 共享底层存储
缓冲区拷贝
- copy() 或 copy(int, int)
- 返回的 ByteBuf 有数据的独立副本
Netty Buffers - ByteBuf的类型
-
根据内存的位置
- HeapByteBuf
- Ø基于数组- 内部为一个字节数组 (byte array)
- ØhasArray()返回True
- Øarray()返回其内部的数组,可以对数组进行直接操作
- –DirectByteBuf
- Ø堆外内存
- Ø具有更好的性能
- Ø创建和释放开销更大
- 根据是否使用内存池
- –Pooled vs Unpooled
- 根据是否使用Unsafe操作(Unsafe)
- –Safe vs Unsafe
Netty Buffers - CompositeByteBuf
•复合缓冲区(CompositeByteBuf)
- 多个ByteBuf组合的视图
- 一个ByteBuf列表,可动态的添加和删除其中的 ByteBuf
- 可能既包含堆缓冲区,也包含直接缓冲区
Netty Buffers - ByteBufHolder
ByteBufHolder
- 除ByteBuf外,还另外存储除有效的实际数据各种属性值
Netty Buffers - ByteBuf分配
不直接通过new来创建,而是通过ByteBufAllocator来创建
- UnpooledByteBufAllocator
- PooledByteBufAllocator
Netty Buffers - Unpooled工具类
•Unpooled 的工具类,它提供了静态的辅助方法来创建未池化的ByteBuf实例
Netty ChannelHandler
ChannelHandler - 业务处理核心逻辑,用户自定义
Netty 提供2个重要的 ChannelHandler 子接口:
- ChannelInboundHandler - 处理进站数据和所有状态更改事件
- ChannelOutboundHandler - 处理出站数据,允许拦截各种操作
Netty Channel状态及转换
Channel的状态及其转换如下图所示:
Netty Channel状态及转换
•当 ChannelHandler 添加到 ChannelPipeline,或者从ChannelPipeline 移除后,对应的方法将会被调用
Netty ChannelInboundHandler
•ChannelInboundHandler 回调方法在下表中:
- 当接收到数据或者与之关联的 Channel 状态改变时调用
- 与 Channel 的生命周期接近
Netty ChannelOutboundHandler
ChannelOutboundHandler回调方法在下表中:
Netty ChannelPipeline
•ChannelPipeline 是ChannelHandler容器
- •包括一系列的ChannelHandler 实例,用于拦截流经一个 Channel 的入站和出站事件
- •每个Channel都有一个其ChannelPipeline
- •可以修改 ChannelPipeline 通过动态添加和删除 ChannelHandler
- •定义了丰富的API调用来回应入站和出站事件
Netty ChannelHandlerContext
•ChannelHandlerContext表示 ChannelHandler 和ChannelPipeline 之间的关联
- 在 ChannelHandler 添加到 ChannelPipeline 时创建
•ChannelHandlerContext表示 ChannelHandler 和ChannelPipeline 之间的关联