一切从ServerBootstrap开始

ServerBootstrap负责初始话netty服务器,并且开始监听端口的socket请求。

bootstrap bootstrap =newServerBootstrap(

newNioServerSocketChannelFactory(
Executors.newCachedThreadPool(),//boss线程池
Executors.newCachedThreadPool()//worker线程池
)
);
bootstrap.setPipelineFactory(newHttpChannelPipelineFactory());
bootstrap.setOption("child.tcpNoDelay",true);
bootstrap.setOption("child.keepAlive",true);
bootstrap.bind(newInetSocketAddress(httpPort));//端口开始监听
ServerBootstrap用一个ServerSocketChannelFactory 来实例化。ServerSocketChannelFactory 有两种选择,一种是NioServerSocketChannelFactory,一种是OioServerSocketChannelFactory。前者使用NIO,后则使用普通的阻塞式IO。它们都需要两个线程池实例作为参数来初始化,一个是boss线程池,一个是worker线程池。

ServerBootstrap.bind(int)负责绑定端口,当这个方法执行后,ServerBootstrap就可以接受指定端口上的socket连接了。一个ServerBootstrap可以绑定多个端口。

boss线程和worker线程

可以这么说,ServerBootstrap监听的一个端口对应一个boss线程,它们一一对应。比如你需要netty监听80和443端口,那么就会有两个boss线程分别负责处理来自两个端口的socket请求。在boss线程接受了socket连接求后,会产生一个channel(一个打开的socket对应一个打开的channel),并把这个channel交给ServerBootstrap初始化时指定的ServerSocketChannelFactory来处理,boss线程则继续处理socket的请求。

ServerSocketChannelFactory则会从worker线程池中找出一个worker线程来继续处理这个请求。
如果是OioServerSocketChannelFactory的话,那个这个channel上所有的socket消息消息,从开始到channel(socket)关闭,都只由这个特定的worker来处理,也就是说一个打开的socket对应一个指定的worker线程,这个worker线程在socket没有关闭的情况下,也只能为这个socket处理消息,无法服务器他socket。

如果是NioServerSocketChannelFactory的话则不然,每个worker可以服务不同的socket或者说channel,worker线程和channel不再有一一对应的关系。
显然,NioServerSocketChannelFactory只需要少量活动的worker线程及能很好的处理众多的channel,而OioServerSocketChannelFactory则需要与打开channel等量的worker线程来服务。

线程是一种资源,所以当netty服务器需要处理长连接的时候,最好选择NioServerSocketChannelFactory,这样可以避免创建大量的worker线程。在用作http服务器的时候,也最好选择NioServerSocketChannelFactory,因为现代浏览器都会使用http keepalive功能(可以让浏览器的不同http请求共享一个信道),这也是一种长连接。

worker线程的生命周期(life circle)

当某个channel有消息到达或者有消息需要写入socket的时候,worker线程就会从线程池中取出一个。在worker线程中,消息会经过设定好的ChannelPipeline处理。ChannelPipeline就是一堆有顺序的filter,它分为两部分:UpstreamHandler和DownStreamHandler。本文着重介绍netty的线程模型,所以关于pipeline的内容从简说明。

客户端送入的消息会首先由许多UpstreamHandler依次处理,处理得到的数据送入应用的业务逻辑handler,通常用SimpleChannelUpstreamHandler来实现这一部分。

publicclassSimpleChannelUpstreamHandler{

publicvoid messageReceived(ChannelHandlerContext c,MessageEvent e)throwsException{
//业务逻辑开始掺入
}
}
对于Nio当messageReceived()方法执行后,如果没有产生异常,worker线程就执行完毕了,它会被线程池回收。业务逻辑hanlder会通过一些方法,把返回的数据交给指定好顺序的DownStreamHandler处理,处理后的数据如果需要,会被写入channel,进而通过绑定的socket发送给客户端。这个过程是由另外一个线程池中的worker线程来完成的。

对于Oio来说,从始到终,都是由一个指定的worker来处理。

减少worker线程的处理占用时间

worker线程是由netty内部管理,统一调配的一种资源,所以最好应该尽快的把让worker线程执行完毕,返回给线程池回收利用。worker线程的大部分时间消耗在在ChannelPipeline的各种handler中,而在这些handler中,一般是负责应用程序业务逻辑掺入的那个handler最占时间,它通常是排在最后的UpstreamHandler。所以通过把这部分处理内容交给另外一个线程来处理,可以有效的减少worker线程的周期循环时间。一般有两种方法:

messageReceived()方法中开启一个新的线程来处理业务逻辑

publicvoid messageReceived(ChannelHandlerContext ctx,MessageEvent e)throwsException{

...
newThread(...).start();
}

在messageReceived()中开启一个新线程来继续处理业务逻辑,而worker线程在执行完messageReceived()就会结束了。更加优雅的方法是另外构造一个线程池来提交业务逻辑处理任务。

利用netty框架自带的ExecutionHandler

基本使用方法

publicclassDatabaseGatewayPipelineFactoryimplementsChannelPipelineFactory{

 
privatefinalExecutionHandler executionHandler;
 
publicDatabaseGatewayPipelineFactory(ExecutionHandler executionHandler){
this.executionHandler= executionHandler;
}
 
publicChannelPipeline getPipeline(){
returnChannels.pipeline(
newDatabaseGatewayProtocolEncoder(),
newDatabaseGatewayProtocolDecoder(),
executionHandler,// 多个pipeline之间必须共享同一个ExecutionHandler
newDatabaseQueryingHandler());//业务逻辑handler,IO密集
}
}
把共享的ExecutionHandler实例放在业务逻辑handler之前即可,注意ExecutionHandler一定要在不同的pipeline之间共享。它的作用是自动从ExecutionHandler自己管理的一个线程池中拿出一个线程来处理排在它后面的业务逻辑handler。而worker线程在经过ExecutionHandler后就结束了,它会被ChannelFactory的worker线程池所回收。

