Hello,今天给各位童鞋们分享Netty,赶紧拿出小本子记下来吧!
一、Netty简介
Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。
二、为什么使用Netty
2.1、手写Java NIO的缺点
因为自己写Java NIO很麻烦:
1)NIO类库和API复杂,要熟练掌握Selector, ServerSocketChannel, SocketChannel, ByteBuffer等
2)要熟悉Java多线程编程,且涉及到Reactor模式,这样才能写出高质量的NIO程序
3)臭名昭著的epoll bug,它会导致selector空轮询,最终导致CPU 100%。
2.2、Netty的优点
1)API使用简单,学习成本低
2)很多功能封装好了,如编解码、支持多种协议如PB
3)性能高:相比其他NIO框架,netty性能最优
4)社区活跃
5)Dubbo, ES,RocketMQ, GRPC等都采用了Netty,质量得到验证。
三、Netty架构图
上图为netty官网首页的架构图:
1)绿色部分是Core核心模块,包括零拷贝、API库、可扩展事件模型等
2)橙色部分:协议支持,包括http协议、webSocket、SSL、Protocol buffer, zlib/gzip压缩与解压缩,Large File Transfer大文件传输等。
3)红色部分为传输服务,包括Socket, Datagram, Http Tunnel等
从上图可以看出netty都有什么功能了:它的功能、协议、传输方式支持的都比较全。
四、Netty的使用
4.1、引入maven依赖
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.20.Final</version>
4.2、创建服务端启动类
4.3、创建服务端业务处理器Handler
4.4、创建客户端启动类
4.5、创建客户端业务处理器Handler
五、Netty的特性与重要组件
5.1、taskQueue任务队列
如果Handler处理器有一些长时间的业务处理,可以交给taskQueue异步处理,按下面的方式来通过taskQueue做业务处理:
总结:这就解释了上一篇reactor中的问题,在handler监听到workGroup中的事件后,实际上也放到了taskQueue线程池中做了异步处理。
5.2、scheduleTaskQueue延时任务队列
延迟任务队列,除了handler处理异步外,只是多了等一段时间在执行:
ctx.channel().eventLoop().schedule(new Runnable() {
@Override
public void run() {
try {
//长时间操作,不至于长时间的业务操作导致Handler阻塞
Thread.sleep(1000);
System.out.println("长时间的业务处理");
} catch (Exception e) {
e.printStackTrace();
}
}
},5, TimeUnit.SECONDS);//5秒后执行
5.3、Future异步机制
在客户端启动时,有这样一行代码:
//连接服务端
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6666).sync();
ChannelFuture提供了操作完成后,一种异步通知方式。在Socket编程中,响应结果都是阻塞的,而ChannelFuture则采用观察者模式异步返回结果:
5.4、Bootstrap与ServerBootStrap
Bootstrap和ServerBootStrep是netty提供的创建客户端和服务端启动的工厂类,使用这个工厂类非常便利地创建启动类:
通过Bootstrap创建启动器的步骤为
5.4.1、group()
在Reactor模式文章中,我们知道服务端要用到两个线程组:
1)bossGroup:用于监听客户端连接,专门负责与客户端创建连接,并把连接注册到WorkGroup的Selector中
2)workGroup:用于处理每一个连接发生的读写事件
一般创建线程直接使用以下new就可以了:
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
那么,既然是线程组,线程数默认多少呢?看源码:
从源码可以看到,默认线程数是CPU核数的2倍。如果想自定义线程数,可以使用有参构造器:
//设置bossGroup线程数为1
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
//设置workerGroup线程数为16
EventLoopGroup workerGroup = new NioEventLoopGroup(16);v
5.4.2、channel()
channel() 方法用于设置通道类型,当建立连接后,会根据这个设置创建对应的Channel实例:
通道的类型有以下几种:
1)NioSocketChannel:异步非阻塞的客户端TCP Socket连接
2)NioServerSocketChannel:异步非阻塞的服务端TCP Socket连接
备注:常用的就是这两种通道类型,因为他们异步非阻塞
3)OioSocketChannel:同步阻塞的客户端TCP Socket连接
4)OioServerSocketChannel:同步阻塞的服务端TCP Socket连接
5.4.3、option() 与 childOption()
1、option() : 设置服务端用于接收进来的连接,也就是bossGroup线程
2、childOption():是提供给父管道接收到的连接,也就是bossWork线程
SocketChannel参数,也就是childOption() 常用的参数:
SO_RCVBUF Socket参数,TCP数据接收缓冲区大小。
TCP_NODELAY TCP参数,立即发送数据,默认值为Ture。
SO_KEEPALIVE Socket参数,连接保活,默认值为False。启用该功能时,TCP会主动探测空闲连接的有效性。
ServerSocketChannel参数,也就是option()参数:即boss线程池的队列长度
SO_BACKLOG Socket参数,服务端接受连接的队列长度,如果队列已满,客户端连接将被拒绝。默认值,Windows为200,其他为128。
5.4.4、设置流水线(重点)
ChannelPipeline是Netty处理请求的责任链,ChannelHander则是具体处理请求的处理器。实际上每一个channel都有一个处理器的流水线。
好啦,今天的文章就到这里,希望能帮助到屏幕前迷茫的你们