【高性能服务器】Tomcat剖析

引言

Tomcat是一个流行的servlet容器,对于开发人员来说整体和容器打交道有必要花一些时间爱你了解其内部结构。本文将从一下几个方面来剖析其内部结构。

  1. 整体结构
  2. 连接器

    1. 初始化过程
    2. 如何处理一个请求
  3. 容器

    1. Session管理
    2. 设计模式
    3. Context
    4. Wrapper

整体结构

首先我们先来看一下Tomcat的整体结构。如下图所示,整个tomcat容器的顶层是server对象,下属多个service。每个service有自己的连接器与容器组合[1]。其中连接器负责处理网络连接,并将包装过的数据流传递给容器。容器最后负责解释servlet,并返回结果。下面我们仔细分析一下各层次的内部结构。

?

图 2.1 tomcat整体结构

?

Server:代表了整个web容器服务,一个server可以包含多个service,并维护service集合,对外提供接口[1]。Server实现了Lifecycle接口,通过start,stop函数管理下属的组件。下面我们来看一些典型的方法,这些方法不仅在server这层中出现,在其下级组件中也频繁出现,所以,有必要好好研究一番。

添加一个service。

Addxxx方法的主要作用是将组件本身和上层组件相连。具体在server中,下层service将自身父对象设为当前server。接下来要判断整个系统是否已经进行过初始化,如果这个方法是在初始化之前调用的,那么不必初始化新加入的service。反之需要主动调用其初始化函数。同理,启动方法也是如此。

Start方法:

Start方法的主要任务是启动组件下属的子组件,至于子组件如何管理启动更下一层的组件,组件本身不加控制。

Initialize方法:

和start方法作用差不多,initialize的主要任务是启动下级组件的初始化工作。

Await方法:

。。。

。。。

Server的主要作用是管理全局组件的启动,初始化以及停止工作。但是和许多组件一样,在完成初期工作后需要进入一个等待状态以节约cup资源,所以需要await方法。Server的await方法是在Bootstrap程序启动并初始化server后,调用server的await方法,使其进入等待状态,等候shutdown命令的到来[2]

上述几个函数在tomcat的其他组件中广泛采用,虽然细节不尽相同,但是整体的功能是一致的,之后不再赘述。

Service:

一个Service的主要功能是管理属于他的连接器和容器,简单的讲,他就是一个连接器和容器的组合。其中连接器可以有多个,以数组的形式存放,在添加新的连接器时需要重新申请空间。这里效率问题需要商讨。

容器对于service来说只能有一个,之所以这么做的原因是分离系统可能遇到需要变化的部分以及其不变的部分。具体来讲,连接器负责处理网络连接,而网络连接可能需要适配多种情况,比如说https与http,ssl与非ssl。所以可能需要不同的连接器处理不同的协议。相反,容器负责解释servlet,后者是针对特定的规范开发的,不会改变。Service同样实现了Lifecycle接口,和server一样他也通过start,stop方法管理下属的组件。

连接器

连接器的主要功能是解析http请求,并将其中的http信息包装成request和response对象,传递给后续的容器处理。这些信息包括http请求头,参数,cookie等内容。这里需要注意的是tomcat Catalina 的connector支持http1.1的长连接功能,长连接是http1.1中的新特性,在原来的1.0协议中浏览器在发起请求后即可与服务器断开连接,网页中图片等资源需要重新请求,会造成不必要的开销。而长连接指的是服务器与浏览器建立连接后除非浏览器主动关闭连接,否则连接将持续保持,这样就可以避免不必要的连接开销。连接器内部通过自制的线程池处理并发请求,但是通过阅读连接器源码我们会发现他本身是单个后台线程的。那么连接器如何处理并发请求呢?

初始化

实际上,在初始化的时候,连接器先产生一个server socket对象,接着启动自身线程,之后会生成一个HttpProcessor线程池,里面所有的线程都处于挂起状态。初始化完成之后,连接器在自身的run方法内将自己阻塞,等待连接到来。

处理请求

