目录
Tomcat概念
核心组件
Web容器
Web服务器之间解析请求的区别
Apache HTTP Server
Nginx
Tomcat
Servlet容器
JSP容器
字节码文件
Tomcat表面处理请求的过程
Tomcat底层处理请求的过程
内部结构
Tomcat部署
JRE环境配置
PATH冒号位置的区别
安装Tomcat
目录结构
常见端口号
发布站点
JMeter压力测试
Tomcat优化
优化前后对比
Tomcat概念
- 免费、开源的Web应用服务器
- Apache软件基金会(Apache Software Foundatio)Jakarta项目中的一个核心项目
- 由Apache、Sun和一些公司及个人共同开发而成
- 深受Java爱好者的喜爱,并得到部分软件开发商的认可
- 目前比较流行的Web应用服务器
核心组件
Tomcat 由一系列的组件构成,其中核心的组件有三个:
web容器:完成web服务器的功能。
Servlet容器:名字为catalina,用于处理Servlet代码。
JSP 容器:用于将 JSP动态网页翻译成Servlet代码。
Web容器
Web 容器负责接收所有HTTP请求,根据请求的URL调用对应的Servlet映射来确定哪个Servlet来处理特定请求,或直接解析静态资源,然后将结果返回给客户端
Web服务器之间解析请求的区别
Apache HTTP Server
Apache HTTP Server服务器本身是可以独立处理静态资源请求,而对于动态资源的解析,Apache需要通过开启mod_php等模块才能动态请求
Nginx
Nginx服务器本身也可以独立处理静态资源请求,对于动态资源的解析,Nginx需要借助FastCGI等接口或者反向代理,将动态资源请求传递给后端服务器来解析,比如php-fpm、Node.js等服务器
Tomcat
Tomcat可以独立处理静态资源和动态资源的请求,Tomcat内置了Servlet和JSP的解析引擎,无需借助额外的模块或接口解析动态请求。
在实际部署中,因为Tomcat的静态解析效率不高,所以通常会将静态资源的处理交给专门的前端服务器,比如 Apache 或 Nginx,而将动态内容交给 Tomcat 这样的应用服务器,实现动静分离。
Servlet容器
在Java程序运行的时候,需要一个基本的JRE(Java运行时环境)环境,JRE不是一个单独的进程,而是一个容器,Tomcat是跑在JRE容器的环境里运行的
Servlet有一个名字:Catalina(卡特琳娜),负责加载和执行Servlet代码,并处理Servlet相关的请求。
比如将JSP代码通过JSP容器翻译成Servlet代码,然后由Servlet容器解析,最后将解析的结果返回Web容器,再由Web容器返回给用户
JSP容器
负责将JSP文件中的静态代码和Java代码编译成Servlet类。
一旦JSP文件被编译为Servlet类,它会被编译成字节码文件(.class)并可以在Servlet容器中执行。
JSP页面中包含的Java代码需要被编译成字节码,以便在Servlet容器中运行。这样做可以确保在每次请求时不需要重新解析和编译JSP页面,而是直接执行已经编译好的字节码
字节码文件
什么是字节码文件,比如使用记事本编写一个使用Main方法执行输出语句"HelloWord"的.java文件
然后在命令行使用javac命令对该文件进行编译,得到了.class为后缀的字节码(bytecode)文件。
这个.class文件就是字节码文件,可以在任何支持了JVM(Java虚拟机)的平台上运行,而无需重新编译
总结
字节码文件是Java代码最终编译的目标,它允许Java程序在JVM(Java虚拟机)上跨平台运行。
Tomcat表面处理请求的过程
- tomcat默认端口号:8080
- 当用户在浏览器中输入服务器的IP地址和端口向客户端发送一个请求
- Tomcat服务器收到请求后通过JSP容器将请求页面的代码转换为Servlet代码
- 再转交给Servlet容器,Servlet基于JRE(Java运行时环境)解析请求
- 如果请求的内容涉及到数据库需要在Servlet代码中连接数据库获取数据
- 最后返回给用户
如果该服务器实现了动静分离,比如Nginx和Tomcat,当用户向Nginx的80端口发送动态解析请求时,Nginx通过反向代理将动态请求传递给Tomcat,由Tomcat处理后返回给Nginx再返回给用户
Tomcat底层处理请求的过程
- 当用户通过浏览器向服务器特定端口发送请求
- Connector接收请求后,交给Container中的Engine容器
- 通过用户输入的域名判断要访问的站点
- 确定了要访问的站点就会将找到对应Host
- Host收到请求后再交给Context
- 由Context当中的Servlet将代码进行解析
- 解析完成后,将请求返回给上层容器,直到返回给Connector,由连接器返回给用户
内部结构
容器 | 说明 |
Tomcat | 可以看作是一个Tomcat服务器 |
Service | Tomcat服务器里有一个Service容器,每一个Tomcat只有一个Service容器,是其他子容器的集合 |
Connector | Service的子容器,当用户在浏览器中向Tomcat发起请求,Tomcat通过Connector(连接器)接收请求,Tomcat可以有多个连接器,每个连接器可以监听特定的端口。如果要在Tomcat部署基于端口的虚拟主机,就要添加连接器,每个连接器监听不同端口 |
Container | Service的子容器,最多只能有一个Container,负责最终为用户提供代码的解析,但是Container又包含了很多子容器 |
Engine | Container的子容器,最多只能有一个Engine,负责管理基于域名的虚拟主机 |
Host | Engine的子容器,Host可以有多个,每个Host都是一个虚拟主机 |
Context | 上下文,负责每一个Host对应站点的代码运行 |
Servlet | Context可以包含多个Servlet,负责处理来自客户端的HTTP请求,执行一些逻辑(比如业务逻辑、数据处理等),然后生成符合HTTP标准的响应返回给客户端。 |
需要注意的是,Tomcat只支持基于端口和基于域名的虚拟主机,而没有基于IP的虚拟主机。
Tomcat部署
导入jdk的rpm软件包,使用rpm -ivh jdk-8u171-linux-x64.rpm命令安装jdk环境
装完可以使用java -version命令测试是否正常显示版本信息,还可以在/usr/下看到名为java的文件夹,就是安装目录
JRE环境配置
为了确保Java能够正常运行,需要设置配置环境变量,在全局环境变量文件中使用export将Java家目录的路径和类库路径的添加为全局变量
并且将Java命令添加到系统查找命令的$PATH变量中,也就是echo $PATH显示的多个路径,系统会在这些路径下查找和用户输入内容所匹配的命令
最后使用source命令重新加载存放环境变量的文件,然后再输出$PATH变量的值,就可以看到Java命令的路径已经被追加到末尾了
此时JRE(Java运行时环境)就配置好了
[root@localhost ~]# vim /etc/profile
export JAVA_HOME=/usr/java/jdk1.8.0_171-amd64
export CLASSPATH=$JAVA_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin
[root@localhost jdk1.8.0_171-amd64]# source /etc/profile
[root@localhost jdk1.8.0_171-amd64]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/java/jdk1.8.0_171-amd64/bin
PATH冒号位置的区别
这里使用的PATH变量不是新建了一个PATH变量,而是调用了系统已有的变量,冒号(:)表示在该变量的值末尾,追加指定值,这里追加了Java命令的路径,让系统可以在终端中识别Java命令
如果将PATH变量的冒号放到末尾去追加行不行呢?
就变成了:export PATH=$JAVA_HOME/bin:$PATH
实际上是可行的,但是实现的效果相反,比如当你执行了export PATH=$JAVA_HOME/bin:$PATH
这个命令会将$JAVA_HOME/bin的路径放在现有$PATH变量的开头,就不是追加了,但是$PATH会把$JAVA_HOME/bin放在$PATH的最前面,在系统识别命令_时,优先搜索Java命令
如果当你执行了export PATH=$PATH:$JAVA_HOME/bin,则会把$JAVA_HOME/bin放到$PATH变量的末尾,当系统识别命令时,会先搜索现有路径再搜索$JAVAHOME/bin
安装Tomcat
导入Tomcat的tar.gz包,由于该包是直接解压使用的,所以使用tar zxvf apache-tomcat-9.0.8.tar.gz命令直接解压,然后通过mv apache-tomcat-9.0.8 /usr/local/tomcat命令将该包移动到/usr/local/下,重命名为tomcat
目录结构
进入tomcat目录,使用ll命令可以查看tomcat的目录结构
目录或文件 | 说明 |
bin | 用于存放Tomcat的可执行文件,比如启动和停止脚本 (startup.sh、shutdown.sh) 以及其他管理和维护 Tomcat 服务器的工具 |
conf | 用于存放Tomcat的配置文件 |
lib | 用于存放Tomcat运行时需要Java类库和依赖的JAR文件 |
logs | 用于存储Tomcat的日志文件 |
temp | 用于存放 Tomcat 运行时生成的临时文件,比如编译后的 JSP 文件等。 |
webapps | 存放Tomcat的默认web应用程序部署目录,将你的WAR包放入后,Tomcat 会自动解压并运行这些应用。 |
work | 用于存放Tomcat运行时生成的servlet编译文件。 |
LICENSE | 这是 Tomcat 的许可证文件,包含了软件使用和分发的许可条款。 |
RELEASE-NOTES | 这是该版本 Tomcat 的发行说明,描述了新功能、改进和已知问题等信息。 |
RUNNING.txt | 这个文件提供了关于如何运行 Tomcat 服务器的简要说明和提示。 |
常见端口号
打开/usr/local/tomcat/conf/server.xml文件,在Tomcat的配置文件中可以看到多个容器的标签内都有Port的属性
这个Port属性就定义了在某个阶段监听的端口号,下面一一列出重要的端口号
端口号 | 说明 |
8005 | 只能在本地用命令行关闭Tomcat服务的端口 |
8009 | Tomcat服务器通过Connector连接器组件与客户程序建立连接使用的端口 |
8080 | Tomcat的web服务端默认端口号(HTTP) |
8443 | 访问Tomcat的HTTPS的端口 |
发布站点
这里我们要通过基于域名的虚拟主机发布两个站点,先创建存放第一个站点的目录www,新建index.jsp文件,添加www.benet.com内容
再创建bbs站点,步骤同上
[root@localhost tomcat]# cd webapps/
[root@localhost webapps]# mkdir www
[root@localhost webapps]# cd www
[root@localhost www]# vim index.jsp
www.benet.com
[root@localhost www]# cd ..
[root@localhost webapps]# mkdir bbs
[root@localhost webapps]# cd bbs
[root@localhost bbs]# vim index.jsp
bbs.benet.com
打开配置文件
[root@localhost ~]# vim /usr/local/tomcat/conf/server.xml
在tomcat的配置文件中添加站点,在第148行可以看到Host容器,修改name属性的域名为www.benet.com,添加Context(上下文)标签,指定该域名的网页文件位置,开启自动重载,然后再创建一个Host标签,修改name等参数,用于第二个站点的发布
- Context标签内的path属性的作用是:虚拟路径,指定了在Web服务器上访问该Web应用程序的路径,如果 path 设置为 ""(空),则该应用程序将作为根应用程序处理。如果设置为 "/myapp",则用户访问http://www.benet.com/myapp地址时,该站点才会可用
- reloadable:当类的内容发行改动时,会自动重载,而不需要人为重启
<Host name="www.benet.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context docBase="/usr/local/tomcat/webapps/www" path="" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="www_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="bbs.benet.com" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Context docBase="/usr/local/tomcat/webapps/bbs" path="" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="bbs_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
首先关闭防火墙,允许tomcat流量通过。最后运行tomcat的bin目录下的startup.sh,启动tomcat
[root@localhost tomcat]# systemctl stop firewalld
[root@localhost tomcat]# cd bin/
[root@localhost bin]# ./startup.sh
[root@localhost bin]# netstat -anpt | grep java
tcp6 0 0 127.0.0.1:8005 :::* LISTEN 19470/java
tcp6 0 0 :::8009 :::* LISTEN 19470/java
tcp6 0 0 :::8080 :::* LISTEN 19470/java
使用Linux或Windows主机都可以测试,但前提是在主机上的Hosts文件添加对应解析条目
192.168.10.101 www.benet.com bbs.benet.com
使用域名:端口号的方式来访问Tomcat服务器
JMeter压力测试
JMeter是基于JAVA开发的压力测试软件。用于在Windows系统上运行,在短时间内向服务器发送大量请求,来测试服务器压力承受的能力
打开一台Win10虚拟机或直接在宿主机上测试,解压apachejmeter31.zip软件包,进入bin目录下,双击运行jmeter.bat批处理文件启动该工具
首先添加一个用户线程组
线程数:每个线程代表一个虚拟用户,将线程组的进程数设置为100,JMeter将会模拟100个并发用户同时对目标系统进行请求,这里用我们使用4000个线程
Ramp-up Period(in seconds):每秒钟,1个线程发送多少个请求
那么请求总量就是4000 * 20 = 80000,也就是说总共向服务器在短时间内发送80000个请求让服务器来响应
右键测试计划是针对整个测试计划添加聚合报告和图形结果,用于显示整个测试计划的测试结果
添加测试的请求
写入要测试的域名和端口号
测试该线程组时时可以把针对整个测试计划的图形结果和聚合报告删除,右键线程组,添加只针对线程组的聚合报告和图形结果
最终效果如下
然后右键线程组,选Start
如果是第一次测试,会提示你保存该线程组,方便以后使用,然后压力测试就已经开始了
当上方的箭头图标变绿了以后,代表测试已经结束,可以查看结果报告
打开聚合报告会显示出测试结果,把优化前的测试结果截图保存,用于和一会优化后的结果对比
Tomcat优化
打开tomcat配置文件
[root@localhost ~]# cd /usr/local/tomcat/conf/
[root@localhost conf]# vim server.xml
将连接器改为以下内容,进行优化
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
minSpareThreads="50"
enableLookups="false"
disableUploadTimeout="true"
acceptCount="300"
maxThreads="500"
processorCache="500"
URIEncoding="UTF-8"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/javascript,text/css,tex t/plain,image/gif,image/jpg,image/png" />
参数 | 说明 |
connectionTimeout="20000" | 指定了连接超时时间,单位是毫秒。在20秒内如果连接没有建立成功,则超时。 |
redirectPort="8443" | 指定了当需要进行重定向时使用的端口号,一般用于HTTPS协议的情况,这里是8443端口 |
minSpareThreads="50" | 指定了最小空闲线程数。Tomcat会尽量保持至少这么多个线程处于空闲状态,以备处理新的请求。 |
enableLookups="false" | 设置是否允许DNS查询。这里设置为false,表示不允许Tomcat对客户端的IP地址进行DNS查询。 |
disableUploadTimeout="true" | 禁用上传超时。设置为true时,Tomcat将不会对上传操作设置超时限制。 |
acceptCount="300" | 指定了在处理满负荷的情况下,能接受的最大连接请求数。当达到这个数目后,新的连接请求将会被拒绝。 |
maxThreads="500" | 指定了连接器处理的最大线程数。当达到这个数目时,新的连接请求会进入等待队列(如果已满则会拒绝连接) |
processorCache="500" | 指定了处理器缓存的大小。Tomcat在内部使用处理器对象池来重复使用已经创建的处理器。这里设置为500,表示最多可以缓存500个处理器对象。 |
URIEncoding="UTF-8" | 指定了URL的编码格式。这里设置为UTF-8 |
compression="on" | 启用响应内容的压缩功能 |
compressionMinSize="2048" | 设置触发压缩的最小响应内容大小,单位是字节。当响应内容大于这个值时才会进行压缩 |
compressableMimeType | 指定可以进行压缩的MIME类型 |
重启tomcat
[root@localhost conf]# ../bin/shutdown.sh
[root@localhost conf]# ../bin/startup.sh
先访问tomcat能否在浏览器正常访问,确保修改后的配置文件能够正常运行tomcat
优化前后对比
确保修改的配置文件能够正常运行tomcat后,可以进行优化的压力测试,此时打开JMeter工具
第二次测试之前先清除全部,否则第二次测试的结果会和第一次的重叠
右键线程组 ——》Start
开始压力测试
待上方箭头图标变成绿色之后,表示测试结束
此时将优化后的聚合报告也截图保存,然后放到Word文档里,可以进行对比
参数 | 说明 |
Label | 表示每个HTTP请求或事务的名称或标识。用来区分不同请求或事务的名称。 |
Samples | 表示测试中一共发出了多少个请求,单位一般为毫秒 |
Average | 平均响应时间,越小越好 |
Median | 中位数,也就是 50% 用户的响应时间 |
90% Line | 90% 用户的响应时间 |
95% Line | 95% 用户的响应时间 |
99% Line | 99% 用户的响应时间 |
Min | 最小响应时间 |
Max | 最大响应时间 |
Error % | 本次测试中出现错误的请求的数量/请求的总数 |
Throughput | 吞吐量,表示每秒完成的请求数。单位是请求/秒 |
Received KB/sec | 每秒接收的数据量,单位是KB/秒。 |
Sent KB/sec | 每秒发送的数据量,单位是KB/秒。 |