`
sunxboy
  • 浏览: 2868667 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Netty4.x分析

 
阅读更多

官网定义: netty是一个异步、事件驱动的网络应用框架,用于快速开发可维护的、高性能的服务端和客户端程序。

原理分析 

Architecture Overview

网络模型:netty采用了Reactor设计模式,Reactor设计可分三种:

单线程版本,如图:

 

学C的朋友会知道IO多路复用,我感觉和这个Reactor模式差不多,Reactor收到新连接调用acceptor的accept,返回的SocketChannel会注册到Reactor里,当连接可读或者可写时,分发一个handler处理。

多线程版本,如图:

 

处理部分增加了线程池。

Multi-Reactor版本:

 

监听端口注册到mainReactor里,有连接,调用accept,返回的连接注册到subReactor里,subReactor只负责读写,处理部分交给线程池。

Netty采用的方式类似于第三种,Netty3.6里mainReactor对应Boss类,subReactord对应NioWorker类;4.x里是实现EventLoopGroup接口的某个类,如NioEventLoopGroup(multithreaded event loop that handles I/O operation),EventLoopGroup相当于管理EventLoop的线程池,thread数量是可以配置的,echoServer例子中:

42,43行就是boss和worker了,ServerBootstrap是设置服务器的帮助类。

47行用NioServerSocketChannel类说明后面会用它去实例channel来接受incoming连接。

48行option方法可以指定Channel实现的方式。

50行:subReactor监听的channel来事件了,处理方法要通过childHandler方法指定,这是需要我们实现的,childHandler方法的参数是ChannelHandler接口的某个类,然后回调;拿FactorialServerInitializer举例,层次关系如图:

ChannelInitializer用来配置channel,这里要实现抽象类ChannelInitializer里的initChannel方法,意味着要在initChannel方法里配置pipeline。

我们观察EventLoopGroup类,如下图所示:

 

EventExecutor和EventLoopGroup都包含通用的 event loop API;EventLoopGroup有register方法,提供向其注册channel,返回ChannelFuture;

Netty Pipeline:

每个channel都有自己的pipeline,channel创建则对应的pipeline自动创建,下图显示了IO事件如何通过ChannelHandler在ChannelPipeline中处理的:

 

在pipeline里,每个stage运行一个InboundHandler或OutboundHandler,设计过MIPS经典五段pipeline的朋友应该知道锁存器设计,这里对应ChannelHandlerContext,ChannelHandlerContext可以通知ChannelPipeline里下一个ChannelHandler工作,并把事件流传给下一个ChannelHandler,也可以动态修改它所属的ChannelPipeline;

Inbound事件流传递方法:

Outbound事件流传递方法:

 我们看下官网的例子,io.netty.example.factorial 这个包,Pipeline部分(服务端):

 

当Socket.read()发生时,handler处理事件的顺序是:BigIntegerDecoder->FactorialServeHandler

当Socket.write()发生时,handler处理事件的顺序是:NumberEncoder

ChannelInboundHandlerAdapter的方法:

ChannelOutboundHandlerAdapter的方法:

关于Pipeline的一些说明:并不是一个阶段执行完了,才去执行下一个阶段,而是每个Handler有对应的事件处理方法(如上ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter中的方法),当这个Handler接收到了某事件,就会调用这个事件处理方法,然后会触发下个Handler对应的事件处理方法,下面用自带的io.netty.example.http.helloworld包验证这个想法(在方法里插了输出):

Socket.read():HttpServerCodec->HttpHelloWorldServerHandler;

Socket.write():HttpServerCodec

Zero Copy:

Netty里用到了ZC技术,这里是介绍ZeroCopy比较好的一篇文章,Netty里FileRegion就是用来支持ZeroCopy的接口,ZC在传输大文件时比较有优势,把大文件指定到Channel上,直接传输,不经过Application层。

 Channel包:

Channel接口封装了socket,提供IO操作(如read,write,connect,bind等)的组建,具体属性、方法可参考文档;

ChannelFuture接口继承了io.netty.util.concurrent.Future,Netty中IO调用均是异步的,调用立即返回,返回结果记录在ChannelFuture里,ChannelFuture随着IO操作的开始而被创建,它的状态可以是完成或者未完成,初始态是未完成,状态如下:

我们可以通过向ChannelFuture里增加和删除ChannelFutureListener(继承GenericFutureListener)(通过addListener(s)、removeListener(s)方法),IO操作完成时触发GenericFutureListener的operationComplete方法执行,这是异步的操作;我们也可以调用ChannelFuture的await方法阻塞Control Flow,直到ChannelFuture完成。

ChannelPipeline已在上文介绍;

Buffer包:

Netty使用自己的buffer API处理字节序列,而不是使用NIO自带的buffer,这样的定制有很多优势吧,官方文档是这么说的:在常见的网络应用中,我们会有一些buffer,它们经常需要组装成一个buffer,netty提供composite buffer,它允许你把已经存在的几个buffer组合起来创建一个virtual buffer,不需要内存拷贝:

还有许多协议的MTU都是不确定的,Netty允许你创建动态大小的buffer,来降低内存开销。

Channel读的数据会写到实现ByteBuf接口的某个类里,ByteBuf里数据满了,会调用handler处理,io.netty.handler.codec包里面会有一些类把package frame,也就是收到的ByteBuf decode成Message,交给handler处理;ByteBuf提供Java nio缓存(ByteBuffer)类似的方法,ByteBuf接口的实现层次图:

buffer包中有一个帮助类Unpooled,用于创建ByteBuf,所有的ByteBuf都是通过ByteBufAllocatore和UnpooledByteBufAllocator分配的,在Unpooled类里,默认的分配器是UnpooledByteBufAllocator,默认分配的ByteBuf类型是UnpooledHeapByteBuf;

HeapByteBuf是在Java堆上分配内存;DirectByteBuf用的是NIO的ByteBuffer,CompositeByteBuf是一个虚拟的buffer,将多种buffer合并成一个buffer;

细心的同学会看到PoolByteBuf和UnpooledByteBuf,PoolByteBuf是4.0新引入的,设计思想借鉴jemalloc(core:混合了slab分配器和buddy分配器),优点是减少内存碎片,Slab分配器是基于对象管理的,分配对象,直接从Slab系统里拿,无需再次初始化,释放对象,则保留在Slab系统里,标记为脏,不需释放,降低GC压力;

 io.netty.handler.codec包:

ByteToMessageCodec类封装了ByteToMessageDecoder和MessageToByteEncoder(都作为Pipeline Handler);我们先观察ByteToMessageDecoder,其可以将流式的字节转化成消息类型,他有一个成员cumulation(ByteBuf类型),收消息时会把收到的msg(ByteBuf类型)传递给cumulation,数据准备好后调用callDecode,callDecode进一步调用decode方法(具体分帧方法),这个方法交给子类实现;MessageToByteEncoder里的write方法同理,write里调用子类实现的encode方法将消息encode成ByteBuf,发送出去。

分享到:
评论

相关推荐

    Netty3.x 源码解析

    本系列文章是对Netty3.x版本源码的详细解读,旨在帮助读者深入理解Netty内部的工作机制以及其设计理念。Netty源码阅读的目的通常有两个:一是因为工作中使用到了Netty,希望通过阅读源码来更加深入地了解它;二是...

    Netty4.x源码分析详解

    在深入分析 Netty 4.x 源码之前,我们首先需要了解其核心概念和架构。 Netty 的核心组件包括: 1. **ByteBuf**: 作为传统 ByteBuffer 的替代品,ByteBuf 提供了更高效且易用的内存管理机制,支持读写分离,避免了...

    Netty3.x 源码

    Netty3.x 版本是其早期的一个版本,虽然现在最新的版本已经发展到了4.x,但3.x版本仍然具有学习价值,特别是对于理解Netty的基本原理和设计模式。 首先,让我们来看看`pom.xml`文件。这是Maven项目对象模型的配置...

    SimpleWeb:基于Netty4.x的简单Web框架

    "SimpleWeb:基于Netty4.x的简单Web框架" 指的是一种使用Netty 4.x版本构建的轻量级Web框架。Netty是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。SimpleWeb可能是该...

    netty4 sources 源码

    这个“netty4 sources 源码”指的是Netty 4.x 版本的源代码,其中4.0.33.Final是特定的版本号。源码分析对于理解Netty的工作原理、优化性能以及定制化开发非常有帮助。 Netty 的核心特性包括: 1. **异步事件驱动*...

    MINA2与Netty4比较分析

    接下来将根据标题和描述的要求详细分析Mina2与Netty4的区别,重点从它们的线程模型、Buffer使用以及Netty4中集成的序列化工具ProtoBuf等方面进行比较。 首先,Mina2和Netty4都是异步事件驱动的网络应用框架。Netty4...

    netty-socket.zip

    Netty 5虽然不是最新的版本(当前最新为Netty 4.x),但仍然具备上述提到的优点。开发者可以通过分析其中的代码,学习如何结合Netty与Socket,创建更高效的网络通信服务。这个示例可能包含了服务器端和客户端的实现...

    4.1.66.Final.jar

    Netty 4.1.66.Final.jar作为4.1.x系列的一个稳定版本,包含了以下关键特性: 1. 优化的ByteBuf:Netty的内存管理组件,提供高效的数据读写和缓冲,避免不必要的内存拷贝。 2. Channel:Netty的核心组件,代表一个...

    Netty实战 电子版1

    5. **Netty 4.x**:本书重点聚焦于Netty 4.x版本,这是Netty的一个重大升级,带来了更好的性能和更多的特性。读者会学习到4.x版本的新功能,如Epoll native transport在Linux上的应用,以及新的内存管理策略。 6. *...

    使用Eclipse_Vert.x开发响应式应用_英文.pdf

    4. **事件总线(Event Bus)**:事件总线是Vert.x 的核心组件,它是一个分布式的、发布/订阅的消息系统,允许不同模块之间通过传递消息进行通信,无论这些模块是否在同一个进程中。 5. **网络库**:Vert.x 包含了HTTP...

    netty-netty-4.1.28.Final:netty-netty-4.1.28。最终源码分析

    JDK 5(用于3.x)或6(用于4.0+)足以运行基于Netty的应用程序。 分支机构看 所有版本的开发都在名称与<majorVersion>.相同的每个分支中进行。 例如,3.9和4.0的开发分别位于和。 与JDK 9结合使用 Netty可以在模块...

    jboss netty5.0

    尽管在撰写本文时,Netty 的最新稳定版本是 4.x 系列,但了解早期版本对于理解其发展历程和基本原理仍然很有价值。 标题 "jboss netty5.0" 提及了 JBoss,这是一个开源的应用服务器,后来成为了 Red Hat 企业版 ...

    netty-transport-udt-4.0.10.Final.zip

    描述中的"subset2.zip,MongoDB文档分析器组合器和生成器子集2.x"可能是指这个项目包含了一个针对MongoDB数据库的特定组件或工具集。MongoDB是一个流行的NoSQL数据库,其文档分析器和组合器可能指的是用于处理和分析...

    Netty案例集锦(并发编程篇)有目录

    升级Netty至3.X版本后,发现线程上下文丢失,影响了业务逻辑的正常执行。 ##### 11.2 问题分析 分析线程上下文丢失的原因,可能与版本升级后的配置差异有关。 ##### 11.3 问题总结 总结线程上下文丢失的解决方法...

    Java Netty-入门教程.pdf

    - 经过长期的发展和完善,Netty 已经非常成熟稳定,经历了多个版本的迭代,如 2.x(2004)、3.x(2008)、4.x(2013)等,每个版本都带来了显著的性能和功能改进。 - 社区活跃,有大量的案例和资源可供参考学习。 ...

    Android使用netty

    在Android端,首先需要添加Netty的依赖库到build.gradle文件中,通常使用的是Android Studio的Gradle插件,添加依赖后,通过`implementation 'io.netty:netty-all:x.x.xFinal'`(这里的x.x.xFinal替换为具体的版本号...

    vertx样例代码

    2. **非阻塞I/O**:Vert.x采用非阻塞I/O模型,利用了Java的Netty库,使得系统能处理大量并发连接,提高了性能和资源利用率。 3. ** Verticle**:Verticle是Vert.x中的基本执行单元,可以理解为微服务或者工作线程。...

    Netty权威指南 第2版 带书签目录 完整版 中文 PDF

    - **协议支持**:分析Netty如何实现常见网络协议,如TCP、UDP、HTTP/1.x和HTTP/2等。 - **性能优化**:探讨Netty在性能优化方面的策略,如缓冲区管理和零拷贝技术的应用。 - **实战案例**:提供实际的项目示例,演示...

    vertx-cluster-demo:基于Hazelcast的群集管理器的Vert.x示例

    4. **Vert.x集群**: 在Vert.x集群中,每个节点都可以发送和接收事件到其他节点,这使得可以构建高度可扩展的微服务架构。Vert.x的集群机制允许在多个节点之间分散负载,当一个节点失败时,其他节点可以接管其任务...

Global site tag (gtag.js) - Google Analytics