当连接到来的时候,连接器只是负责建立连接,然后将这个连接传递给线程池中某一个被唤醒的HttpProcessor对象处理。HttpProcessor对象负责具体的并发工作[2]。Initialize生成一个server socket:

Start方法主要工作:

Run 负责建立连接,并分配processor处理线程:

HttpProcessor的assign方法:

HttpProcessor的run方法:

HttpProcessor的await方法:

Processor通过一个available变量控制线程的休眠与唤醒,简单来说就是设available的初始值为false,那么在processor的run方法中会调用await先将自己挂起。当连接器调用processor的assign方法时,processor获得socket对象,将available置为true,唤醒线程。此时await会失效,执行process方法。在process中主要完成了两件事,第一,解析http请求并将其包装。第二,将包装后的请求传递给容器,并等待其返回。

处理请求的过程

容器

简单来说容器的主要负责传递请求给servlet,并返回响应。下图是容器整体结构,分为四层,从顶之下依次是engine,host,context,wrapper。与tomcat整体的结构相类似,容器之间的管理也是典型的链式结构。例如说Engine的start函数会启动其下属的所有容器。

?

容器的层次

下面我们简单的看一下各层次代表的功能。

  • Engine :表示整个 Catalina Servlet引擎
  • Host :表示一个虚拟主机。
  • Context :表示一个web app应用
  • Wrapper:表示单个servlet

?

容器设计模式(职责链设计模式)

职责链设计模式简单的理解就是一个请求在父对象处理完后,通过调用引用对象的invoke()方法将请求传递给下一级。Tomcat中职责链模式被广泛的应用。从engine到host再到context一直到wrapper都通过一个责任链传递请求,整个容器结构就像一条链子一样被串在一起。

?

?

为了便于维护和扩展,容器间的方法调用统一采用"管道+阀"的模式,也就是上述的职责链设计模式。下面我们具体看个例子:

StandarEngine:

StandardPipeline:

StandardPipelineValveContext:

我们可以看到StandarEngine会调用其管道pipeline中的阀的集合StandardPipelineValveContext,而StandardPipelineValveContext会依次传递请求给其集合内的阀。最后StandardPipelineValveContext会将请求传递给基础阀basic,将请求传递给下层的容器。

Session管理

接下来我们来看一下tomcat的session管理管理功能。总的来说tomcat通过Session管理器来管理建立的Session对象,Session管理器负责创建、更新、销毁Session对象[2]。下面这个代码片段展示了host通过cookie中sessionid来寻找对应的session。

Session管理器的主要方法:

  • createSession() - 创建session实例
  • getMaxInactiveInterval()、setMaxInactiveInterval() – 获取或设置一个到期时间,单位为秒
  • add()、remove() – 从session池中添加、移除session实例

默认的Session存储在服务器的内存中,当服务器被关闭或者内存不足时,需要将session存储到磁盘中,即session的持久化功能。

?

?

在tomcat中,通过store接口规定session的持久化操作规范。

Store接口有两个比较重要的方法

  1. Save()方法用于将制定的Session对象存储到某种持久性存储器中
  2. load()方法会从存储器中依据Session对象的标识符价将该session对象载入到内存中

实现这个接口的有两个重要的类,分别是FileStore,主要负责将Session对象存储到某个文件中。另一个是JDBCStore,负责Session对象通过JDBC存入到数据库中。

Context容器

Context的主要特征

  • Context实例代表一个具体的Web应用程序,具备servlet运行的基本环境。Context最重要的功能就是管理servlet实例。包含一个或多个Wrapper实例,每个Wrapper表示一个具体的servlet定义
  • StandarContext具备url映射功能,即负责寻找url对应的wrapper容器。
  • StandardContext支持运行时重载文件,并且具备热部署的能力。

Context的url映射

Context通过一个map来映射url和相对应的wrapper容器,具体是通过StandarContextMaper的map方法中四条规则匹配获取得到的。

先解析得到要匹配的应用名称:

规则一:完全匹配规则

