Tomcat 架构
最近在开发过程中,遇到需要对Tomcat配置进行优化,索性把整个Tomcat架构以及底层的一些基础知识一起研究了一下。对于Tomcat的架构设计有很多地方值得借鉴学习,包括模块化设计,模块组件的生命周期管理,通信编程的一些原理以及技巧等等
一、Tomcat源码导入
研究的Tomcat为:9.0.6,JDK为1.8
IDEA新建Maven工程,我新建的工程为tomcatSource,配置pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.invoker.fy</groupId>
<artifactId>tomcatSource</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant-apache-log4j</artifactId>
<version>1.6.5</version>
</dependency>
<dependency>
<groupId>ant</groupId>
<artifactId>ant-commons-logging</artifactId>
<version>1.6.5</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>javax.xml.rpc</groupId>
<artifactId>javax.xml.rpc-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>tomcatSource</finalName>
<sourceDirectory>java</sourceDirectory>
<resources>
<resource>
<directory>java</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<configuration>
<encoding>UTF-8</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Apache 官网下载源码:https://tomcat.apache.org/download-90.cgi,下载zip包
解压,将文件copy到工程tomcatSource目录下,工程目录结构如下
Tomcat组件生命周期
server.xml文件,删除了注释
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
tomcat实际上是一个servlet容器,从server.xml文件解析可以看出容器包含server、service、connector、container等等,这些容器都具有新建、初始化完成、启动、停止、失败、销毁等状态。Tomcat的实现提供了对这些容器的生命周期管理
Tomcat 架构图
先来看一下Tomcat的顶层架构,Server是最顶层的容器,1个Server包含至少一个Service,1个Service包含多个Connector和1个Container容器
(1)Server控制这个Tomcat的生命周期
(2)Service对外提供服务
(3)Connector用于接受请求并将请求封装成request和response来具体处理
(4)Container用来处理Servlet,具体处理request请求
整个Tomcat最核心的2个容器组件为Connector和Container,开发过程中tomcat调优也在Connector容器组件的配置优化,所以重点说一下Connector容器
一般接收到一个请求时,首先经过Serveice容器,再经过Connector容器,将接收到的请求底层的socket封装成request和resposne来具体处理,然后交由Container处理,container处理完之后返回给Connector,Connector通过socket将处理的结果返回给客户端;这样整个请求就处理完了
(1) Connector就是使用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型;ProtocolHandler包含三个组件,endpoint用于处理底层socket网络连接,实现的是TCP/IP协议,Processor用于将Endpoint接收到的Socket封装成Request,Adapter用于将Request交给Container进行具体的处理
(2)Endpoint的抽象实现AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口。Acceptor用于监听请求,AsyncTimeout用于检查异步Request的超时,Handler用于处理接收到的Socket,在内部调用Processor进行处理
(3)Connector在接收到请求后会首先调用最顶层容器的Pipeline来处理,这里的最顶层容器的Pipeline就是EnginePipeline,然后执行StandardEngineValue、StandardHostValue、StandardWrapperValue,当执行到StandardWrapperValue,会调用FilterChain处理链,最终执行处理链的service方法;当所有的Pipeline-Value都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端
至此,整个Tomcat架构有了一个清晰的认识,由于tomcat是一个servlet容器,所以每个容器都有servlet特征,包括初始化、service、销毁等方法;代码细节可以研究源码;下面重点说一下tomcat调优,connctor的配置
在项目中,对于web项目war包部署,通常在server.xml中配置Host节点以及war包项目路径,对于Connector配置说一下
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
配置中Executor用来配置tomcat共享线程池,配置参数官网说明:
当tomcat启动的时候,一旦有请求过来,就会创建minSpareThreads线程,用来处理请求,当超过maxThreads数量时,进入队列,队列大小控制为maxQueueSize,超过队列数量,就会拒绝请请求;对于这几个参数的设置,要根据业务场景以及服务器性能来决定,如果是计算密集型的,通常maxThreads要控制小一些,因为太大,线程的切换消耗CPU,但IO密集型的,可以控制大一些,提高并发能力;maxThreads默认为200,minSpareThreads默认为25,队列默认为LinkedBlockingQueue*阻塞队列,但不建议设置*,因为任何请求都会有超时时间的设置,可以根据业务场景合理设定;经验值:并发线程数量=CPU核心数 * CPU使用率 * (1 + 等待时间/计算时间),比如CPU核数为64,使用率为0.75,等待时间/计算时间为2,maxThreads设置为144;
注意:如果connector节点配置了Executor,则Executor节点一定要配置在Connector节点前面,一旦配置了Executor,则connector配置的maxThreads就无效
下面来看一下Connector节点配置参数官网说明:http://tomcat.apache.org/tomcat-9.0-doc/config/http.html
重点说一下maxConnections,最大可以接受的连接数,不一定处理;好比看房,取号的都在售楼处外面候着,maxConnections为最大取号的数量,maxThreads为楼房数量,默认一个楼房只允许一个人看(怎么可能!!!)因为tomcat一个线程只会处理一个连接,acceptCount即队列数量,就是售楼处中待看房的人;所以tomcat性能瓶颈依赖的是maxThreads + acceptCount;
上一篇: HashMap源码分析
下一篇: tomcat架构
推荐阅读
-
tomcat8运行报nested exception is java.lang.NoClassDefFoundError
-
Intellij IDEA remote tomcat debug with jrebel on linux
-
为什么 Facebook 不使用 Java 架构?使用 Java 与 PHP 架构相比有哪些优势和劣势?
-
高访问量的评论系统数据库存储过程架构
-
.net及其他架构中异常 (Except) 设计准则的详细介绍
-
Oracle Golden Gate体系架构详解
-
nginx+tomcat配置https最简单方案
-
承载千万级并发的分布式系统架构设计思想
-
百度凤巢架构师张栋离职 出任im2.0首席科学家
-
MySQL性能调优与架构设计-架构篇