转载。 https://blog.csdn.net/qq_27641935/article/details/86543578

之前在看rocketmq源码时,发现底层用了Netty,顺便学习了一下,网上不少博客讲的有错误之处,而且大部分一模一样,估计大部分都是复制别人的。为了不被误导,我专门买了本《Netty权威指南》,仔细阅读了一遍,而且微信请教了锋哥(李林锋),遂整理出这篇分享。

本人一直秉承原则:宁愿不写、少写,也尽量不写错的知识!以免误人子弟!

希望转载的同学,标出原文链接。谢谢!同时非常欢迎指出错误,本人及时修正!

版本说明

Netty3(3.x)版本是比较旧的版本。

Netty4(4.x)版本是当前官方推荐的,目前一直在维护中。跟3.x版本相比变化比较大,特别是API。

Netty5(5.x)是被舍弃的版本,官方不推荐使用!

Netty5舍弃的官方解释:

1. netty5中使用了 ForkJoinPool,增加了代码的复杂度,但是对性能的改善却不明显

2. 多个分支的代码同步工作量很大

3. 作者觉得当下还不到发布一个新版本的时候

4. 在发布版本之前,还有更多问题需要调查一下,比如是否应该废弃 exceptionCaught,是否暴露EventExecutorChooser等等。

参考:https://github.com/netty/netty/issues/4466

1. Netty基本概念

Netty是一个高性能、异步事件驱动的NIO框架它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果

作为当前最流行的NIO框架,Netty在互联网领域、大数据分布式计算领域、游戏行业、通信行业等获得了广泛的应用,一些业界著名的开源组件也基于Netty的NIO框架构建。如:Dubbo、 RocketMQ、Hadoop的Avro、Spark等。

Netty需要学习的内容: 编解码器、TCP粘包/拆包及Netty如何解决、ByteBuf、Channel和Unsafe、ChannelPipeline和ChannelHandler、EventLoop和EventLoopGroup、Future等。

编解码器

Java序列化的目的主要有两个:

  • 网络传输
  • 对象持久化

Java序列化仅仅是Java编解码技术的一种,由于他的种种缺陷,衍生出多种编解码技术和框架。

Java序列化的缺点:

  • 无法跨语言
  • 序列化后的码流太大
  • 序列化性能太低

业界主流的编解码框架:

  • Google Protobuf:支持Java、C++、Python三种语言,高效的编码性能,结构化数据存储格式(XML,JSON等)
  • Facebook Thrift:适用于静态的数据交换,需要先确定好它的数据结构。结构变化后需要重新编译IDL文件,这也是Thrift的弱项。
  • JBoss Marshalling:是一个Java对象的序列化API,修正了JDK自带的序列化包的很多问题,但又保持跟java.io.Serializable接口的兼容。
  • Hessian:一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能,采用的是二进制RPC协议。

TCP粘包/拆包:

TCP是个“流”协议,所谓流,就是没有界限的一串数据。TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓存区的实际情况进行包的划分,所以在业务上的一个完整的包,可能被TCP拆分成多个包进行发送,也可能把多个小包封装成一个大的数据包发送,这就是TCP粘包和拆包问题。

有如下几种情况:

正常情况

粘包

粘包和拆包同时发生

2. Netty线程模型

在JAVA NIO方面Selector给Reactor模式提供了基础,Netty结合Selector和Reactor模式设计了高效的线程模型。

关于Java NIO 构造Reator模式,Doug Lea在《Scalable IO in Java》中给了很好的阐述,这里截取PPT对Reator模式的实现进行说明。

(1)Reactor单线程模型

这是最简单的Reactor单线程模型,由于Reactor模式使用的是异步非阻塞IO,所有的IO操作都不会被阻塞,理论上一个线程可以独立处理所有的IO操作。这时Reactor线程是个多面手,负责多路分离套接字,Accept新连接,并分发请求到处理链中。

对于一些小容量应用场景,可以使用到单线程模型。但对于高负载,大并发的应用却不合适,主要原因如下:

1. 当一个NIO线程同时处理成百上千的链路,性能上无法支撑,即使NIO线程的CPU负荷达到100%,也无法完全处理消息。

2. 当NIO线程负载过重后,处理速度会变慢,会导致大量客户端连接超时,超时之后往往会重发,更加重了NIO线程的负载。

