IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Netty学习笔记 -> 正文阅读

[网络协议]Netty学习笔记

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 时间轮源码解析

?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 01:33:50  更:2022-02-19 01:35:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年10日历 -2024/10/5 11:14:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码