`
sasion
  • 浏览: 34633 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

高性能的HTTP引擎—— Grizzly(二) Grizzly简介

阅读更多
                             Grizzly简介
正如前文所说,用Java技术来编写一个扩展性能很高的服务器软件是件很困难的事情。Java虚拟机的线程管理机制使得纯Java写的HTTP引擎很难响应成千上万的并发用户。正如Tomcat一样,在并发用户数不是很高的情况下能够获得很高的吞吐量,但是在高并发的情况下性能下降很快,变得不太稳定。

在JDK 1.4推出NIO之后,有很多基于NIO的框架出现,利用NIO的新特性,来编写高性能的HTTP引擎。其中以Jean-Francois Arcand的Grizzly最为引人瞩目。Grizzly最早被用于Sun Java System Application Server, Platform Edition 8.1。随后成为开源软件GlassFish的一部分。在今后,Sun Java System Application Server 9.x的Platform Edition和Enterprise Edition都会使用Grizzly作为HTTP引擎。

17.2.1  Grizzly的基本架构

图17-1描述了Grizzly的基本架构。



图17-1  Grizzly的基本架构

Grizzly的基本架构主要包含以下几个方面:Pipeline、SelectorThread和Task。下面分别加以介绍。

1. Pipeline
在com.sun.enterprise.web.connector.grizzly包下,有许多与Pipeline相关的类,例如Pipeline、KeepAlivePipeline、ThreadPoolExecutorPipeline、LinkedListPipeline等。Pipeline是个不太好理解的词汇,其实把这些类叫做ThreadPoolWrapper可能更加合适和容易理解。只要熟悉服务器端的软件,对Thread Pool(线程池)一定不会陌生。线程比起进程来说,消耗的资源要少,共享数据更加简单。因此,现在大多数服务器软件(特别是HTTP服务器)都会采用多线程模式。但是线程的创建和关闭仍然是比较慢的系统服务,聪明的服务器软件设计者会在系统启动的时候,预先创建一些线程,并且将这些线程管理起来,在系统正常运行的时候服务于客户的请求。通过这样的手段,线程不需要在使用的时候临时创建,大大提高了软件的运行速度和效率。对这种线程的管理方法叫做线程池。线程池中的线程需要互相协作,有序地执行客户的请求。一般用于同步线程的结构叫任务队列。客户的请求根据先后顺序被放到了任务队列中,线程池中空闲的线程会从任务队列中获得任务并执行。

Grizzly中的Pipeline实际上封装了一个Thread Pool(线程池)和一个任务队列。Pipeline的主要目的是封装了一个统一的接口,可以让Grizzly根据配置文件任意选择不同算法的线程池,来获得不同的特点和性能。在Grizzly中已经实现了好几种线程池。其中有ThreadPoolExecutorPipeline(基于java.util.concurrent.ThreadPoolExecutor来实现的线程池),还有LinkedListPipeline(使用简单的linklist数据结构管理的线程池)。在早期的Grizzly中还会看到一些其他的实现。经过测试以后,淘汰了一些性能不好的算法,目前只剩下这两种Pipeline了。事实上在大并发用户的测试中,LinkedListPipeline的性能是最好的,因此被设置为默认的选择。在以后的版本中,ThreadPoolExecutorPipeline也可能会消失,只保留性能最好的算法是明智的选择。但是现在还存在两种算法,其主要原因是java.util.concurrent.ThreadPoolExecutor的名声太响,所有的文章和测试都曾经证明过它的高性能。就连Grizzly的作者本身都不相信LinkedListPipeline的性能要比ThreadPoolExecutorPipeline好,只不过当前的测试结果事实如此。因此该作者自己也说,一旦有证据证明ThreadPoolExecutorPipeline的性能又重新超过LinkedListPipeline,他会立即将默认的设置指向ThreadPoolExecutorPipeline。

KeepAlivePipeline是一个特例,它并不是用来执行特定任务的,而是用来维护HTTP协议中的持久连接的状态,例如维护最大的持久连接数,持久连接的timeout时间等。另外,异步的socketChannel中缺少一个类似socket.setSoTimeout的函数,这个函数在保证服务器软件的可靠性和安全性(抗DOS攻击)上,具有重要的作用。Grizzly是用KeepAlivePipeline类来模拟socket.setSoTimeout的作用。

2. SelectorThread
这是Grizzly的主要入口类,位于com.sun.enterprise.web.connector.grizzly的包下。在SelectorThread中,SocketChannel和Selector被创建并被初始化。当网络有请求进来的时候,Selector会根据不同的请求类型和NIO的不同事件进行不同的处理。

当NIO的事件为OP_READ的时候,表明是原有的连接中有新的请求数据传过来了。这类请求属于ReadTask,应该交给负责处理ReadTask的处理器来处理。ReadTask有自己的Pipeline(也就是线程池)来处理,这样就不会占用主线程来处理Read的请求。

当NIO的事件为OP_ACCEPT的时候,表明是有新的请求进来了,这类请求属于AcceptTask,应该交给负责处理AcceptTask的处理器来处理。在老版本的GlassFish中,AcceptTask也有自己的Pipeline来处理,这样就让AcceptTask在主线程以外的线程中执行。但是经过多次性能测试和比较,发现当AcceptTask在主线程(SelectorThread)中执行的时候,性能最好。因此,在读最新的Grizzly源代码的时候,会发现图17-1中的AcceptPipeline根本不存在,因为AcceptTask已经由SelectThread类中HandleAccept函数来执行了。

当ReadTask执行完以后,表明整个请求的数据已经完全接收到,就可以进行请求处理了,请求处理属于ProcessTask,交给负责处理ProcessTask的处理器来处理。ProcessTask有自己的Pipeline(也就是线程池)来处理,这样就不会占用主线程来处理请求。

3. Task
在Grizzly的框架中包含下面几种任务。

(1)   AcceptTask:用于响应新的连接请求。前面已经说过,这个任务的类事实上已经不存在,没有单独抽象出来。因为处理Accept已经成为SelectThread内部的一部分了。

(2)   ProcessTask:用于处理并且响应请求。这个任务通常是对请求的数据进行解析,解析完后再将请求传递给其他服务的容器(如Servlet容器)进行真正的业务处理。

(3)   ReadTask:用于SocketChannel最初的读取操作。由于NIO是非阻塞的操作,最初的读取往往不能获得全部的请求数据,这时候,ReakTask会将任务委托给StreamAlgorithm,根据不同实现,用不同的方法将剩下的请求数据获取。

在com.sun.enterprise.web.connector.grizzly.algorithms的包下,Grizzly默认实现了4个算法:

l   ContentLengthAlgorithm

l   SeekHeaderAlgorithm

l   StateMachineAlgorithm

l   NoParsingAlgorithm

前3个算法主要是围绕HTTP请求中的Content-length字段来进行解析。只要能读到这个字段的值,那么我们就可以预先判断整个请求的长度,从而确定什么时候完成请求读取,接着进行请求处理了。第4个算法是对请求数据根本不进行预处理,假设所有的数据都读进来了。如果最后发现请求数据读得不完全,再交给请求处理任务(ProcessTask)来负责将剩下的内容读取过来。

17.2.2  源码阅读指南

根据图17-1的结构,结合Grizzly的源代码,可以看到Grizzly的大致脉络。

SelectorThread是个入口,根据Grizzly所在的不同环境,启动的方法有所不同。如果Grizzly作为单独可运行的应用(Grizzly可以从GlassFish中独立出来),在com.sun.enterprise. web.connector.grizzly.standalone包下的Main类是这样使用SelectorThread的:

【例17.4】单独运行的Grizzly对SelectorThread的调用:

private static void start(String args[]) throws Exception {

...

    SelectorThread selectorThread = null;

    String selectorThreadClassname = System.getProperty(SELECTOR_THREAD);

    if (selectorThreadClassname != null){

        selectorThread = loadInstance(selectorThreadClassname);

    } else {

        selectorThread = new SelectorThread();

    }

    selectorThread.setPort(port);

    StaticResourcesAdapter adapter = new StaticResourcesAdapter();

    adapter.setRootFolder(folder);      

    selectorThread.setAdapter(adapter);

    selectorThread.setDisplayConfiguration(true);

    selectorThread.initEndpoint();

    selectorThread.startEndpoint();

}

如果Grizzly是在GlassFish中,它作为服务线程,run()方法是整个线程启动的钥匙。从源码中很容易看出在run()方法中调用了startEndpoint()方法,startEndpoint()在做好一些准备工作之后,调用了startListener()。startListener()便进入了主线程的循环之中。在循环中只有一个方法,那就是doSelect()方法。

在doSelect()中,可以很清楚地看到NIO的框架结构。

【例17.5】SelectorThread中的doSelect():

selectorState = selector.select(selectorTimeout);

...

readyKeys = selector.selectedKeys();

iterator = readyKeys.iterator();

while (iterator.hasNext()) {

    key = iterator.next();

    iterator.remove();

    if (key.isValid()) {

        handleConnection(key);

    } else {

        cancelKey(key);

    }

}

与大多数NIO的架构一样,先是调用selector.select(selectorTimeout),看看当前的频道有没有数据准备好了。如果有的话,通过selector.selectedKeys()将准备好的这些频道的SelectionKey取到。对这些频道的处理就交给handleConnection(key)函数了。

【例17.6】SelectorThread中的handleConnection:

protected void handleConnection(SelectionKey key) throws

IOException,InterruptedException

{

    Task task = null;

    if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT){

        handleAccept(key);

        return;

    } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ){

        task = handleRead(key);

    }

if (((SocketChannel)key.channel()).isOpen()) {

        task.execute();

} else {

        cancelKey(key);

}

}

handleConnection函数很短,但是有一些重要的特点需要指出来。handleConnection的主要功能是区分那些已经准备好的频道,看看它们是属于新的连接(OP_ACCEPT)还是有新的请求数据(OP_READ)。

如果是OP_ACCEPT,那么就调用函数handleAccept(key)。这个函数会在当前的线程内执行,主要的功能就是根据新来的连接创建新的频道,再将这个频道注册到Selector中。如果是OP_READ,那么就调用函数handleRead(key)。这个函数返回了一个Task。通过task.execute()将这个任务的实际运行交给Pipeline中的线程池来执行。换句话说,对新的请求数据的处理是在另外的线程中来处理的,而不是当前的线程。

事实上,在早期的Grizzly的版本中,对OP_ACCEPT的处理与OP_READ一样,也是有单独的任务(AcceptTask)和单独的线程来执行。但是经过性能测试,证明当对OP_ACCEPT的处理在主线程的时候性能最好。因此就取消了AcceptTask在单独线程中的处理,演化为当前的模型。

再随后的工作主要就交给ReadTask和ProcessTask去做了。这里不作详细的介绍。
分享到:
评论
1 楼 cnliuxj 2008-04-30  
很好,受益匪浅

相关推荐

    grizzly-utils-1.9.18-q.zip

    而“animation4j”这个名字暗示了它可能基于Java语言,与Grizzly框架有关,Grizzly是一个轻量级的Java服务器端框架,常用于构建高性能的网络应用。 在“animation4j”中,我们可以预见到它会提供一套完整的动画管理...

    grizzly-portunif-2.3-rc3.zip

    Grizzly通常指的是一个高性能、轻量级的Java网络应用框架,而PortUnif可能是它的一个组件,可能涉及到网络端口统一或者代理相关的功能。然而,描述中并未直接提到Grizzly或PortUnif,而是提到了“bencode.zip”和...

    fish-letter:鱼书——一款开源通信框架

    1. **高性能**:通过优化的I/O模型和高效的内存管理,鱼书能够在高并发环境下保持良好的性能,降低延迟,提高吞吐量。 2. **易用性**:框架的API设计简洁明了,使得开发者能够快速上手,减少学习成本。同时,丰富的...

    openstack quantum安装文档

    这个标签指出了文档的主题——OpenStack Quantum,即 OpenStack 中用于管理网络资源的组件。 #### 正文内容概览及详细解析 **1. 概述** - **什么是 OpenStack Networking?** - OpenStack Networking(现更名为 ...

    SNS单模无芯光纤仿真与传感器结构特性分析——基于Rsoft beamprop模块

    内容概要:本文主要探讨了SNS单模无芯光纤的仿真分析及其在通信和传感领域的应用潜力。首先介绍了模间干涉仿真的重要性,利用Rsoft beamprop模块模拟不同模式光在光纤中的传播情况,进而分析光纤的传输性能和模式特性。接着讨论了光纤传输特性的仿真,包括损耗、色散和模式耦合等参数的评估。随后,文章分析了光纤的结构特性,如折射率分布、包层和纤芯直径对性能的影响,并探讨了镀膜技术对光纤性能的提升作用。最后,进行了变形仿真分析,研究外部因素导致的光纤变形对其性能的影响。通过这些分析,为优化光纤设计提供了理论依据。 适合人群:从事光纤通信、光学工程及相关领域的研究人员和技术人员。 使用场景及目标:适用于需要深入了解SNS单模无芯光纤特性和优化设计的研究项目,旨在提高光纤性能并拓展其应用场景。 其他说明:本文不仅提供了详细的仿真方法和技术细节,还对未来的发展方向进行了展望,强调了SNS单模无芯光纤在未来通信和传感领域的重要地位。

    发那科USM通讯程序socket-rece

    发那科USM通讯程序socket-set

    嵌入式八股文面试题库资料知识宝典-WIFI.zip

    嵌入式八股文面试题库资料知识宝典-WIFI.zip

    JS+HTML源码与image

    源码与image

    物流行业车辆路径优化:基于遗传算法和其他优化算法的MATLAB实现及应用

    内容概要:本文详细探讨了物流行业中路径规划与车辆路径优化(VRP)的问题,特别是针对冷链物流、带时间窗的车辆路径优化(VRPTW)、考虑充电桩的车辆路径优化(EVRP)以及多配送中心情况下的路径优化。文中不仅介绍了遗传算法、蚁群算法、粒子群算法等多种优化算法的理论背景,还提供了完整的MATLAB代码及注释,帮助读者理解这些算法的具体实现。此外,文章还讨论了如何通过MATLAB处理大量数据和复杂计算,以得出最优的路径方案。 适合人群:从事物流行业的研究人员和技术人员,尤其是对路径优化感兴趣的开发者和工程师。 使用场景及目标:适用于需要优化车辆路径的企业和个人,旨在提高配送效率、降低成本、确保按时交付货物。通过学习本文提供的算法和代码,读者可以在实际工作中应用这些优化方法,提升物流系统的性能。 其他说明:为了更好地理解和应用这些算法,建议读者参考相关文献和教程进行深入学习。同时,实际应用中还需根据具体情况进行参数调整和优化。

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_8.doc.zip

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_8.doc.zip

    基于灰狼优化算法的城市路径规划Matlab实现——解决TSP问题

    内容概要:本文介绍了基于灰狼优化算法(GWO)的城市路径规划优化问题(TSP),并通过Matlab实现了该算法。文章详细解释了GWO算法的工作原理,包括寻找猎物、围捕猎物和攻击猎物三个阶段,并提供了具体的代码示例。通过不断迭代优化路径,最终得到最优的城市路径规划方案。与传统TSP求解方法相比,GWO算法具有更好的全局搜索能力和较快的收敛速度,适用于复杂的城市环境。尽管如此,算法在面对大量城市节点时仍面临运算时间和参数设置的挑战。 适合人群:对路径规划、优化算法感兴趣的科研人员、学生以及从事交通规划的专业人士。 使用场景及目标:①研究和开发高效的路径规划算法;②优化城市交通系统,提升出行效率;③探索人工智能在交通领域的应用。 其他说明:文中提到的代码可以作为学习和研究的基础,但实际应用中需要根据具体情况调整算法参数和优化策略。

    嵌入式八股文面试题库资料知识宝典-Intel3.zip

    嵌入式八股文面试题库资料知识宝典-Intel3.zip

    嵌入式八股文面试题库资料知识宝典-2019京东C++.zip

    嵌入式八股文面试题库资料知识宝典-2019京东C++.zip

    嵌入式八股文面试题库资料知识宝典-北京光桥科技有限公司面试题.zip

    嵌入式八股文面试题库资料知识宝典-北京光桥科技有限公司面试题.zip

    物理学领域十字形声子晶体的能带与传输特性研究及应用

    内容概要:本文详细探讨了十字形声子晶体的能带结构和传输特性。首先介绍了声子晶体作为新型周期性结构在物理学和工程学中的重要地位,特别是十字形声子晶体的独特结构特点。接着从散射体的形状、大小、排列周期等方面分析了其对能带结构的影响,并通过理论计算和仿真获得了能带图。随后讨论了十字形声子晶体的传输特性,即它对声波的调控能力,包括传播速度、模式和能量分布的变化。最后通过大量实验和仿真验证了理论分析的正确性,并得出结论指出散射体的材料、形状和排列方式对其性能有重大影响。 适合人群:从事物理学、材料科学、声学等相关领域的研究人员和技术人员。 使用场景及目标:适用于希望深入了解声子晶体尤其是十字形声子晶体能带与传输特性的科研工作者,旨在为相关领域的创新和发展提供理论支持和技术指导。 其他说明:文中还对未来的研究方向进行了展望,强调了声子晶体在未来多个领域的潜在应用价值。

    嵌入式系统开发_USB主机控制器_Arduino兼容开源硬件_基于Mega32U4和MAX3421E芯片的USB设备扩展开发板_支持多种USB外设接入与控制的通用型嵌入式开发平台_.zip

    嵌入式系统开发_USB主机控制器_Arduino兼容开源硬件_基于Mega32U4和MAX3421E芯片的USB设备扩展开发板_支持多种USB外设接入与控制的通用型嵌入式开发平台_

    e2b8a-main.zip

    e2b8a-main.zip

    少儿编程scratch项目源代码文件案例素材-火柴人跑酷(2).zip

    少儿编程scratch项目源代码文件案例素材-火柴人跑酷(2).zip

    【HarmonyOS分布式技术】远程启动子系统详解:跨设备无缝启动与智能协同的应用场景及未来展望

    内容概要:本文详细介绍了HarmonyOS分布式远程启动子系统,该系统作为HarmonyOS的重要组成部分,旨在打破设备间的界限,实现跨设备无缝启动、智能设备选择和数据同步与连续性等功能。通过分布式软总线和分布式数据管理技术,它能够快速、稳定地实现设备间的通信和数据同步,为用户提供便捷的操作体验。文章还探讨了该系统在智能家居、智能办公和教育等领域的应用场景,展示了其在提升效率和用户体验方面的巨大潜力。最后,文章展望了该系统的未来发展,强调其在技术优化和应用场景拓展上的无限可能性。 适合人群:对HarmonyOS及其分布式技术感兴趣的用户、开发者和行业从业者。 使用场景及目标:①理解HarmonyOS分布式远程启动子系统的工作原理和技术细节;②探索该系统在智能家居、智能办公和教育等领域的具体应用场景;③了解该系统为开发者提供的开发优势和实践要点。 其他说明:本文不仅介绍了HarmonyOS分布式远程启动子系统的核心技术和应用场景,还展望了其未来的发展方向。通过阅读本文,用户可以全面了解该系统如何通过技术创新提升设备间的协同能力和用户体验,为智能生活带来新的变革。

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_1.zip

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_1.zip

Global site tag (gtag.js) - Google Analytics