3. 可靠性低,一个线程意外死循环,会导致整个通信系统不可用。

为了解决这些问题,出现了Reactor多线程模型。

(2)Reactor多线程模型

相比上一种模式,该模型在处理链部分采用了多线程(线程池)。

在绝大多数场景下,该模型都能满足性能需求。但是,在一些特殊的应用场景下,如服务器会对客户端的握手消息进行安全认证。这类场景下,单独的一个Acceptor线程可能会存在性能不足的问题。为了解决这些问题,产生了第三种Reactor线程模型。

(3)Reactor主从模型 

该模型相比第二种模型,是将Reactor分成两部分,mainReactor负责监听server socket,accept新连接;并将建立的socket分派给subReactor。subReactor负责多路分离已连接的socket,读写网络数据,对业务处理功能,其扔给worker线程池完成。通常,subReactor个数上可与CPU个数等同。

利用主从NIO线程模型,可以解决一个服务端监听线程无法有效处理所有客户端连接的性能不足问题,因此,在Netty的官方Demo中,推荐使用该线程模型。

(4)Netty模型

Netty的线程模型并不是一成不变,它实际取决于用户的启动参数配置。通过设置不同的启动参数,Netty可以同时支持Reactor单线程模型、多线程模型和主从模型。

前面介绍完 Netty 相关一些理论,下面从功能特性、模块组件来介绍 Netty 的架构设计。

3. Netty功能特性

下图是Netty的功能特性:

4. Netty模块组件

Netty主要有下面一些组件:

  • Selector
  • NioEventLoop
  • NioEventLoopGroup
  • ChannelHandler
  • ChannelHandlerContext
  • ChannelPipeline

Selector

Netty 基于 Selector 对象实现 I/O 多路复用,通过 Selector 一个线程可以监听多个连接的 Channel 事件。

NioEventLoop

其中维护了一个线程和任务队列,支持异步提交执行任务,线程启动时会调用 NioEventLoop 的 run 方法,执行 I/O 任务和非 I/O 任务。

NioEventLoopGroup

主要管理 eventLoop 的生命周期,可以理解为一个线程池,内部维护了一组线程,每个线程(NioEventLoop)负责处理多个 Channel 上的事件,而一个 Channel 只对应于一个线程。

ChannelHandler

是一个接口,处理 I/O 事件或拦截 I/O 操作,并将其转发到其 ChannelPipeline(业务处理链)中的下一个处理程序。

ChannelHandlerContext

保存 Channel 相关的所有上下文信息,同时关联一个 ChannelHandler 对象。

 

ChannelPipeline 是保存 ChannelHandler 的 List,用于处理或拦截 Channel 的入站事件和出站操作。实现了一种高级形式的拦截过滤器模式,使用户可以完全控制事件的处理方式,以及 Channel 中各个的 ChannelHandler 如何相互交互。

ChannelPipeline对事件流的拦截和处理流程:

Netty中的事件分为Inbond事件和Outbound事件。

Inbound事件通常由I/O线程触发,如TCP链路建立事件、链路关闭事件、读事件、异常通知事件等。

Outbound事件通常是用户主动发起的网络I/O操作,如用户发起的连接操作、绑定操作、消息发送等。

在 Netty中,Channel 、ChannelHandler、ChannelHandlerContext、 ChannelPipeline的关系如下图:

一个 Channel 包含了一个 ChannelPipeline,而 ChannelPipeline 中又维护了一个由 ChannelHandlerContext 组成的双向链表并且每个 ChannelHandlerContext 中又关联着一个 ChannelHandler。

入站事件和出站事件在一个双向链表中,入站事件会从链表 head 往后传递到最后一个入站的 handler,出站事件会从链表 tail 往前传递到最前一个出站的 handler,两种类型的 handler 互不干扰。

以上是Netty的主要原理介绍,Netty源码分析的话,后续有时间会继续分享出来。

