什么是Netty

介绍

        第一:Netty 是一个 基于 NIO 模型的高性能网络通信框架,其实可以认为它是 对 NIO 网络模型的封装,提供了简单易用的 API,我们可以利用这些封装好的 API 快速开发自己的网络程序。

        第二:Netty 在 NIO 的基础上做了很多优化,比如零拷贝机制、高性能无锁队列、 内存池等,因此性能会比 NIO 更高。

        第三:Netty 可以支持多种通信协议,如 Http、WebSocket 等,并且针对数据通信的拆包黏包问题,Netty 内置了拆包策略。


为什么要用 Netty?

      Nety 相比于直接使用 JDK 自带的 NIO 相关的 API 来说更加易用。同时,它还具有以下特点:

1. 统一的 API,支持多种传输类型,如阻塞、非阻塞,以及 epoll、poll 等模型。

2. 我们可以使用非常少的代码来实现,多线程 Reactor 模型以及主从多线程 Reactor 模型

3. 自带编解码器解决 TCP 粘包/拆包问题。

4. 自带各种协议栈。

5. 比直接使用 Java 库中的 NIO API 有更高的吞吐量、更低的延迟、更低的资源消耗和更少      的内存复制。

6. 安全性不错,有完整的 SSL/TLS 以及 StartTLS 支持。

7. 社区活跃成熟稳定,经历了大型项目的使用和考验,而且很多开源项目都使用到了     Netty, 比如我们经常接触的Dubbo、RocketMQ 等等


Netty 可以做什么事情? 

        我们之所以要用 Netty,核心点还是在于解决服务器如何承载更多的用户同时访问的问 题。 传统的 BIO 模型,由于阻塞的特性,使得在高并发场景中,很难获得更高的吞吐量。         而后来基于 NIO 的多路复用模型虽然在阻塞方面进行了优化,但是它的 API 使用比较 复杂,对于初学者来说使用不是很友好。

        而 Netty 是基于 NIO 的封装,提供了成熟且 简单易用的 API,降低了使用成本和学习成本。 本质上来说,Netty 和 NIO 所扮演的角色是相同的,都是为了提升服务端的吞吐量, 让用户获得更好的产品体验。 另外,Netty 这个中间件经过很多年的验证,在目前主流的中间件如 Zookeeper、 Dubbo、RocketMQ 中都有应用。


Netty 核心组件了解吗?分别有什么作用?

        Netty 由三层结构构成:网络通信层、事件调度器与服务编排层

        在网络通信层有三个核心组件:Bootstrap、ServerBootStrap、Channel

                1、Bootstrap 负责客户端启动并用来链接远程 netty server

                2、ServerBootStrap 负责服务端监听,用来监听指定端口,

                3、Channel 是负责网络通信的载体

        事件调度器有两个核心组件:EventLoopGroup 与 EventLoop

                1、 EventLoopGroup 本质上是一个线程池,主要负责接收 I/O 请求,并分配线程执行                           处理请求。

                2、 EventLoop。相当于线程池中的线程

        在服务编排层有三个核心组件:ChannelPipeline、ChannelHandler、ChannelHandlerContext                  1、ChannelPipeline 负责将多个 Channelhandler链接在一起

                2、ChannelHandler 针对 IO 数据的处理器,数据接收后,通过指定的 Handler 进行处理。

                3、ChannelHandlerContext 用来保存 ChannelHandler


Netty 有几种线程模型? 

Netty 提供了三种 Reactor 模型的支持:

        1、单线程单 Reactor 模型

        2、多线程单 Reactor 模型

        3、多线程多 Reactor 模型


 对于这三种线程 Reactor 模型的理解

Reactor 模型有三个重要的组件:

        1. Reactor :将 I/O 事件发派给对应的 Handler

        2. Acceptor :处理客户端连接请求

        3. Handlers :执行非阻塞读/写

