1.netty的高性能表现在哪些方面?对平常的项目开发的启发?
Reactor线程模型
2.netty中有哪些重要的组件,他们之间的联系?
3.netty的内存池,对象池是怎么设计的?
4.针对netty你有哪些印象深刻的系统调优案例?
netty对Java NIO进行了高级封装(拆包、粘包,数据编解码,TCP断线重连),简化了网络应用的开发过程
为什么要学习netty:
1.I/O模型,线程模型,事件处理机制
2.易用的API接口
3.数据协议,序列化的支持
I/O请求的两阶段:
1.I/O调用阶段:用户进程向内核发起系统调用
2.I/O执行阶段:内核等待I/O请求处理完成返回
2.1:I/O设备获取数据到内核缓冲区
2.2:数据从内核缓冲区拷贝到用户态缓冲区
Linux的5种主要I/O模型:
1.同步阻塞I/O(BIO)
2.同步非阻塞I/O(NIO)
3.I/O多路复用
一个线程实现处理多个I/O句柄的操作
select poll epoll 都是I/O多路复用的具体实现
4.信号驱动I/O(半异步的I/O模型,内核通知何时可以开始I/O操作)
5.异步I/O
从内核缓冲拷贝到用户态缓冲区也是由系统异步完成,由内核通知何时I/O操作已经完成
netty基于非阻塞I/O实现自己的I/O模型
底层依赖的是JDK NIO框架的多路复用器Selector
一个Selector可以同时轮训多个Channel
当有数据处于就绪状态,需要一个事件分发器(Event Dispather)将事件分发给对应的读写事件处理器(Event Handler)
事件分发器有两种设计模式:
Reactor(采用同步IO)和Proactor(采用异步IO)
主流事件驱动模型还是依照select或epoll
Netty的整体架构脉络
逻辑架构:
1.网络通信层
职责是进行网络I/O操作,支持多种网络协议和I/O模型的连接操作
BootStrap --主要负责整个Netty程序的启动,创建,初始化Channel等,远端服务器连接,只绑定一个EventLoopGroup(Boss)
ServerBootStrap --服务器端启动,绑定本地端口,绑定两个EventLoopGroup(Worker)
Channel --是网络通信的载体,提供了与底层Socket交互的能力,提供了基本的API用于网络I/O操作,register,bind,connect,read,write,flush等
2.事件调度层
职责是通过Reactor线程模型对各类事件进行聚合处理
通过Selector主循环线程集成多种事件(I/O事件,信号事件,定时事件)
EventLoopGroup--本质是个线程池并分配线程执行处理请求,是Netty Reactor线程模型的具体实现方式
EventLoop--负责向注册的Channel发起I/O读写操作,处理网络连接生命周期的所有I/O事件(accept,connect,read,write)
每个EventLoop是单线程的,通过selector进行事件循环
EventLoopGroup 根据不同的参数配置,实现Reactor的3种线程模型:
3.服务编排层
职责是组装各类服务,用以实现网络事件的动态编排和有序传播
ChannelPipeline--组装编排各种ChannelHandler
ChannelHandler--实际数据的编解码以及加工处理操作
ChannelHandlerContext
每一个新的Channel会对应绑定一个新的ChannelPipeline
一个ChannelPipeline关联一个EventLoop
一个EventLoop仅会绑定一个线程
网络通信层--BootStrap
服务端启动过程:
1.配置线程池:
单线程模式:
EventLoopGroup group = new NioEventLoopGroup(1);
ServerBootstrap b = new ServerBootstrap();
b.group(group)
多线程模式:
EventLoopGroup group = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(group)
主从多线程模式:
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
2.Channel初始化
2.1.设置 Channel 类型
b.channel(NioServerSocketChannel.class);
2.2.注册 ChannelHandler
b.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast("codec", new HttpServerCodec())
.addLast("compressor", new HttpContentCompressor())
.addLast("aggregator", new HttpObjectAggregator(65536))
.addLast("handler", new HttpServerHandler());
}
})
2.3.设置 Channel 参数
b.option(ChannelOption.SO_KEEPALIVE, true);
3.端口绑定
ChannelFuture f = b.bind().sync();
事件调度层--EventLoop
EventLoop是Netty Reactor线程模型的核心处理引擎,是一种事件等待和处理的程序模型,可以解决多线程资源消耗高的问题
每个EventLoop线程都维护一个Selector选择器和任务队列taskQueue
主要负责处理I/O事件,普通任务,定时任务
主流网络框架都采用I/O多路复用的方案, Reactor模式作为其中的读写事件分发器,负责将读写事件分发给对应的读写事件处理者
EventLoop运行模式:
源码:
1.select(wakeUp.getAndSet(false)); //轮训I/O事件
2.processSelectedKeys(); //处理I/O事件
3.runAllTasks(); //处理任务
|-1.合并定时任务到普通任务队列
fetchFromScheduledTaskQueue();
|-2.从普通任务队列中取出任务
pollTask();
|-3.计算任务处理的超时时间
dealline = ScheduledFutureTask.nanoTime()+timeoutNanos;
|-4.安全执行任务
safeExecute(task);
|-5.每执行64个任务检查下是否超时,
|-6.收尾工作
afterRunningTasks();
NioEventLoop 无锁串行化设计:
优点:
使系统吞吐量达到最大化
降低了用户开发业务逻辑的难度
缺点:
不能执行时间过长的I/O操作,一旦一个I/O事件发生阻塞,后续所有I/O事件都无法执行
JDK中epoll的实现是存在漏洞的
即使selector轮训的事件列表为空,NIO线程一样会被唤醒,导致CPU100%占用。
Netty 的事件轮训中,
1.每次selector之前记录currentTimeNanos,
2.如果事件轮训时间>=timeoutMills则正常的
3.通过selector_auto_rebuild_threshold阈值,通过selectCnt>该值时触发重建selector对象 并break
处理任务:
总结:
MainReactor线程:处理客户端请求接入
SubReactor线程:数据读取,I/O事件的分发与执行
任务处理线程:执行普通任务或者定时任务,如空闲连接检测,心跳上报
服务编排层--ChannelPipline与ChannelHandler
channelpipline负责调度各种类型的ChannelHandler,实际数据的加工处理由ChannelHandler完成
ChannelPipline是双向链表结构
ChannelInboundHandler和ChannelOutboundHandler
每个channelHandler由一个ChannelHandlerContext封装
Inbound和Outbound传播方向相反
(head-tail) (tail-head)