| |
|
开发:
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地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
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年11日历 | -2024/11/26 8:47:30- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |