JavaSocket编程之Netty框架线程模型
1.Netty概述
Netty是一个由JBoss提供的高效的Java NIO client-server(客户端-服务器)开发框架,使用Netty可以快速开发网络应用。Netty提供了一种新的方式来使开发网络应用程序,使其很容易使用且有很强的可扩展性。Netty的内部实现是很复杂的,但是Netty提供了简单易用的API从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,采用事件驱动机制,非阻塞执行,所以整个Netty都是异步的。Netty框架体系结构图如下:
文章图片
Netty框架体系结构图 2.Java NIO缓冲区与通道
一个Buffer对象是固定数量的数据的容器,其作用是一个存储器。通道Channel是I/O传输发生时通过的入口,而缓冲区是这些数据传输的来源或目标。对于离开缓冲区的传输,您想传递出去的数据被置于一个缓冲区,被传送到通道。缓冲区是包在一个对象内的基本数据元素数组。Buffer类相比一个简单数组的优点是它将关于数据的数据内容和信息包含在一个单一的对象中。缓冲区家族成员如下所示:
文章图片
缓冲区Buffer具有四个属性来提供关于其所包含的数据元素的信息。
它们是:
容量(Capacity):缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,且不能被改变。
上界(Limit):缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数。
位置(Position):下一个要被读或写的元素的索引。位置会自动由相应的get( )和put( )函数更新。
标记(Mark):一个备忘位置。调用mark( )来设定mark = postion。调用reset( )设定position = mark。标记在设定前是未定义的(undefined)。
这四个属性之间总是遵循以下关系
0 <= mark <= position <= limit <= capacity
文章图片
3.Netty核心网络模型
Netty是典型的Reactor模型结构,在实现上,Netty中的Boss类充当mainReactor,NioWorker类充当subReactor(默认NioWorker的个数是当前服务器的可用核数)。在处理新来的请求时,NioWorker读完已收到的数据到ChannelBuffer中,之后触发ChannelPipeline中的ChannelHandler流。Netty是事件驱动,非阻塞的,可以通过ChannelHandler链来控制执行流向。
3.1 Refactor单线程模型
Reactor单线程模型,指的是所有的IO操作都在同一个NIO线程上面完成;
Reactor单线程模型特点:
1)Java NIO服务端,接收客户端的TCP连接;
2)Java NIO客户端,向服务端发起TCP连接;
3)Java NIO服务端/客户端,读取通信对端的请求或者应答消息;
4)Java NIO服务端/客户端,向通信对端发送消息请求或者应答消息
使用场景:对于一些小容量应用场景,可以使用单线程模型。但是对于高负载、大并发的应用场景却不合适,比如一个NIO线程同时处理成百上千的链路,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送。Reactor单线程模型如下图所示:
文章图片
3.2 Refactor多线程模型
Rector多线程模型与单线程模型最大的区别就是有一组NIO线程处理IO操作。
Reactor多线程模型的特点:
1)有一个专门的NIO线程-Acceptor线程用于监听服务端,接收客户端的TCP连接请求;
2)网络IO操作-读、写等由一个NIO线程池负责,线程池可以采用标准的JDK线程池实现,它包含一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送;
3)1个NIO线程可以同时处理N条链路,但是1个链路只对应1个NIO线程,防止发生并发操作问题。
Reactor多线程模型如下图所示:
文章图片
3.3 Netty服务器端创建过程
Netty服务器启动时,创建两个NIOEventLoopGroup独立的Reator线程池,一个用于接收客户端的TCP连接,一个用于处理IO的相关的读写操作。
Netty线程模型是建立在Reactor模型的基础上,线程模型并不是一成不变的,通过启动参数的配置,可以在不同的线程模型之间切换。Netty服务器端创建过程序列图如下:
文章图片
Netty服务器端创建过程序列图
1)首先创建一个ServerBootstrap实例,这是Netty服务端的启动辅助类;
2)设置并绑定Reactor线程池,Netty的Reactor线程池是EventLoopGroup,它其实就是EventLoop线程的数组。EventLoop的职责是处理所有注册到本线程多路复用器Selector上的Channel;
3)设置并绑定服务端NIOserverSocketChannel, Netty通过工厂类,利用反射方式创建NioServerSocketChannel对象
4)设置TCP连接参数,TCP链路建立时创建并初始化ChannelPipeline,它本质是一个负责处理网络事件的职责链,负责管理和执行ChannelHandler。网络事件以事件流的形式在ChannelPipeline中流转,由ChannelPipeline根据ChannelHandler的执行策略调度ChannelHandler的执行;
5)添加并设置ChannelHandler,加入到ChannelPipeline事件流;
6)服务器端绑定监听端口,并启动服务器;
7)启动NioEventLoop负责调度和执行Selector轮询操作,选择准备就绪的Channel集合;
8)当轮询到准备就绪的Channel之后,就由Reactor线程NioEventLoop执行ChannelPipeline的相应方法;
9)执行Netty系统并调度执行ChannelHandler业务逻辑
3.4 Netty线程模型实例
注册两个OutboundHandler,执行顺序为注册顺序的逆序,注册两个InboundHandler,执行顺序为注册顺序,注册HelloServerInHandler用于接收客户端消息已经向客户端发送消息,主要代码如下:
文章图片
文章图片
本订阅号提供Java相关技术分享,从Java编程基础到Java高级技术,从JavaWeb技术基础Jsp、Servlet、>JDBC到SSH、SSM开发框架,从REST风格接口设计到分布式项目实战。剖析主流开源技术框架,用亲身
实践来谱写深度Java技术日志。
文章图片
Java技术日志
【JavaSocket编程之Netty框架线程模型】欢迎关注 Java技术日志 微信订阅号
推荐阅读
- PMSJ寻平面设计师之现代(Hyundai)
- 太平之莲
- 闲杂“细雨”
- 七年之痒之后
- 深入理解Go之generate
- 由浅入深理解AOP
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 生活随笔|好天气下的意外之喜
- 感恩之旅第75天
- python学习之|python学习之 实现QQ自动发送消息