概述
1.Netty的高性能体现在哪些方面?
(1)异步非阻塞通信。使用异步非阻塞通信方式,利用I/O多路复用技术,只需少量的线程就能管理大量的网络连接的读写操作。
(2)采用高效的Reactor线程模型。
支持三种Reactor线程模型:Reactor单线程模型、Reactor多线程模型、主从Reactor多线程模型。
(3)串行无锁化设计。NioEventLoop线程池采用串行无锁化执行方式,避免多线程竞争(锁同步)引起的性能下降,比一个队列+线程池模型的性能更好。
(4)高效的并发编程。大量使用volatile;广泛使用CAS和原子类;使用线程安全的容器;通过读写锁提升并发性能。
(5)高性能的序列化框架。默认支持Google Protobuf,也可以扩展Netty编解码接口实现自己的高性能序列化方式。
(6)零拷贝。Netty有三种情况使用了零拷贝技术。
第一种情况:Netty的接受和发送ByteBuf可以采用Direct Buffer,使用堆外内存进行I/O读写,不需要进行字节缓存区的二次拷贝。注意:Netty也支持堆内存方式。
第二种情况:CompositeByteBuf类可以将多个ByteBuf合并成一个逻辑上的ByteBuf,避免ByteBuf之间的相互拷贝。
第三种情况:文件传输使用零拷贝。Netty的文件传输类DefaultFileRegion的transferTo方法直接将文件缓存区的数据发送到目标Channel,避免通过传统的循环write方式导致的内存拷贝问题。
(7)内存池。接受、发送缓冲区在使用堆外内存时,利用内存池最大程度地重用缓存区,极大得降低堆外内存分配和释放的消耗时间。
(8)灵活的TCP参数配置能力。常用的TCP配置参数有:
SO_BACKLOG 对应listen函数的backlog参数,表示入队的未完成、已完成三次握手的连接请求数的最大值,UNIX网络编程_卷一一书有权威的讲解。
SO_REUSEADDR 重用TIME_WAIT套接字。
TCP_NODELAY TCP Nagle算法,减少小包的发送,为了降低延迟通常会关闭。
SO_KEEPALIVE TCP协议自身的心跳,在业务层通常也会实现心跳。
SO_RCVBUF 接受缓存区的大小。
SO_SNDBUF 发送缓存区的大小。
2.Netty的执行流程是怎样的?
(1)创建ServerBootstrap实例。
(2)创建parentGroup和childGroup,都是EventLoopGroup对象,内部会创建Reactor线程模型中的处理线程池。
EventLoopGroup接口的实现有:NioEventLoopGroup,EpollEventLoopGroup,KQueueEventLoopGroup。
(3)调用ServerBootstrap的group方法绑定parentGroup和childGroup。
(4)调用ServerBootstrap的channel方法,指定ServerChannel接口的实现类,accept新连接时使用该实现类创建ServerChannel对象。
(5)调用ServerBootstrap的option、childOption方法,设置TCP配置参数。
(6)调用ServerBootstrap的childHandler方法,设置channel初始化器,为ChannelInitializer抽象类的子类。
accept新连接时,创建好ServerChannel对象后,通过channel初始化器往channel的pipeline中添加ChannelHandler,例如编解码处理器、连接心跳管理处理器、ssl处理器、业务计算处理器等等。当channel上发生网络I/O事件时,通过pipeline中的ChannelHandler链进行处理。
(7)调用ServerBootstrap的bind方法,绑定、并监听端口。
(8)当监听channel上出现可读(OP_READ)或者可接受(OP_ACCEPT)事件时,netty底层会调用accept方法接受这个新连接,创建一个新的channel,同时调用channel初始化器initChannel方法,构建完整的channel处理器链。创建好channel之后,把这个channel注册到网络I/O事件监听列表中。
(9)当普通channel上出现可读(OP_READ)事件时,netty底层先调用read方法将数据读入字节数组中(默认采用堆外内存零拷贝方式读取数据),然后使用channel的pipline处理器链依次进行处理:对接受的数据反序列化,ssl认证,业务处理,对响应数据序列化,发送响应等等。
(10)心跳检测,当channel上超过指定时间没有发生网络I/O时间,心跳处理ChannelHandler就会发出IdleStateEvent事件,通常在业务处理ChannelHandler的userEventTriggered方法中进行处理,关闭channel,清理相关联的业务数据,或者输出日志信息。
3.Netty支持哪些心跳类型?
支持三种心跳类型:ReaderIdle,WriterIdle,AllIdle,分别是读心跳检测,写心跳检测和全部心跳检测。
读心跳检测:检测超时时间内是否有接受到对端的数据包,如果没有发出ReaderIdleStateEvent事件。
写心跳检测:检测超时时间内是有有向对端发出数据包,如果没有发出WriterIdleStateEvent事件。
全部心跳检测:检测超时时间内是否有接受到对端的数据包,或者是否有向对端发出数据包,如果都没有发出AllIdleState事件。
4.Netty的心跳机制是如何实现的?
TCP保持长连接的过程中,可能出现断网、某一端掉电(没有执行关闭socket)等网络异常,异常发生时,如果client和server之间没有网络交互,两方不能及时发现连接已经断开。对于服务端而言,无效的连接会一直占用系统资源,应该及时发现后关闭socket,释放掉占用的资源。通过心跳机制来解决这个问题。
TCP自带有心跳机制,提供了SO_KEEPALIVE长连接心跳保活选型。TCP自带的心跳机制不够灵活,一般在应用层会实现自定义的心跳机制。
Netty通过channel的IdleStateHandler和定时任务实现心跳检测。当新连接的channel创建时,调用channel初始化器的InitChannel方法把IdleStateHandler加入channel的处理器链pipline中,然后调用ChannelHandler的channelActive、channelRegistered方法启动心跳检测定时任务。当channel上发生读写操作时,调整心跳检测的状态和读写事件发生的时刻。心跳检测定时任务执行时检测上一次读/写发生后经过的时间长度有没有过期,如果没有过期用新的时间间隔启动下一个心跳检测定时任务;如果过期先用新的时间间隔启动下一个心跳检测定时任务,然后发出IdleStateEvent事件。当channel对应的连接断开时,ChannelHandler的channelInActive、channelRemove方法会被调用,此时取消开启的心跳检测任务。
5.Netty发送消息有几种方式?
(1)调用Channel的发送方法。
(2)调用与ChannelHandler绑定的ChannelHandlerContext的发送方法。
6.Netty中有哪些重要组件?
(1)Channel:是Netty的网络抽象类,封装了socket,包含所有的网络I/O操作方法,例如connect,bind,read,write等。
(2)EventLoop:用于处理channel上发生的网络I/O事件,内部会创建线程池,把channel的网络I/O事件封装成任务放入线程池进行处理。
(3)ChannelFuture:Netty中的I/O操作都是异步处理的,在发起I/O操作时,通过ChannelFuture的addListener方法注册相应的ChannelFutureListener监听器,当I/O操作完成时回调监听器的方法,告知发起方I/O操作的最终结果是失败、还是成功,发起方进而执行后续的操作。
(4)ChannelHandler:channel上网络I/O事件的处理器,不同的I/O事件有不同的处理方法,连接成功调用channelActive,连接断开调用channelInActive,接受到消息调用channelRead等等。ChannelHandler会组装成处理器链,每个ChannelHandler只执行一个操作,这种利用单一责任原则设计模式可以让代码可读性、可维护性更好。
(5)ChannelPipeline:为ChannelHandler处理器链提供容器,channel在创建时,会为channel创建只属于它的pipeline,将channel的完整的ChannelHandler处理器链保持在pipeline中。每个channel都有一个pipeline容器,pipeline中的ChannelHandler都是新new出来的,不同的channel之间并不共享ChannelHandler对象,这样设计可以保证ChannelHandler是线程安全的。
7.Netty是什么?
Netty是一个基于NIO的客户端-服务端网络通信框架,使用它可以快速地开发网络应用程序。
Netty极大地简化、优化了TCP、UDP套接字网络服务的网络编程,同时性能和安全性上都表现良好。
Netty支持多种协议,例如FTP,SMTP,HTTP以及各种二进制和基于文本的协议。
8.Netty有哪些应用场景?
(1)用于RPC框架的网络层,例如Dubbo、Motan。
(2)实现HTTP服务。
(3)开发CS架构的应用程序,例如即时聊天系统、Zookeeper。
9.为什么要用Netty?
(1)提供统一的API,支持多种传输方式:阻塞和非阻塞。
(2)线程模型简单、高效,开销低,性能非常好。
(3)自带编解码器,可以很好的解决TCP粘包/拆包问题。
(4)自带非常多的协议栈实现。
(5)容易使用,大大地降低了网络编程的难度。比直接使用Java的socket api开发高性能的网络服务的难度低得多。
(6)安全性很好,SSL/TLS以及StartTLS有完整的支持。
(7)社区活跃,成熟稳定。经过众多大项目的使用和考验,例如Dubbo,zookeeper,RocketMQ等。
10.粘包拆包发生的原因是什么?怎么解决粘包拆包?
TCP提供面向“数据流”的可靠传输服务,会出现粘包拆包问题。
UDP提供面向“数据报”的不可靠传输服务,数据包之间没有联系,并且有明确的边界,不存在粘包拆包问题。
粘包出现的主要原因:发送方写入数据小于套接字缓冲区大小,多个数据包合在一个缓冲区发送;接受方读取套接字缓冲区数据不及时,多个数据包堆积在缓冲区中。
拆包出现的主要原因:发送方写入数据大于套接字缓冲区大小,发送方发送的数据大于MTU(最大传输单元),数据包必须拆包。
粘包拆包的解决方法:指导思想是给数据包添加明确的边界。
(1)设置固定长度的数据包,长度不足时用特殊字符补齐。
(2)消息之间用特殊字符分隔,遇到分隔符时将数据包拆开。
(3)使用固定长度包头+包体的发送消息,包头里边放上包头长度的字段。
发送方按照包头、包体、包头、包体...这种固定顺序发送消息。
接收方按照包头、包体、包头、包体...这种固定顺序接受消息。
11.Netty时间轮
Netty采用的是Hashed时间轮(unsorted),实现类为HashedWheelTimer。数据结构如下图。
由数组和双向链表组成,和HashMap的结构类似。
tickDuration字段用于表示每个tick的时间间隔,即图中圆盘的刻度。值越小精度越高,单位时间内触发次数越多,性能会有一定的下降。
ticksPerWheel代表数组的长度,即图中圆盘的长度。值越大散列程度越好,查找效率越高,但是内存开销大一些;值越小,内存开销小,冲突较多,查找效率低。
图中方框节点中的数字表示剩余圈数,即HashedWheelTimeout的remainingRouds表示的含义。
调用newTimeout方法提交任务,先写入暂存队列,在worker线程执行tick操作时真正写入时间轮。
调用cancel方法取消任务,也是先写入暂存队列,在worker线程执行tick操作时真正从时间轮中删除。
worker线程用于触发tick操作:
(1)处理待取消任务。
(2)处理待提交任务。
(3)处理超时逻辑。遍历当前刻度对应的双向链表,如果剩余圈数为0,执行定时任务的回调方法,然后从时间轮中移除。
12.Netty时间轮使用的注意事项有哪些?
(1)适用于时间精度要求不高,定时任务请求量较大的场景,例如服务端连接心跳检测。
(2)Netty时间轮中任务调度和执行是单线程,处理任务不要包含耗时的操作,否则会阻塞其他定时任务的执行。
Timer的实现方式还有:
Java的Timer、ScheduledThreadPoolExecutor 试用于时间精度高,定时任务请求小的场景。
Java的DelayQueue。
Kafa实现的带等级时间轮。
(3)不要大量创建时间轮对象,每个时间轮都会创建一个worker线程。
(4)Netty时间轮时间复杂度为:
newTimeout即startTimer O(1)
cancel即stopTimer O(1)
perTickBookKeeping O(n/m),n为任务个数,m为ticksPerWheel数组长度。
参考资料:
[1]Reactor模型参考资料:【NIO系列】——之Reactor模型 - wier的个人空间 - OSCHINA - 中文开源技术交流社区
[2]Netty权威指南第2版
[3]1000道Java程序员必备面试题
[4]Netty ChannelOption.SO_BACKLOG配置:Netty ChannelOption.SO_BACKLOG配置_架构师的小跟班的博客-CSDN博客_channeloption.so_backlog
[5]UNIX环境高级编程
[6]Linux体系下的accept队列和SYN队列:Linux体系下的accept队列和SYN队列 - 知乎
[7]UNIX网络编程_卷一
[8]Netty时间轮调度算法原理分析,再不了解你就out啦:Netty时间轮调度算法原理分析,再不了解你就out啦,java高级特性编程及实战第三章_m0_63176399的博客-CSDN博客
[9]Netty 时间轮源码解析:Netty 时间轮源码解析
最后
以上就是健康白云为你收集整理的Netty学习笔记的全部内容,希望文章能够帮你解决Netty学习笔记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复