Netty源码分析 之 实现原理

开门见山,在此我就不介绍Netty,关于Neety的介绍、用法我在此推荐一篇文章http://www.kafka0102.com/2010/06/167.html,关于Java NIO网络编程的知识请Google。

 

Netty版本:3.6.6

 

个人觉得Netty之所以高性能主要是因为它的多路I/O复用模型和零拷贝的Buffer。

Netty中有两大核心组件ChannelFactory与ChannelPipeline,可以说Netty的整个架构的核心都是靠这两大组件支撑起来的。

 

Netty的网络模型(ChannelFactory)

 


ChannelFactory有两组线程池BossPoolWorkerPoolBossPool相对上图的mainReactor负责接受连接请求,workerPool对应上图的SubReactorThreadPool部分,用于处理自身任务队列、读、写等操作。

BossPool工作线程接受到连接后,将此连接交给workerPoolworkerPool监听并处理此连接的读写事件.

下面看一下Netty的网络模型实现原理

ChannelFactory接口

它负责创建Channel

 

NioServerSocketChannelFactory

实现自ChannelFactory接口,服务器端的Channel工厂

 

NioClientSocketChannelFactory

实现自ChannelFactory接口,客户端的Channel工厂

这两个实现类中都维护了3个对象bossPoolworkerPoolsink;

sink:则对应PipeLine设计模式(下面会了解到)中的sink部分;

 

下面是ChannelFactory的基本原理图(有些类,有些方法看不懂没事,源码分析的时候会了解到)

 

Thread Pipeline设计模式

 

关于此设计模式的思想请参看此PPThttp://febird.googlecode.com/svn-history/r515/trunk/febird/doc/multi_thread_pipeline_cn.pptx

这个PPT讲得可能有点抽象,我举个包子解释一下:

Pipeline可以看成是生产车间的一条生产流水线,原材料(数据)经过流水线中的每一道工序加工(也就是Handler)最终成为一个产品,每道工序由不同的人(Thread)干,有的工序复杂做得比较慢,有的工序简单做得比较快,但是一个产品必需等到所有工序都加工完后才能进行组装出厂(sink所干的事)。

 

WorkThreadPool:有了生产线流水线那谁来负责生产呢?工人。如果把工人看成是一个Thread那么一个生产车间里的所有工人组成的集合可以看成是ThreadPool。正常情况下,一个工人往往会被分配很多的原材料(数据),但一个工人每次只能加工一个原材料(假设是这样),因此必需要有一个池子(任务排队)来保证工人们正常完成工作,工人的工资一般与自己加工的产品量挂钩,如果大家都从这个池子里拿原材料加工将很有可能会导致冲突(线程同步导致的阻塞),因此厂里给每个工人按月给定一定的数量的任务(WorkThread有了自己的队列),这样每个工人各自完成各自的任务,几乎不会有竞争。

ChannelPipeline的默认实现类是DefaultChannelPipeline,各个被注册到Pipeline中的ChanelHandler都是在同一个工作线程中执行的,不会被拆分到多个线程中去,DefaultChannelPipeline中维护的是一个单向前后节点相连的链表的首尾指针(head,tail),此链表的数据结构如图:

 

                                                          (DefaultChanelPipeline)

 

 

当底层NIO触发“读”事件的时候将从head节点开始执行如下动作:

1、判断当前节点的Handler是否实现了ChannelUpstreamHandler接口

             a)如果是则执行其handleUpstream(ctx, e)

             b)否则继续向查找next直到为next为null

 

当代码调用channel.write方法后将从tail节点开始执行如下动作:

1、判断当前节点的Handler是否实现了ChannelDownstreamHandler接口

             a)如果是则执行其handleDownstream(ctx, e)

             b)否则继续查找prev直到为prev为null

             c)当上面两种情况在执行的时候,如果当前节点的prev为null的时候则执行此Pipeline中sink对象的eventSunk方法做关闭、绑定、链接、写数据等操作

 如图

 

 从图中可以看出底层NIO触发read事件将触发PipelineUpstream直到最后的Hhandler处理完成(这里通常做解码操作)后丢弃;当用户代码调用Channelwrite方法后将触发PipelineDownStream直到最前面的Handler处理完后(这里通常做编码操作)再执行底层Socketwrite操作。

自定义的ChannelHandler可以控制是否继续执行后续的handler。这点很像Spring中的ReflectiveMethodInvocation

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty5.0 架构剖析和码解读 作者:李林锋 版权所有 email neu_lilinfeng@ © Netty5.0 架构剖析和码解读1 1. 概述2 1.1. JAVA 的IO演进2 1.1.1. 传统BIO通信的弊端2 1.1.2. Linux 的网络IO模型简介4 1.1.3. IO复用技术介绍7 1.1.4. JAVA的异步IO8 1.1.5. 业界主流的NIO框架介绍10 2.NIO入门10 2.1. NIO服务端10 2.2. NIO客户端13 3.Netty分析16 3.1. 服务端创建16 3.1.1. 服务端启动辅助类ServerBootstrap16 3.1.2. NioServerSocketChannel 的注册21 3.1.3. 新的客户端接入25 3.2. 客户端创建28 3.2.1. 客户端连接辅助类Bootstrap28 3.2.2. 服务端返回ACK应答,客户端连接成功32 3.3. 读操作33 3.3.1. 异步读取消息33 3.4. 写操作39 3.4.1. 异步消息发送39 3.4.2. Flush操作42 4.Netty架构50 4.1. 逻辑架构50 5. 附录51 5.1. 作者简介51 5.2. 使用声明51 1. 概述 1.1.JAVA 的IO演进 1.1.1. 传统BIO通信的弊端 在JDK 1.4推出JAVANIO1.0之前,基于JAVA 的所有Socket通信都采用 BIO 了同步阻塞模式( ),这种一请求一应答的通信模型简化了上层的应用开发, 但是在可靠性和性能方面存在巨大的弊端。所以,在很长一段时间,大型的应 C C++ 用服务器都采用 或者 开发。当并发访问量增大、响应时间延迟变大后, 采用JAVABIO作为服务端的软件只有通过硬件不断的扩容来满足访问量的激 增,它大大增加了企业的成本,随着集群的膨胀,系统的可维护性也面临巨大 的挑战,解决这个问题已经刻不容缓。 首先,我们通过下面这幅图来看下采用BIO 的服务端通信模型:采用BIO 通信模型的 1connect NewThread1 WebBrowse 2connect 2handle(Req) WebBrowse 3connect Acceptor NewThread2 WebBrowse WebBrowse 4connect NewThread3 3sendResponsetopeer NewThread4 图1.1.1-1 BIO通信模型图 服务端,通常由一个独立的Accepto 线程负责监听客户端的连接,接收到客户 端连接之后为客户端连接创建一个新的线程处理请求消息

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值