Netty详解

初识Netty

Netty是一个高性能、异步事件驱动的NIO框架,提供了对TCP、UDP和文件传输的支持,核心功能是让客户端和服务端两者之间进行通信交流。

如果上述这种说法太过于官方,不容易理解的话,那我换种无脑式说法。

Netty的作用是,对TCP/UDP编程进行了简化和封装,提供了更容易使用的网络编程接口

所以,说到这里,我们就明白为什么Dubbo、gRPC等RPC框架会用到Netty了吧,因为它们都存在服务消费者调用服务提供者的场景。

可以这样说,但凡用Java开发的、跟网络IO相关的中间件,基本上少不了Netty的影子。

另外,Netty的底层是依赖于JDK中的NIO,在此之上进行了优化,包括如下几点:

  • 简化概念,降低编程复杂性。
  • 在性能上得到很大提升。
  • 解决了JDK中epoll selector空轮询导致CPU 100%的问题。


Netty & Tomcat

Netty 和 Tomcat 最大的区别在于对通信协议的支持。Tomcat 是基于 HTTP 协议的,本质是一个基于HTTP协议的Web容器,而Netty则是以TCP、UDP协议为主,并支持通过编程自定义各种协议。


核心组件

从某种意义上说,了解的Netty的核心组件,也就理顺的它整体的运行过程。

网上基于这五个组件的解释众说纷纭,我不得已在此基础上加入了自己的理解。

Channel:相当于socket,与另一端进行通信的通道,具备bind、connect、read、write等IO操作的能力。EventLoop事件循环,负责处理Channel的IO事件,一个EventLoopGroup包含多个EventLoop,一个EventLoop可被分配至多个Channel,一个Channel只能注册于一个EventLoop,一个EventLoop只能与一个Thread绑定。ChannelFuture:channel IO事件的异步操作结果。
ChannelHandler:包含IO事件具体的业务逻辑
ChannelPipeline:ChannelHandler的管道容器。


高性能

从宏观来讲,Netty的高性能主要在于:Reactor模式、Zero Copy和对象池

1、Reactor模式

通过设置不同的启动参数,Netty可以同时支持单Reactor单线程模型、单Reactor多线程模型和主从Reactor多线层模型

Reactor模型思想:

分而治之 + 事件驱动(优点:模块化、高性能————把大拆小,减少阻塞时间)

分而治之

一个连接里完整的网络处理过程一般分为accept、read、decode、process、encode、send(write)这几步。

Reactor模式将每个步骤映射为一个Task,服务端线程执行的最小逻辑单元不再是一次完整的网络请求,而是Task,且采用非阻塞方式执行。

事件驱动

相应的Task(accept、read、write)对应特定网络事件。当Task准备就绪时,Reactor收到对应的网络事件通知,并将Task分发给绑定了对应网络事件的Acceptor和Handler执行。

Netty基于Reactor模型实现,Reactor模型主要由Acceptor、Reactor、Handler组成。

Netty 通过 Reactor 模型基于多路复用器接收并处理用户请求,内部实现了两个线程池, boss 线程池和 worker 线程池,其中 boss 线程池的线程负责处理请求的 accept 事件,当接收 到 accept 事件的请求时,把对应的 socket 封装到一个 NioSocketChannel 中,并交给 worker 线程池,其中 work 线程池负责请求的 read 和 write 事件,由对应的 Handler 处理。

Netty线程模型:


 

2、Zero Copy

Zero Copy技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域,这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽

举例来说,如果要读取一个文件并通过网络发送它,传统方式下每个读/写周期都需要复制两次数据和切换两次上下文,而数据的复制都需要依靠CPU。通过零复制技术完成相同的操作,上下文切换减少到两次,并且不需要CPU复制数据。

3、对象池

对象池模式(The Object Pool Pattern)是单例模式的一个变种,对象池模式管理一个可代替对象的集合,组件从池中借出对象,用它来完成一些任务并当任务完成时归还该对象。

Netty中的Recycler,该类是个容器,基于ThreadLocal实现的的轻量级对象池,内部主要是一个Stack结构。当需要使用一个实例时,就弹出,当使用完毕时,就清空后入栈。


拆包粘包

TCP是一种流协议(stream protocol),先把数据流拆分成适当长度的报文段,然后TCP把数据包传给IP层,由它来通过网络将数据包传送给接收端的IP层。

MTU (Maxitum Transmission Unit),最大传输单元,是链路层对一次可以发送的最大数据的限制。

MSS(Maxitum Segment Size),最大分段大小,是TCP报文中data部分的最大长度,是传输层对一次可以发送的最大数据的限制。

MTU(1500字节) = MSS(1460字节) + TCP header (20字节) + IP header (20字节)

假设客户端分别发送两个数据包D1、D2个服务端:

  • 粘包:服务端一次接收到了D1和D2两个数据包,两个包粘在一起;
  • 拆包:服务端分三次读到了数据部分,第一次读到了D1包,第二次读到了D2包的部分内容,第三次读到了D2包的剩下内容;
  • 拆包粘包:服务端分两次读到了数据包,第一次读到了D1和D2的部分内容,第二次读到了D2的剩下部分;

解决方案

  • 设置定长消息,服务端每次读取既定长度的内容作为一条完整消息(如:不足补0000等)。
  • 设置消息边界,服务端从网络流中按消息编辑分离出消息内容(如:数据边界的标识为换行符"\n")。
  • 使用带消息头的协议,消息头存储消息开始标识及消息长度信息,服务端获取消息头的时候解析出消息长度,然后向后读取该长度的内容。

Netty中的解决方案

  • FixedLengthFrameDecoder(使用定长的报文来分包)
  • DelimiterBasedFrameDecoder(添加特殊分隔符报文来分包)
  • LineBasedFrameDecoder(数据未尾添加回车换行符来分包)
  • LengthFieldBasedFrameDecoder(使用消息头和消息体来分包)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值