Netty知识点
2020-02-11 12:02:52 0 举报
AI智能生成
Netty知识点 知识图谱 架构
作者其他创作
大纲/内容
1、JavaNIO介绍
1、JAVA网络IO基础知识
1.OSI 七层网络
2.TCP和UDP
TCP 是面向连接的、可靠的流协议,通讯完成时要拆除连接
UDP是面向无连接的通讯协议,UDP通讯时不需要接收方确认,属于不可靠的传输,可能会出现丢包现象。
3.Socket
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口
4.Linux IO模型
同步
1.阻塞io (blocking i/o)
2.非阻塞io (non blocking i/o)
3.IO多路复用 (mulitplexing i/o)
最大连接数
select
单个进程的最大连接数受FD_SETSIZE限制
poll
没有最大连接数限制
epoll
连接数有限制,但是很大
FD剧增带来的io效率
select
FD增加会造成遍历速度慢的线性下降性能问题
poll
同上
epoll
scoket活跃数少,性能好,反之,性能差
消息传递方式
select
内核将消息传递到用户空间
poll
同上
epoll
内核和用户空间共享一块内存
4.信号驱动 (signal driven i/o)
异步
1.异步io (asyncchronous i/o)
5.应用程序如何获取数据
数据准备
数据拷贝
6.IO基础入门
Linux网络IO模型简介
IO编程
关键示例
IOServer.java
ServerSocket serverSocket = new ServerSocket(8000)
InputStream inputStream = socket.getInputStream()
Server 端首先创建了一个serverSocket来监听 8000 端口,然后创建一个线程,线程里面不断调用阻塞方法 serversocket.accept();
IOClient.java
Socket socket = new Socket("127.0.0.1", 8000);
socket.getOutputStream().write((new Date() + ": hello world").getBytes());
系统庞大后存在的问题
线程资源受限:线程是操作系统中非常宝贵的资源,同一时刻有大量的线程处于阻塞状态是非常严重的资源浪费,操作系统耗不起
线程切换效率低下:单机 CPU 核数固定,线程爆炸之后操作系统频繁进行线程切换,应用性能急剧下降。
IO 编程中,我们看到数据读写是以字节流为单位。
IO多路复用技术
2、NIO入门
传统的BIO编程
BIO通信模型图
同步阻塞式IO创建的TimeServer源码分析
同步阻塞式IO创建的TimeClient源码分析
伪异步IO编程
伪异步IO模型图
伪异步IO创建的TimeServer源码分析
伪异步IO弊端分析
NIO编程
NIO类库简介
NIO服务端序列图
NIO创建的TimeServer源码分析
NIO客户端时序图
NIO创建的TimeClient源码分析
AIO编程
AIO创建的TimeServer源码分析
AIO创建的TimeClient源码分析
AIO版本时间服务器运行结果
选择Netty的理由
不选择Java原生NIO编程的原因
为什么选择Netty
2、Netty NIO开发
3、Netty入门应用
消息资源管理
Netty如何管理资源
业务逻辑如何处理消息
发送消息方式
ChannelHandlerContext.write()
ChannelPipeline.write()
Channel.write()
Channel关闭方式
ChannelHandlerContext.close()
Channel.close()
内存管理
需要手动释放的场景
Netty默认会在ChannelPipline的最后添加一个tail handler帮你完成ByteBuf的release
如果中途没有使用fireChannelRead传递下去也要自己释放
通过Channel或ChannelHandlerContext创建的但是没有传递下去的ByteBuf也要手动释放
内存泄露监测
ResourceLeakDetector
检测级别
DISABLE
SIMPLE(默认)
ADVANCED
PARANOID
参数设置
java -Dio.netty.leakDetectionLevel=ADVANCED
特定场景
NIO
非阻塞传输,基于java.nio
Epoll
非阻塞传输,基于JNI的epoll,只支持linux,性能优于NIO。linux-2.5.44(2002)+
OIO
阻塞传输,基于java.net
Local
本地传输,在VM内部通过管道通讯
Embedded
测试使用
启动类
EventExecutorGroup
ServerBootstrap
EventLoopGroup
NioEventLoopGroup
shutdownGracefully()
Future
ServerChannel
NioServerSocketChannel
member ChannelPipeline
ChannelHandler
abstractChannelInitializer
initChannel()
bind()
ChannelFuture
ChannelPipeline
Future
ScheduledFuture
第三方序列化框架的支持
MsgpackDecoder
MsgpackEncoder
ProtobufDecoder
ProtobufEncoder
ProtobufVarint32FrameDecoder(处理半包)
ProtobufVarint32LengthFieldPrepender(处理半包)
内存API
PooledByteBufAllocator
ChannelHandlerContext.alloc()
UnpooledByteBufAllocator
Unpooled
Unpooled.directBuffer()
Unpooled.buffer()
Unpooled.copiedBuffer()
ByteBuf
ByteBuf.order()
ByteBuf.duplicate()
事件传递
InBound
AbstractNioByteChannel.read()
DefaultChannelPipeline.fireChannelRead()
head
HeadContext
ChannelHandlerContext
head.invokeChannelRead()
ChannelInboundHandler.channelRead()
ctx.fireChannelRead()
fireChannelRead()
next
ChannelHandlerContext
next.invokeChannelRead()
OutBound
Channel.write()
ChannelPipeline.write()
ChannelPipeline.write()
TailContext
ChannelHandlerContext
tail.write()
ChannelHandlerContext.write()
next
ChannelHandlerContext
next.invokeWrite()
invokeWrite0
ChannelOutboundHandler.write()
ChannelHandlerContext
ctx.write()
write()
4、TCP粘包拆包问题的解决之道
tcp粘包
发生原因
write写入字节大于sendBuffer大小
进行MSS大小的Segment分段
以太网帧的payload大于MTU
解决策略
消息定长
消息尾分隔符
分为消息头消息体,头中包含消息长度
LineBasedFrameDecoder
FixedLengthFrameDecoder
DelimiterBasedFrameDecoder
TCP粘包拆包
TCP粘包拆包问题说明
TCP粘包拆包发生的原因
粘包问题的解决策略
TCP的半包,粘包
原因
半包
1.可能是IP分片传输导致
2.传输过程中丢失部分包导致出现的半包
3.一个包可能被分成了两次传输,在取数据的时候,先取到了一部分
粘包
1.发送数据过大,那么他本身会启用Nagle算法(可配置是否启用)对较小的数据包进行合并
2.如果消息没有被及时从缓存区取走,下次在取数据的时候可能就会出现一次取出多个数据包的情况
如何解决
加分割符
长度
消息头(消息体长度)
netty 自带解码器解决这个问题
LineBasedFrameDecoder
利用\n,\r行尾加标识符
FixedLengthFrameDecoder
利用消息长度
LengthFieldPrepender
子主题
DelimiterBasedFrameDecoder
利用自定义分隔符
编码器
未考虑TCP粘包导致功能异常案例
TimeServer的改造
TimeClient的改造
运行结果
利用LineBasedFrameDecoder解决TCP粘包问题
支持TCP粘包的TimeServer
支持TCP粘包的TimeClient
运行支持TCP粘包的时间服务器程序
LineBasedFrameDecoder和StringDecoder的原理分析
5、分隔符和定长解码器的应用
DelimiterBasedFrameDecoder应用开发
DelimiterBasedFrameDecoder服务端开发
DelimiterBaseFrameDecoder客户端开发
运行DelimiterBasedFrameDecoder服务端和客户端
FixedLenthFrameDecoder应用开发
FixedLengthFrameDecoder服务端开发
利用telnet命令行测试EchoServer服务端
3、Netty编解码开发
6、编解码技术
java序列化的缺点
无法跨语言
序列化后的码流太大
序列化性能太低
业界主流的编码解码框架
google的protobuf
facebook的thrift
jboss的marshalling
客户端与服务端通信协议编解码
通信协议的设计
分支主题
服务端与客户端交互,双方协商出来的满足一定规则的二进制数据格式
编码
Java 对象根据协议封装成二进制数据包的过程成为编码public ByteBuf encode(Packet packet) {// .... return byteBuf;}
// 1. 创建 ByteBuf 对象 ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer()
这里我们调用 Netty 的 ByteBuf 分配器来创建,ioBuffer() 方法会返回适配 io 读写相关的内存,它会尽可能创建一个直接内存,直接内存可以理解为不受 jvm 堆管理的内存空间,写到 IO 缓冲区的效果更高
// 2. 序列化 Java 对象 byte[] bytes = Serializer.DEFAULT.serialize(packet);
// 3. 实际编码过程 byteBuf.writeInt(MAGIC_NUMBER); byteBuf.writeByte(packet.getVersion()); byteBuf.writeByte(Serializer.DEFAULT.getSerializerAlgorithm()); byteBuf.writeByte(packet.getCommand()); byteBuf.writeInt(bytes.length); byteBuf.writeBytes(bytes);
解码
二进制数据包中解析出 Java 对象的过程成为解码
public Packet decode(ByteBuf byteBuf) { // 跳过 magic number byteBuf.skipBytes(4); // 跳过版本号 byteBuf.skipBytes(1); // 序列化算法标识 byte serializeAlgorithm = byteBuf.readByte(); // 指令 byte command = byteBuf.readByte(); // 数据包长度 int length = byteBuf.readInt(); byte[] bytes = new byte[length]; byteBuf.readBytes(bytes); Class requestType = getRequestType(command); Serializer serializer = getSerializer(serializeAlgorithm); if (requestType != null && serializer != null) { return serializer.deserialize(requestType, bytes); } return null;}
7、MessagePack编解码
MessagePack介绍
MessagePack多语言支持
messagePack java API介绍
MessagePack开发包下载
MessagePack编码器和解码器开发
MessagePack编码器开发
MessagePack解码器开发
功能测试
粘包半包支持
8、google protobuf编解码
Protobuf的入门
protobuf开发环境搭建
protobuf编解码开发
运行protobuf例子
Netty的Protobuf服务端开发
protobuf版本的图书订购服务端开发
protobuf版本的图书订购客户端开发
protobuf版本的图书订购程序功能测试
Protobuf的使用注意事项
9、Jboss Marshalling编解码
Marshalling开发环境准备
Netty的Marshalling服务端开发
Netty的Marshalling客户端开发
运行Marshalling客户端和服务端历程
4、Netty多协议开发
10、http协议开发应用
Http协议的介绍
Http协议的url
Http协议的请求消息
Http协议的请求响应
Netty Http服务端入门
Http服务端例子场景描述
Http服务端开发
Netty Http文件服务器例子运行结果
Netty Http+xml协议栈开发
开发场景介绍
Http+xml协议栈设计
高效的XML绑定框架JiBx
Http+xml编解码框架开发
Http+xml协议栈测试
小结
11、websocket协议开发
Http协议的弊端
WebSocket入门
websocket背景
websocket连接建立
websocket生命周期
websocket连接关闭
Netty WebSocket协议开发
WebSocket服务端功能介绍
WebSocket服务端开发
运行WebSocket服务端
12、私有协议栈开发
私有协议介绍
Netty协议栈功能设计
网络拓扑图
协议栈功能描述
通信模型
消息定义
Netty协议支持的字段类型
Netty协议的编解码规范
链路的建立
链路的关闭
可靠性设计
安全性设计
可扩展性设计
Netty协议栈开发
数据结构定义
消息编解码
握手和安全认证
心跳检测机制
断连重连
客户端代码
服务端代码
运行协议栈
正常场景
异常场景:服务端宕机重启
异常场景:客户端宕机重启
13、服务端创建
原生NIO类库的复杂性
Netty服务端创建源码分析
Netty服务端创建时序图
Netty服务端创建源码分析
客户端接入源码分析
14、客户端创建
Netty客户端创建流程分析
Netty客户端创建时序图
Netty客户端创建流程分析
Netty客户端创建源码分析
客户端连接辅助类Bootstrap
客户端连接操作
异步链接结果通知
客户端连接超时机制
5、源码分析
15、ByteBuf和相关辅助类
ByteBuf功能说明
ByteBuf的工作原理
ByteBuf的功能介绍
Bytebuf
原生Bytebuffer缺点
长度固定,容量不能动态扩展收缩,出现数组越界
只有一个位置标识指针,读写转换时要手动调用flip()
api功能有限
Bytebuffer
flip()
flip操作后
flip操作前
典型用法
指针
写入
读取
discardRead
clear
内置方法
readSlice(int length)
返回当前ByteBuf新创建的子区域,与原Bytebuf共享缓冲区,但是独立维护自己的readIndex和writeIndex。新建的子区域readIndex为0,wirteIndex为length
wirteZero(int length)
将当前的缓冲区内容填充为NUL(0x00)起始位置为writeIndex,填充长度为length,填充后wirteIndex+=length
readerIndex和writeIndex
分支主题
discardable bytes
会造成内存复制,频繁调用会导致性能下降
Clear操作
不清空缓冲区本身,主要是将readIndex和writeIndex还原初始位置
Mard Reset
Derived buffer
duplicate
返回当前byteBuf的复制对象,共享一个缓冲区,但是独立维护读写索引
copy
复制一个新的byteBuf索引和内容都是新的
slice
返回当前byteBuf可读子区域,与原始缓冲区内容共享,读写下标独立维护
set/get随机读写
查找
indexOf
bytesBefore
forEachBytes
HeapByteBuf
基于堆内存分配回收速度快,缺点是需要额外一次内存copy
索引
readerIndex
writerIndex
复合缓冲区模式
本质上类似于提供一个或多个ByteBuf的组合视图,可以根据需要添加和删除不同类型的ByteBuf
派生缓冲区
已经存在的缓冲区的视图
修改了这个新的ByteBuf实例的具体内容,那么对应的源实例也会被修改,因为其内部存储是共享的
使用派生缓冲区,避免了复制内存的开销,有效提高程序的性能
直接缓冲区模式
于堆外分配的直接内存,不会占用堆的容量。适用于套接字传输过程,避免了数据从内部缓冲区拷贝到直接缓冲区的过程,性能较好
优点: 使用Socket传递数据时性能很好,避免了数据从Jvm堆内存拷贝到直接缓冲区的过程。提高了性能
缺点: 相对于堆缓冲区而言,Direct Buffer分配内存空间和释放更为昂贵
堆缓冲区模式
数据存放在JVM的堆空间,通过将数据存储在数组中实现
堆缓冲的优点: 由于数据存储在Jvm堆中可以快速创建和快速释放,并且提供了数组直接快速访问的方法
堆缓冲的缺点: 每次数据与I/O进行传输时,都需要将数据拷贝到直接缓冲区
引用计数
在池化的时候无法使用jvm回收内存,需要靠手动回收内存
DirectByteBuf
堆外内存分配,分配回收速度慢,0copy
池化/非池化
池化使用了对象池技术,减少gc,但是会带来额外维护开销
动态扩容
门限4MB,新申请的容量大于4m小于maxCap时以4m的大小增长,小于4m时则以64的倍数进行增长
对象池
PoolArena
由多个chunk组成
chunk
由多个page组成,以二叉树形式存储
page
辅助类
byteBufHolder
bytebuf容器
bytebufAllocator
CompositeBytebuf
将多个bytebuf组装到一起,形成统一视图
BytebufUtil
encodeString
decodeString
hexDump
ByteBuf源码分析
ByteBuf的主要类继承关系
AbstractByteBuf源码分析
AbstractReferenceCountedByteBuf源码分析
UnpooledHeapByteBuf源码分析
PooledButeBuf内存池原理分析
PooledDirectByteBuf源码分析
ByteBuf相关的辅助类功能介绍
ByteBufHolder
ByteBufAllocator
CompositeByteBuf
ByteBufUtil
16、channel和unsafe
Channel功能说明
Channel的工作原理
Channel的功能介绍
Channel源码分析
Channel的主要继承关系类图
AbstractChannel源码分析
AbstractNIOChannel源码分析
AbstractNioByteChannel源码分析
AbstractNioMessageChannel源码分析
AbstractNioMessageServerChannel源码分析
NioServerSocketChannel源码分析
NioSocketChannel源码分析
Unsafe功能说明
Unsafe源码分析
Unsafe继承关系类图
AbstractUnsafe源码分析
AbstractNioUnsafe源码分析
NioByteUnsafe源码分析
ServerChannel
传输类型
NioServerSocketChannel
非阻塞传输
EpollServerSocketChannel
非阻塞传输
OioServerSocketChannel
阻塞传输
Local
本地传输
Embedded
测试
method
config()
ChannelConfig
3.netty里面主要对象
1.ServerBootstrap
childHandler
2.EventLoop
对应selector
3.EventLoopGroup
一组EventLoop的抽象
4.SocketChannel
pipeline()
ChannelPipeline
eventLoop()
EventLoop
closeFuture()
ChannelFuture
bind()
connect()
read()
write()
写入ChannelPipeline缓存
flush()
SocketChannel
NioSocketChannel
17、channelPipeline和channelHandler
ChannelPipeline功能说明
ChannelPipeline的事件处理
自定义拦截器
构建Pipeline
ChannelPipeline的主要特性
ChannelPipeline源码分析
ChannelPipeline的类集成关系图
ChannelPipeline对ChannelHandler的管理
ChannelPipeline的inbound事件
ChannelPipeline的outbound事件
ChannelHandler功能说明
ChannelHandlerAdapter功能说明
ByteToMessageDecoder功能说明
MessageToMessageDecoder功能说明
LengthFieldBasedFrameDecoder功能说明
MessageToByteEncoder功能说明
MessageToMessageEncoder功能说明
LengthFieldPrepender功能说明
ChannelHandler源码分析
ChannelHandler的类集成关系图
ByteToMessageDecoder源码分析
MessageToMessageDecoder源码分析
LengthFieldBasedFrameDecoder源码分析
MessageToByteEncoder源码分析
MessageToMessageEncoder源码分析
LengthFieldPrepender源码分析
ChannelHandlerContext
pipeline()
ChannelPipeline
channel()
Channel
executor()
EventExecutor
close()
ChannelFuture
alloc()
ByteBufAllocator
ChannelHandler
interface: ChannelInboundHandler
abstract: ChannelInboundHandlerAdapter
method
channelActive()
channelRead()
channelReadComplete()
exceptionCaught()
abstractChannelInitializer
initChannel()
abstractSimpleChannelInboundHandler
channelRead0()
类型匹配则自动释放byteBuf引用
interface: ChannelOutboundHandler
abstract: ChannelOutboundHandlerAdapter
WriteTimeoutHandler
abstract: ChannelDuplexHandler
IdleStateHandler
ReadTimeoutHandler
annotation @Sharable
解码器
ByteToMessageDecoder
abstractMessageToMessageDecoder
事件
ChannelRegistered()
channel注册事件
channelActive
Tcp链路建立成功,channel激活
channelread
channelReadComplete
读完成
exceptionCauth
userEventTriggered
用户自定义
channelWriabilityChanged
写状态变化时
channelInactive
编码器
MessageToByteEncoder
abstractMessageToMessageEncoder
编解码器
abstract:MessageToMessageCodec
分类
数据粘包/拆包处理
加解密处理
业务流程处理
优点
分层处理,网络处理和业务处理分离
18、eventLoop和eventLoopGroup
Netty的线程模型
Reactor单线程模型
Reactor多线程模型
主从Reactor多线程模型
Netty的线程模型
最佳实践
EventLoop
控制流、多线程处理、并发
Reactor单线程
分支主题
nio线程职责
接收客户端连接
向服务端发起连接
读取请求或者应答
发消息或者应答
Reactor多线程
分支主题
特点
专门的nio线程接收客户端请求(单线程)
读写也有专门的线程池负责
一个NIO线程同时处理n条链路,一个链路对应一个nio线程
最佳实践
不要在channelHandler中启动用户线程
解码要放在NIO线程调用解码Handler中进行,不要切换到用户线程完成
如果业务操作简单,可以直接在NIO线程上完成逻辑
如果业务复杂耗时,可封装成task发到业务线程池中完成
主从Reactor多线程
分支主题
与多线程reactor相比,使用线程池接收客户端请求
EventLoopGroup
NioEventLoopGroup
EpollEventLoopGroup
OioEventLoopGroup
NioEventLoop源码分析
NioEventLoop设计原理
NioEventLoop继承关系类图
NioEventLoop
19、future和promise
Future功能
ChannelFuture
异步通知
sync()
channel()
ChannelFutureListener
operationComplete
Promise功能介绍
Promise源码分析
Promise继承关系类图
DefaultPromise
0 条评论
下一页