规则二:前缀匹配规则

规则三:扩展名匹配规则

默认匹配规则

Context的重载机制

重载是指当web.xml或者WEB-INF/classes目录下文件被修改过,tomcat会重新扫描目录。StandardContext定义了reloadable 属性来指明该应用程序是否启用了重载功能[3]。Tomcat4中,StandardContext对象使用另一个线程检查WEB-INF目录中的所有类和JAR文件的时间戳。

Standarcontext的run方法加载实现runnable接口的webappLoader:

webappLoader会在主方法中周期扫描context目录,如果发生变化立即通知reload线程重载整个context。

重载分两步,第一步关闭所有wrapper容器,接着新的wrappeer和老的wrappeer一同启动。

?

4.6 Wrapper容器

Wrapper代表一个servlet,它负责管理一个servlet,包括servlet的装载,初始化,执行,以及资源回收。需要注意的是Wrapper是最底层的容器,它底下没有子容器了。在 servlet 第一次被请求的时候, StandardWrapper 加载 servlet 类。它是动态的加载 servlet[2]

Wrapper的过滤器

过滤器是wrapper的另一个重要机制,web开发者可以设置多个过滤器,每个过滤器中可以装载多个过滤类。通过读取配置文件信息,wrapper会依次加载过滤器,并将请求传递。同时在过滤器的末尾会调用servlet的service方法。

?

StandardWrapper需要将自己的大部分公共方法对servlet程序员隐藏起来。因此,StandardWrapper类将自身包装成门面类StandardWrapperFacade的实例。门面设计模式主要用在一个大的系统中,子系统需要互相通信但又不能将内部过多的信息暴露给其他系统的情况。

?

小结

Tomcat是一个较为复杂的servlet容器,本文只是简单的介绍了其中一些重要的组件及其运行原理,对于内部其他组件,比如说日志系统,类加载器等没有涉及。本文研究的tomcat是4版本的,新的tomcat更为复杂,但是主要的原理应该没有改动。作为一名web开发人员深入了解一下服务器的内部结构是很有必要的。

时间: 2024-09-30 05:12:44

【高性能服务器】Tomcat剖析的相关文章

Tomcat剖析(四):Tomcat默认连接器(2)

Tomcat剖析(四):Tomcat默认连接器(2) 目录: Tomcat剖析(一):一个简单的Web服务器 Tomcat剖析(二):一个简单的Servlet服务器 Tomcat剖析(三):连接器(1) Tomcat剖析(三):连接器(2) Tomcat剖析(四):Tomcat默认连接器(1) Tomcat剖析(四):Tomcat默认连接器(2) 同样的,你需要先下载代码. https://github.com/zebinlin/Tomcat4-src 经过上一节的讲解,你已经理解了请求和响应对

Tomcat剖析(二)

Tomcat剖析(二) 目录: Tomcat剖析(一):一个简单的Web服务器 Tomcat剖析(二):一个简单的Servlet服务器 这一节基于 <深度剖析Tomcat>第二章: 一个简单的Servlet服务器 总结而成. 上一节,我们了解了一个简单的Web服务器的总体处理流程是怎样的:这一节,我们开始搭建一个简单的Servlet容器,也就是增加实现了servlet的简单加载执行,而不仅仅是将文件内容输出到浏览器上.当然,这一节的servlet的实现是最简单的,用来了解整个Servlet的大

Tomcat剖析(三):连接器

Tomcat剖析(三) 目录: Tomcat剖析(一):一个简单的Web服务器 Tomcat剖析(二):一个简单的Servlet服务器 Tomcat剖析(三):连接器 大家都知道Catalina 中有两个主要的模块:连接器和容器.本节将HttpServer2完善为HttpConnect,创建一个更好的请求和响应对象的连接器,不仅仅是简简单单的调用自己的await方法,而是用线程启动. 上一节是使用Reques对象,因为我们不知道请求的类型,而这一节中,如果是HTTP请求,那么Request对象中

【高性能服务器】Nginx剖析