它的构造方法是ExecutionHandler(Executor executor) ,很显然executor就是ExecutionHandler内部管理的线程池了。netty额外给我们提供了两种线程池:
MemoryAwareThreadPoolExecutor和OrderedMemoryAwareThreadPoolExecutor,它们都在org.jboss.netty.handler.execution 包下。
MemoryAwareThreadPoolExecutor确保jvm不会因为过多的线程而导致内存溢出错误,OrderedMemoryAwareThreadPoolExecutor是前一个线程池的子类,除了保证没有内存溢出之外,还可以保证channel event的处理次序。具体可以查看API文档,上面有详细说明。

Netty服务器线程模型概览的更多相关文章

  1. 面试官:Netty的线程模型可不只是主从多Reactor这么简单

    笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...

  2. Netty IO线程模型学习总结

    Netty框架的 主要线程是IO线程.线程模型的好坏直接决定了系统的吞吐量.并发性和安全性. Netty的线程模型遵循了Reactor的基础线程模型.以下我们先一起看下该模型 Reactor线程模型 ...

  3. Netty Reactor 线程模型笔记

    引用: https://www.cnblogs.com/TomSnail/p/6158249.html https://www.cnblogs.com/heavenhome/articles/6554 ...

  4. netty之==线程模型

    1.1 netty线程模型本质遵循了Reactor的基础线程模型,所以得先介绍Reactor模型  1.2  Reactor模型 无论是C++还是Java编写的网络框架,大多数都是基于Reactor模 ...

  5. netty源码解解析(4.0)-4 线程模型-概览

    netty线程体系概览 netty的高并发能力很大程度上由它的线程模型决定的,netty定义了两种类型的线程: I/O线程: EventLoop, EventLoopGroup.一个EventLoop ...

  6. netty reactor线程模型分析

    netty4线程模型 ServerBootstrap http示例 // Configure the server. EventLoopGroup bossGroup = new EpollEvent ...

  7. Tomcat 7服务器线程模型

    Tomcat 7服务器网络处理主要由NioEndpoint,其处理客户端连接的主要流程如图所示图中Acceptor及Worker分别是以线程池形式存在,Poller是一个单线程.注意,与BIO的实现一 ...

  8. 【Netty源码分析】Reactor线程模型

    1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 时间回到十几年前,那时主流的CPU都还是单核(除了商用高性能的小机),CPU的核心频率是机器最重要的指标之一. 在Java领域当时比 ...

  9. Netty系列之Netty线程模型

    Reference: http://www.infoq.com/cn/articles/netty-threading-model 1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 ...

随机推荐

  1. GIT服务器实现web代码自动部署

    之前在一台vps服务器上面搭建了Git服务器,用来做代码管理,方便团队开发.但是问题也就相应的来了,使用git可以轻松的上传代码,而由于做的是web开发,每次还都得到服务器上把代码手动pull或者复制 ...

  2. java 实现md5加密的三种方式与解密

      java 实现md5加密的三种方式 CreateTime--2018年5月31日15点04分 Author:Marydon 一.解密 说明:截止文章发布,Java没有实现解密,但是已有网站可以免费 ...

  3. 【转载】Java 网络编程

      本文主要是自己在网络编程方面的学习总结,先主要介绍计算机网络方面的相关内容,包括计算机网络基础,OSI参考模型,TCP/IP协议簇,常见的网络协议等等,在此基础上,介绍Java中的网络编程. 一. ...

  4. oracle 拼接字符串的两种方式

      方式一:使用管道符||进行拼接 方式二:使用concat()函数 区别: 方式一可以拼接多个字符串:方式二只能将2个字符串拼接到一起. 写在最后 哪位大佬如若发现文章存在纰漏之处或需要补充更多内容 ...

  5. jqPlot图表插件学习之ajax-json数据加载

    一.准备工作 首先我们需要到官网下载所需的文件: 官网下载(笔者选择的是jquery.jqplot.1.0.8r1250.zip这个版本) 然后读者需要根据自己的情况新建一个项目并且按照如下的方式加载 ...

  6. python之模块cmath

    # -*- coding: utf-8 -*-#python 27#xiaodeng#python之模块cmath #复数的数学函数,如log.tan.sin等函数用法,针对我目前的情况用途较少,暂不 ...

  7. Maven实战——Gradle,构建工具的未来?

    许晓斌-- 四月 05, 2011 Maven面临的挑战 软件行业新旧交替的速度之快往往令人咂舌,不用多少时间,你就会发现曾经大红大紫的技术已经成为了昨日黄花,当然,Maven也不会例外.虽然目前它基 ...

  8. [转]极不和谐的 fork 多线程程序

    极不和谐的 fork 多线程程序 继续前几天的话题.做梦幻西游服务器优化的事情.以往的代码,定期存盘的工作分两个步骤,把 VM 里的动态数据序列化,然后把序列化后的数据写盘.这两个步骤,序列化工作并没 ...

  9. 实现外卖选餐时两级 tableView 联动效果

    最近实现了下饿了么中选餐时两级tableView联动效果,先上效果图,大家感受一下: 下面说下具体实现步骤: 首先分解一下,实现这个需求主要是两点,一是点击左边tableView,同时滚动右边tabl ...

  10. 浅析iOS中的触摸事件

    一.什么是响应者对象? 在 iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为“响应者对象”.UIApplication.UIViewControl ...