这是最基本的单 Reactor 单线程模

        其中 Reactor 线程,负责多路分离套接字,有新连接到来触发 connect 事件之后,交由 Acceptor 进行处理,有 IO读写事件之后交给hanlder处理。

        Acceptor 主要任务就是构建 handler ,在获取到和 client 相关的 SocketChannel 之 后 ,绑定到相应的 hanlder 上,对应的 SocketChannel 有读写事件之后,基于 racotor 分发,hanlder 就可以处理了(所有的 IO 事件都绑定到 selector 上,有 Reactor 分发

多线程单 Reactor模型

        单线程 Reactor 这种实现方式有存在着缺点,从实例代码中可以看出,handler 的执行是串行的,如果其中一个 handler 处理线程阻塞将导致其他的业务处理阻塞。由于 handler 和 reactor 在同一个线程中的执行,这也将导致无法接收新的请求。 为了解决这种问题,有人提出使用多线程的方式来处理业务,也就是在业务处理的地方加入线程池异步处理,将 reactor 和 handler 在不同的线程来执行,这就是多线程单 Reactor模型


多线程多 Reactor

        在多线程单 Reactor 模型中,所有的 I/O 操作是由一个 Reactor 来完成,而 Reactor 运行在单个线程中,它需要处理包括 Accept()/read()/write/connect 操作,对于小 量的场景,影响不大。但是对于高负载、大并发或大数据量的应用场景时,容易成为瓶 颈,主要原因如下:

        1、一个 NIO 线程同时处理成百上千的链路,性能上无法支撑,即便 NIO 线程的 CPU 负荷达到 100%,也无法满足海量消息的读取和发送;

        2、当 NIO 线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了 NIO 线程的负载,最终会导致大量消息积压和处理超时,成为系统的性能瓶颈;

        所以,我们还可以更进一步优化,引入多 Reactor 多线程模式,

        1、Main Reactor 负责接收客户端的连接请求,然后把接收到的请求传递给 SubReactor(其中 subReactor 可以有多个),具体的业务 IO 处理由 SubReactor 完成。

        2、Acceptor,请求接收者,在实践时其职责类似服务器,并不真正负责连接请求的 建立,而只将其请求委托 Main Reactor 线程池来实现,起到一个转发的作用。

        3、Main Reactor,主 Reactor 线程组,主要负责连接事件,并将 IO 读写请求转发到 SubReactor 线程池。

        4、Sub Reactor,Main Reactor 通常监听客户端连接后会将通道的读写转发到 Sub Reactor 线程池中一个线程(负载均衡),负责数据的读写。在 NIO 中 通常注册通 道的读(OP_READ)、写事件(OP_WRITE)。


补充:TCP的粘包拆包技术

        TCP 是一个面向「流」的协议,所谓流就是没有界限的一长串二进制数据。在实际的传输过程中,TCP 会根据网络情况将数据包进行拆分或者拼装,如果业务没有定义一个明确的界限规则,在应用层的业务上就会出现粘包拆包的现象。

        平时大家在网络编程过程中可能会遇到这样一种现象:客户端发送了一长串消息,服务端接受的消息揉在一起或者被拆分了,这样就会造成消息难以被正确理解。比如说有一天你特别想喝奶茶,看了一下外卖,某某奶茶看着不错,于是你在群里发了一条消息,想找几个人拼奶茶:
奶茶有人喝吗?结果群里同事回了一句:现在不是已经三点了吗?你觉得莫名其妙,看了一眼同事的手机,他收到的消息是这样的两行:
                一点
                点奶茶有人喝吗?

        用专业的术语来说这种现象就是「拆包」了。


TCP 粘包拆包的现象

        粘包拆包问题一般是处于应用层下的问题,在数据链路层、网络层以及传输层都有可能发生。我们日常的网络应用开发大多都在传输层进行,因此本文着重讲解传输层粘包拆包问题。

传输层        传输层有两个协议我们都很熟悉:UDP 和 TCP,UDP有消息保护边界,不会发生粘包拆包问题,因此粘包拆包问题只发生在TCP协议中。

        下面用一个简单的例子来讲解什么是粘包和拆包。

        假设客户端向服务端连续发送了两个数据包,用 packet1 和 packet2 来表示,那么服务端收到的数据可能有四种:

        (1) 第一种情况,服务端按顺序正常收到两个包,即未出现粘包和拆包的现象。

         (2) 第二种情况,服务端只收到一个数据包,由于 TCP 保证送达的特性,所以这一个数据包包含了客户端发送的两个数据包的信息,这种现象就是粘包。除非客户端发送的数据包有明确的规则,否则服务端不知道两个包的界限,难以处理数据。

 

        (3) 第三种情况,服务端收到了三个数据包,Package1数据包被拆分为两个数据包:Package1.1和Package1.2,这种现象就是拆包,至于拆包的原因下面会讲,服务端收到拆开的数据包也很难处理。

        

       (4) 第四种情况,一些大的数据包被拆分为小的数据包,小的数据包与其他数据包粘在一起,这种现象是将上面的粘包和拆包综合在一块。

 

 


TCP 粘包拆包的原因

        TCP 是一个面向「流」的协议,所谓流就是没有界限的一长串二进制数据。TCP 作为传输层协议并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行数据包的划分,所以在业务上认为是一个完整的包,可能会被 TCP 拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就会出现粘包拆包的问题。

        例如,TCP缓冲区是1024个字节大小,如果应用一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,站在业务上来看这就是「粘包」;

        如果应用一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是「拆包」,也就是将一个大的包拆分为多个小包进行发送。


TCP 粘包拆包的解决方法

        TCP 是面向流的,会发生粘包和拆包,那作为应用程序,如何从这源源不断涌来的数据流中拆分出或者合并出有意义的信息呢? 通常会有以下一些常用的方法:

(1) 发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

如下图,在每个包前面加上包的实际长度。

 

 

(2) 发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。

下图每个包的固定长度为 4,接收端很容易进行区分。

                 

(3) 可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

如下图,在每个包的后面加上特殊字符:/

                       


Netty框架解决粘包拆包问题

        Netty 作为一款高性能的 Java 网络编程框架,不仅是基于 Java NIO 进行了深度封装,还在客户端与服务端之间的数据传输上做了有效处理。

        前面说过 TCP 传输会出现粘包和拆包的现象,Netty 针对这一点内置了多款数据流编解码器,客户端服务端按照约定好的规则进行数据传输即可解决这个问题。

Netty 提供了多款开箱即用的编解码器:

  1. (1)FixedLengthFrameDecoder 固定长度解码器
  1. (2)DelimiterBasedFrameDecoder 指定分隔符解码器
  1. (3)LengthFieldBasedFrameDecoder 基于数据包长度解码器
  1. (4)等等……这里不再列举

小结 

TCP 是一个面向「流」的协议,所谓流就是没有界限的一长串二进制数据。在实际的传输过程中,TCP 会根据网络情况将数据包进行拆分或者拼装,如果业务没有定义一个明确的界限规则,在应用层的业务上就会出现粘包拆包的现象。

针对 TCP 粘包拆包的现象,常见的解决思路如下:

        (1) 发送端给每个数据包添加包首部。

        (2) 发送端将每个数据包封装为固定长度。

        (3) 可以在数据包之间设置边界。

为了解决粘包拆包,Netty 框架也提供了很多开箱即用的编解码器,极大简化网络编程解决此类问题的难度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/63437.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓13不再支持PPTP怎么办?新的连接解决方案分享

随着Android 13的发布,我们迎来了一个令人兴奋的新品时刻。然而,对于一些用户而言,这也意味着必须面对一个重要的问题:Android 13不再支持PPTP协议。如果你是一个习惯使用PPTP协议来连接换地址的用户,那么你可能需要重…

微信小程序中键盘弹起输入框自动跳到键盘上方处理

效果展示 键盘未弹起时 键盘弹起后: 实现方式 话就不多说了 我直接贴代码了 原理就是用你点击的输入框的底部 距离顶部的位置 减去屏幕高度除以2,然后设成负值,再将这个值给到最外层相对定位的盒子的top属性,这样就不会出现顶…

【Hystrix技术指南】(7)故障切换的运作流程原理分析(含源码)

背景介绍 目前对于一些非核心操作,如增减库存后保存操作日志发送异步消息时(具体业务流程),一旦出现MQ服务异常时,会导致接口响应超时,因此可以考虑对非核心操作引入服务降级、服务隔离。 Hystrix说明 官方…

使用 Python 和 Flask 构建简单的 Restful API 第 1 部分

一、说明 我将把这个系列分成 3 或 4 篇文章。在本系列的最后,您将了解使用flask构建 restful API 是多么容易。在本文中,我们将设置环境并创建将显示“Hello World”的终结点。 我假设你的电脑上安装了python 2.7和pip。我已经在python 2.7上测试了本文…

C语言属刷题训练【第八天】

文章目录 🪗1、如下程序的运行结果是( )💻2、若有定义: int a[2][3]; ,以下选项中对 a 数组元素正确引用的是( )🧿3、在下面的字符数组定义中,哪一个有语法错…

大厂容器云实践之路(一)

1-华为CCE容器云实践 华为企业云 | CCE容器引擎实践 ——从IaaS到PaaS到容器集群 容器部署时代的来临 IaaS服务如日中天 2014-2015年,大家都在安逸的使用IaaS服务; 亚马逊AWS的部署能力方面比所有竞争对手…

从零构建深度学习推理框架-7 计算图的表达式

什么是表达式 表达式就是一个计算过程,类似于如下: output_mid input1 input2 output output_mid * input3用图形来表达就是这样的。 但是在PNNX的表达式(Experssion Layer)中不是这个样子,而是以一种抽象得方式,…

Active Directory安全和风险状况管理

风险评估和管理 风险评估和管理是主动安全性和合规性管理不可或缺的一部分。 发现关键基础设施组件中的风险行为和配置对于阻止网络入侵和预防网络攻击至关重要。帐户泄露和配置错误漏洞是用于破坏网络的常见技术。当评估、监控和降低 Active Directory 基础架构的风险时&…

HCIP 链路聚合技术

1、链路聚合概述 为了保证网络的稳定性,仅仅是设备进行备份还不够,我们需要针对我们的链路进行备份,同时也增加了链路的利用率,提高带宽。避免一条链路出现故障,导致网络无法正常通信。这就可以使用链路聚合技术。 以…

图片预览插件vue-photo-preview的使用

移动端项目中需要图片预览的功能,但本身使用mintui,vantui中虽然也有,但是为了一个组件安装这个有点儿多余,就选用了vue-photo-preview插件实现(其实偷懒也不想自己写)。 1、安装 npm i vue-photo-preview…

计算机竞赛 LSTM的预测算法 - 股票预测 天气预测 房价预测

0 简介 今天学长向大家介绍LSTM基础 基于LSTM的预测算法 - 股票预测 天气预测 房价预测 这是一个较为新颖的竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/postgraduate 1 基于 Ke…

怎么做Tik Tok海外娱乐公会呢?新加坡市场怎么样?

一、为什么选择TikTok直播 1. 海外市场潜力巨大 • 自2016年始,多家直播平台陆续拓展至东南亚、中东、俄罗斯、日韩、欧美、拉美等地区。 • 海外市场作为直播发展新蓝海,2021年直播行业整申请cmxyci体规模达百亿美元,并维持高速增长。 &a…