Netty 原理

        前段时间在看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对事件流的拦截和处理流程:

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 基本原理 - 轮回的博客 - CSDN博客

版权声明:本文为博主原创文章,转载请附上博文链接!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容