首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

Netty Server端代码简略分析

2012-12-04 
Netty Server端代码简单分析Netty源码简单分析:Netty整体架构清晰的分为两部分:1.ChannelFactory:主要负责

Netty Server端代码简单分析
Netty源码简单分析:
Netty整体架构清晰的分为两部分:
1.ChannelFactory:主要负责生产网络通信相关的Channel和ChannelSink实例,NIO Server端一般使用NioServerSocketChannelFactory,用户也可以定制自己的ChannelFactory。
2.ChannelPipelineFactory:主要用来对传输数据的处理,由于对数据的处理属于业务相关,用户应自己实现ChannelPipelineFactory,然后往ChannelPipelineFactory添加自定义的Handler

Netty服务端启动步骤:
代码:

// 构造一个服务端Bootstrap实例,并通过构造方法指定一个ChannelFactory实现// 其中后两个参数分别是BOSS和WORK的线程池Bootstrap serverBootstrap = new ServerBootstrap(        new NioServerSocketChannelFactory(                Executors.newCachedThreadPool(),                 Executors.newCachedThreadPool()));// 注册用户自己实现的ChannelPipelineFactoryserverBootstrap.setPipelineFactory(this.pipelineFactory);// 调用bind等待客户端来连接((ServerBootstrap) serverBootstrap).bind(socketAddress);


Netty提供NIO与BIO两种模式,我们主要关心NIO的模式:
NIO处理方式:
1.Netty用一个BOSS线程去处理客户端的接入,创建Channel
2.从WORK线程池(WORK线程数量默认为cpu cores的2倍)拿出一个WORK线程交给BOSS创建好的Channel实例(Channel实例持有java网络对象)
3.WORK线程进行数据读入(读到ChannelBuffer)
4.接着触发相应的事件传递给ChannelPipeline进行业务处理(ChannelPipeline中包含一系列用户自定义的ChannelHandler组成的链)

有一点要注意的是,执行整个ChannelHandler链这个过程是串行的,如果业务逻辑(比如DB操作)比较耗时,会导致WORK线程长时间被占用得不到释放,最终影响整个服务端的并发处理能力,所以一般我们通过ExecutionHandler线程池来异步处理ChannelHandler调用链,使得WORK线程经过ExecutionHandler时得到释放。
要解决这个问题增加下面代码即可:
ExecutionHandler executionHandler =        new ExecutionHandler(                new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576));public ChannelPipeline getPipeline() {        return Channels.pipeline(                                new DatabaseGatewayProtocolEncoder(),                                new DatabaseGatewayProtocolDecoder(),                                executionHandler, // Must be shared                                new DatabaseQueryingHandler());}


Netty为ExecutionHandler提供了两种可选的线程池模型:
1) MemoryAwareThreadPoolExecutor
通过对线程池内存的使用控制,可控制Executor中待处理任务的上限(超过上限时,后续进来的任务将被阻塞),并可控制单个Channel待处理任务的上限,防止内存溢出错误;
2) OrderedMemoryAwareThreadPoolExecutor
是1)的子类。除了MemoryAwareThreadPoolExecutor 的功能之外,它还可以保证同一Channel中处理的事件流的顺序性,这主要是控制事件在异步处理模式下可能出现的错误的事件顺序,但它并不保证同一Channel中的事件都在一个线程中执行,也没必要保证这个。
我们看下OrderedMemoryAwareThreadPoolExecutor中的注释:

Thread X: --- Channel A (Event A1) --.   .-- Channel B (Event B2) --- Channel B (Event B3) --->
                                                                    \ /
                                                                    X
                                                                    / \
Thread Y: --- Channel B (Event B1) --'   '-- Channel A (Event A2) --- Channel A (Event A3) --->
处理同一个Channel的事件,是串行的方式执行的,但是同一个Channel的多个事件,可能会分布到线程中池中的多个线程去处理,不同的Channel事件可以并发处理,互相并不影响

再来看看MemoryAwareThreadPoolExecutor中的注释
Thread X: --- Channel A (Event 2) --- Channel A (Event 1) --------------------------->
Thread Y: --- Channel A (Event 3) --- Channel B (Event 2) --- Channel B (Event 3) --->
Thread Z: --- Channel B (Event 1) --- Channel B (Event 4) --- Channel A (Event 4) --->
同一个Channel的事件,并不保证处理顺序,可能一个线程先处理了Channel A (Event 3),然后另一个线程才处理Channel A (Event 2),如果业务不要求保证事件的处理顺序,我认为还是尽量使用MemoryAwareThreadPoolExecutor比较好

Netty采用标准的SEDA(Staged Event-Driven Architecture) 架构
SEDA的核心思想是把一个请求处理过程分成几个Stage,不同资源消耗的Stag使用不同数量的线程来处理,Stag间使用事件驱动的异步通信模式。更进一步,在每个Stage中可以动态配置自己的线程数,在超载时降级运行或拒绝服务。

Netty所设计的事件类型,代表了网络交互的各个阶段,每个阶段发生时,会触发相应的事件并交给ChannelPipeline进行处理。事件处理都是通过Channels类中的静态方法调用开始的。

Channels中事件流转静态方法:
1.fireChannelOpen
2.fireChannelBound
3.fireChannelConnected
4.fireMessageReceived
5.fireWriteCompleteLater
6.fireWriteComplete
7.fireChannelInterestChangedLater
8.fireChannelDisconnectedLater
9.fireChannelDisconnected
10.fireChannelUnboundLater
11.fireChannelUnbound
12.fireChannelClosedLater
13.fireChannelClosed
14.fireExceptionCaughtLater
15.fireExceptionCaught
16.fireChildChannelStateChanged


Netty将网络事件分为两种类型:
1.Upstresam:上行,主要是由网络底层反馈给Netty的,比如messageReceived、channelConnected
2.Downstream:下行,框架自己发起的,比如bind、write、connect等

Netty的ChannelHandler 分为3种类型:
1.只处理Upstream事件:实现ChannelUpstreamHandler接口
2.只处理Downstream事件:实现ChannelDownstreamHandler接口
3.同时处理Upstream和Downstream事件:同时实现ChannelUpstreamHandler和ChannelDownstreamHandler接口
ChannelPipeline维持所有ChannelHandler的有序链表,当有Upstresam或Downstream网络事件发生时,调用匹配事件类型的ChannelHandler来处理。ChannelHandler自身可以控制是否要流转到调用链中的下一个ChannelHandler(ctx.sendUpstream(e)或者ctx.sendDownstream(e)),这一样有一个好处,比如业务数据Decoder出现非法数据时不必继续流转到下一个ChannelHandler

下面是我胡乱的画的一个图:




热点排行