官网定义: 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,发送出去。

Netty in Twitter:

写Netty的同学在twitter工作,twitter的新搜索架构Blender就是基于Netty的,如果您能FQ,可以访问这里,否则中文在这里,英文在这里,来了解Blender的架构。

Netty4.x分析的更多相关文章

  1. Netty4.x分析(转)

    官网定义: netty是一个异步.事件驱动的网络应用框架,用于快速开发可维护的.高性能的服务端和客户端程序. 原理分析 Architecture Overview 网络模型:netty采用了React ...

  2. 【Netty学习】 ChannelInitializer 学习

    ChannelInitializer在Netty中是一个很重要的东西.也是4.x版本中用户接触比较多的一个类 它本身是继承ChannelInboundHandlerAdapter的.实现Channel ...

  3. netty4.0.x源码分析—bootstrap

    Bootstrap的意思就是引导,辅助的意思,在编写服务端或客户端程序时,我们都需要先new一个bootstrap,然后基于这个bootstrap调用函数,添加eventloop和handler,可见 ...

  4. [netty4][netty-transpot]Channel体系分析

    Channel体系分析 接口与类结构体系 -- [I]AttributeMap, ChannelOutboundInvoker, Comparable -- [I]AttributeMap ---- ...

  5. [netty4][netty-common]Future与Promise分析

    接口与类结构体系 -- [I]java.util.concurrent.Future<V> ---- [I]io.netty.util.concurrent.Future<V> ...

  6. gRPC源码分析0-导读

    gRPC是Google开源的新一代RPC框架,官网是http://www.grpc.io.正式发布于2016年8月,技术栈非常的新,基于HTTP/2,netty4.1,proto3.虽然目前在工程化方 ...

  7. 消息中间件MetaQ高性能原因分析-转自阿里中间件

    简介 MetaQ是一款高性能的消息中间件,经过几年的发展,已经非常成熟稳定,历经多年双11的零点峰值压测,表现堪称完美. MetaQ当前最新最稳定的稳本是3.x系统,MetaQ 3.x重新设计和实现, ...

  8. Netty4 中的内存管理

    在Netty4中引入了新的内存管理机制极大地提升其性能,本文将对该内在管理机制进行剖析. 这里有篇文章讲述了在推特(Twitter)内部 使用Netty的状况以及Netty4所带来的性能收益. 在分析 ...

  9. netty源码分析

    1.Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.也就是说,Netty 是一个基于N ...

随机推荐

  1. java读取照片信息 获取照片拍摄时的经纬度

    项目结构 源码:ImageInfo.zip 第一步:添加需要的架包metadate-extractor.jar 架包下载地址:https://code.google.com/p/metadata-ex ...

  2. angular依赖注入的理解(转)

    使用过java进行开发的人肯定知道大名鼎鼎的spring框架,对于spring的IOC肯定也有所了解,通过配置文件定义好bean之后,如果需要使用这些bean,不需要自己去实例化,而是跟spring这 ...

  3. <四>面向对象分析之UML核心元素之用例

    一:基本概念        --->用例定义了一组用例实例,其中每个实例都是系统所执行一系列操作,这些操作生成特定主角可以观测的值.        --->所谓用例,就是一件事情,要完成这 ...

  4. iwpriv工具通过ioctl动态获取相应无线网卡驱动的private_args所有扩展参数

    iwpriv工具通过ioctl动态获取相应无线网卡驱动的private_args所有扩展参数 iwpriv是处理下面的wlan_private_args的所有扩展命令,iwpriv的实现上,是这样的, ...

  5. java jvm学习笔记十三(jvm基本结构)

    欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完 ...

  6. 程序破解之 API HOOK技术 z

    API HOOK,就是截获API调用的技术,在程序对一个API调用之前先执行你的函数,然后根据你的需要可以执行缺省的API调用或者进行其他处理,假设如果想截获一个进程对网络的访问,一般是几个socke ...

  7. C++ primer里的template用法

    来源:http://c.chinaitlab.com/cc/ccjq/200806/752604_2.html --  template 的用法    在程序设计当中经常会出现使用同种数据结构的不同实 ...

  8. Chromuim开发机配置

    一个出色的程序员需要一台给力的电脑. 之前使用ThinkPad R400笔记本编译Chromium,确实太痛苦了,第一次编译未使用SSD,超过了24小时都没有编译完.后来断断续续折腾了将近一个月才编译 ...

  9. Config配置文件详解

    (默认的配置设置)以下所有的代码都应该位于 <configuration> <system.web> 和 </system.web> </configurat ...

  10. LeetCode题解——3Sum

    题目: 给定一个数组,找出其中和为0的所有3个数的组合.每个组合的3个数都是非递降的. 解法: 先排序再遍历,设置3个指针,第一个依次遍历,第二三个在第一个指针后面的部分里,左右夹逼查找和为第一个数的 ...