引言 Nginx是一个流行的高性能服务器,官方宣称在压力测试下可以支持5万个并发连接,而且占用内存极低.相比于其他昂贵的硬件负载均衡解决方案,Nginx是开源免费的,可以大大降低成本.本文将从一下几个方面来剖析其内部结构. 特点 进程模型 惊群效应 负载均衡 核心模块 模块分类 事件驱动模块机制 反向代理模块 配置文件 Nginx的特点 Nginx是俄罗斯工程师开发的高性能Web服务器,为了实现高效Nginx全部采用C语言编写,因为底层对不同的操作系统进行了封装,所以Nginx实现了平台无关性.

【MySQL】《高性能MySQL》 学习笔记,第三章,服务器性能剖析

第三章:服务器性能剖析 ? 本章将针对如下三个问题进行解答: ? 如何确认服务器是否达到了性能最佳的状态 ? 找出某条语句为什么执行不够快 ? 诊断被用户描述成"停顿","堆积","卡死"的某些间歇性疑难故障 1.性能优化简介: ? 针对性能问题,1000个DBA,有1000个回答.诸如,"QPS","CPU Load","可扩展性"之类. 原则一:我们将性能定义为完成某件任务所需要的时

Tomcat剖析(五):Tomcat 容器

Tomcat剖析(五):Tomcat 容器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三):连接器(1) 4. Tomcat剖析(三):连接器(2) 5. Tomcat剖析(四):Tomcat默认连接器(1) 6. Tomcat剖析(四):Tomcat默认连接器(2) 7. Tomcat剖析(五):容器 第一部分:概述 这一节基于<深度剖析Tomcat>第五章:容器 总结而成 一定要先到我的git

Tomcat剖析(一)

Tomcat剖析(一) 这一节基于 <深度剖析Tomcat>第一章:一个简单的Web服务器 总结而成.写得不好之处,请见谅 对Tomcat而言,如果直接对其源码进行分析是困难的,所以这里被设计得足够简单使得你能理解一个 servlet 容器是如何工作的,没有对Tomcat本身的连接器和容器进行分析,本节旨在明白服务器的整个流程大致是如何进行的.需要知道如何完善Web服务器,可以参考这本书后面的章节,或者等我发表<Tomcat剖析(二)>. 文中细说明是从书中相关章节中copy下来的

Linux高性能服务器编程——定时器

 定时器 服务器程序通常管理着众多定时事件,因此有效组织这些定时事件,使之能在预期的时间点被触发且不影响服务器的主要逻辑,对于服务器的性能有着至关重要的影响.位置我们要将每个定时事件封装成定时器,并使用某种容器类型的数据结构,比如链表.排序链表和时间轮将所有定时器串联起来,以实现对定时事件的统一管理. Linux提供三种定时方法: 1.socket选项SO_RECVTIMEO和SO_SNDTIMEO. 2.SIGALRM信号 3.I/O复用系统调用的超时参数 socket选项SO_RCVTI

Linux 高性能服务器编程——高级I/O函数

重定向dup和dup2函数 [cpp] view plaincopyprint? #include <unistd.h> int dup(int file_descriptor); int dup2(int file_descriptor_one, int file_descriptor_two); dup创建一个新的文件描述符, 此描述符和原有的file_descriptor指向相同的文件.管道或者网络连接. dup返回的文件描述符总是取系统当前可用的最小整数值. dup2函数通过使用参数f

完成端口与高性能服务器程序开发

原文出处:http://blog.csdn.NET/roen/archive/2007/03/19/1533378.aspx 以一个文件传输服务端为例,在我的机器上它只起两个线程就可以为很多个客户端同时提供文件下载服务,程序的性能会随机器内CPU个数的增加而线性增长,我 尽可能做到使它清晰易懂,虽然程序很小却用到了NT 5的一些新特性,重叠IO,完成端口以及线程池,基于这种模型的服务端程序应该是NT系统上性能最好的了. 首先.做为完成端口的基础,我们应该理解重叠IO,这需要你已经理解了内核对象及