Netty 基本原理的更多相关文章

  1. Netty通信原理

    Netty是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端,它极大的简化了TCP和UDP套接字服务器等网络编程. BIO(Blocking IO):每一个请求,一个S ...

  2. 这可能是目前最透彻的Netty原理架构解析

    https://juejin.im/post/5be00763e51d453d4a5cf289 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希 ...

  3. Netty原理架构解析

    Netty原理架构解析 转载自:http://www.sohu.com/a/272879207_463994本文转载关于Netty的原理架构解析,方便之后巩固复习 Netty是一个异步事件驱动的网络应 ...

  4. 【Netty】最透彻的Netty原理架构解析

    这可能是目前最透彻的Netty原理架构解析 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希望给大家在实际开发实践.学习开源项目方面提供参考. ...

  5. dubbo在idea下的使用创建 服务者,消费者 注册中心

    1.基于windows 下  spring 下的dubbo  需要书写配置文件 (1).创建带有web工程的项目 创建一个服务者 package cn.edu.aynu.bean; import lo ...

  6. 一个I/O线程可以并发处理N个客户端连接和读写操作 I/O复用模型 基于Buf操作NIO可以读取任意位置的数据 Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel 事件驱动消息通知观察者模式

    Tomcat那些事儿 https://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650860016&idx=2&sn=549 ...

  7. Netty--索引

    Netty 入门示例 Netty原理架构解析 Netty 基本原理 Netty面试题 阿里的Netty知识点你又了解多少

  8. dubbo入门学习(六)-----dubbo原理

    RPC原理 一次完整的RPC调用流程(同步调用,异步另说)如下: 1)服务消费方(client)调用以本地调用方式调用服务: 2)client stub接收到调用后负责将方法.参数等组装成能够进行网络 ...

  9. 🏆【Alibaba微服务技术系列】「Dubbo3.0技术专题」回顾Dubbo2.x的技术原理和功能实现及源码分析(温故而知新)

    RPC服务 什么叫RPC? RPC[Remote Procedure Call]是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范.它允许程序调用另一个地址空间(通常是共享网络的另 ...

随机推荐

  1. 学习:c++指向指针的指针(多级间接寻址)

    指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链.通常,一个指针包含一个变量的地址.当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置. 当一个 ...

  2. c++ main函数

    vs 2015的运行环境 1.参数 int main(int argc, char* argv[]) 1)两个参数的类型是固定的,但参数名可以是符合命名规则的任何命名 2)argv[0]为执行文件的路 ...

  3. react基本语法及组件

    一.react简介 1.起源:React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源. 2.特点: 1.声明式设计 −React采用声明 ...

  4. 71: libreoj #10151 区间dp

    $des$ https://loj.ac/problem/10151 $sol$ 区间dp $f_{i, j}$ 表示区间 $[l, r]$ 合并的最大值 枚举中间点 $k$ $f_{i, j} =m ...

  5. 【loj2985】【WC2019】I君的商店

    题目 交互题: 有\(n\)个物品,每个物品的价格为0或者1; 给出为1的物品的个数奇偶性k,并保证至少有一个价格为1: 每次可以询问一个集合S的另一个集合T的价值和的大小,交互库会返回>=或者 ...

  6. 56、Spark Streaming: transform以及实时黑名单过滤案例实战

    一.transform以及实时黑名单过滤案例实战 1.概述 transform操作,应用在DStream上时,可以用于执行任意的RDD到RDD的转换操作.它可以用于实现,DStream API中所没有 ...

  7. windows 10下启用docker的k8s集群

    安装Docker Desktop后,由于国内无法下载到Kubernete的文件,在Docker Desktop设置里勾选启用Kubernete一直显示”Kubernete is starting”状态 ...

  8. 动态BGP与静态BGP

    在阿里云上选择ECS的时候,发现有动态BGP和静态BGP区分,静态的要便宜些,搜了下区别如下: 静态BGP路由是指由网络运营商手动配置的路由信息.当网络的拓扑结构或链路的状态发生变化时,运营商需要手动 ...

  9. 【maven】插件和依赖管理

    1.插件管理 定义 pluginManagement 用来做插件管理的.它是表示插件声明,即你在项目中的pluginManagement下声明了插件,Maven不会加载该插件,pluginManage ...

  10. 记某app内购破解 – 安卓逆向菜鸟的初体验

    前言 因为某个机缘,我拿到一个赛车app,玩了一会想买个装备,居然要我掏钱包,作为一名cracker,我觉得我的尊严受到了严重的蔑视(无奈钱包空空),我觉得要捍卫我那脆弱的玻璃心(钱包),所以,开干吧 ...