小阿轩yx-Tomcat 部署及优化
Tomcat 概述
- 免费的、开放源代码的Web应用服务器
- Apache软件基金会(Apache Software Foundation)Jakarta项目中的一个核心项目
- 由Apache、Sun和一些公司及个人共同开发而成
- 深受Java爱好者的喜爱,并得到部分软件开发商的认可
- 目前比较流行的Web应用服务器。
Tomcat 核心组件
Tomcat 由一系列的组件构成,其中核心的组件有三个
-
web容器:完成web服务器的功能
-
Servlet容器:名字为catalina,用于处理Servlet代码
-
JSP 容器:用于将 JSP动态网页翻译成Servlet代码
JavaServlet
-
Servlet是Java Servlet 的简称,可以理解为是一个服务连接器
-
是用Java编写的服务器端程序
优势
-
具有独立于平台和协议的特性
简单的理解
-
servlet 就是一个中间件
包含
-
接口
-
方法
将客户端和数据库连接,从而实现动态网页的创建
JSP容器
-
JSP 全称 Java Server Pages,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以< % 开头,以%>结束
-
JSP是一种 Java servlet,主要用于实现 Java web应用程序的用户界面部分
-
JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页
Tomcat 请求处理
- 用户在浏览器中输入网址 localhost:8080/testindexjsp,请求被发送到本机端口 8080,被在那里监听的 Coyote HTTP/1.1 Connector 获得;
- Connector把该请求交给它所在的Service 的 Engine(Container)来处理,并等待Engine 的回应:
- Engine 获得请求 localhost/test/index.jsp,匹配所有的虚拟主机 Host;
- Engine 匹配到名为 localhost的 Host(即使匹配不到也把请求交给该 Host 处理,因为该 Host 被定义为该 Engine 的默认主机),名为 localhost 的 Host 获得请求/testindex.jsp,匹配它所拥有的所有 Context。Host 匹配到路径为/test 的 Context(如果匹配不到就把该请求交给路径名为“”的 Context 去处理);
- path=“/test”的 Context 获得请求/index.jsp,在它的 mapping table 中寻找出对应的Servlet。 Context 匹配到 URL Pattemn 为*.jsp的 Servlet,对应于 JspServlet 类:
- 构造 HttpServletRequest 对象和 HtpServetResponse 对象,作为参数调用 JspServlet的 doGet()或 doPost0),执行业务逻辑、数据存储等;
- Context 把执行完之后的 HttpServletResponse 对象返回给 Host;
- Host 把 HttpServletResponse 对象返回给 Engine;
- Engine 把 HttpServletResponse 对象返回 Connector;
- Connector把 HttpServletResponse 对象返回给客户 Browser;
Tomcat 功能组件结构
6个核心组件
-
Server
-
Service
-
Connector
-
Engine
-
Host
-
Context等
Server
-
Server元素在最顶层,代表整个Tomcat容器,因此它必须是server.xml中唯一一个最外层的元素。一个Server元素中可以有一个或多个Service元素
-
主要任务,提供一个接口让客户端能够访问到这个Service集合,同时维护它所包含的所有Service的声明周期,包括如何初始化、如何结束服务、如何找到客户端要访问的Service
Service
-
作用,在Connector和Engine外面包了一层,把它们组装在一起,对外提供服务。一个Service可以包含多个Connector,但是只能包含一个Engine;其中Connector的作用是从客户端接收请求,Engine的作用是处理接收进来的请求。Tomcat可以提供多个Service,不同的Service监听不同的端口
Connector
主要功能
-
接收连接请求,创建Request和Response对象用于和请求端交换数据;然后分配线程让Engine来处理这个请求,并把产生的Request和Response对象传给Engine。通过配置Connector,可以控制请求Service的协议及端口号
Engine组件
-
在Service组件中有且只有一个;Engine是Service组件中的请求处理组件。Engine组件从一个或多个Connector中接收请求并处理,并将完成的响应返回给Connector,最终传递给客户端
-
实际上,Engine、Host和Context都是容器,但它们不是平行的关系,而是父子关系:Engine包含Host,Host包含Context
Host
-
是Engine的子容器。Engine组件中可以内嵌1个或多个Host组件,每个Host组件代表Engine中的一个虚拟主机。Host组件至少有一个,且其中一个的name必须与Engine组件的defaultHost属性相匹配
Host虚拟主机的作用
-
是运行多个Web应用(一个Context代表一个Web应用),并负责安装、展开、启动和结束每个Web应用
Context元素
-
代表在特定虚拟主机上运行的一个Web应用。每个Web应用基于WAR文件,或WAR文件解压后对应的目录(这里称为应用目录)。Context是Host的子容器,每个Host中可以定义任意多的Context元素
Container结构分析
每个 Service 会包含一个 Container容器
Container内部包含了4个子容器
-
Engine:引擎,用来管理多个虚拟主机,一个Service 最多只能有一个Engine;
-
Host:代表一个虚拟主机,也可以叫站点,通过配置 Host 就可以添加站点;
-
Context:代表一个 web应用,包含多个Servlet封装器;
-
wrapper:封装器,容器的最底层。每一wrapper 封装着一个Servlet,负责对象实例的创建、执行和销毁功能。
-
Engine、Host、Context和 wrapper,这四个容器之间属于父子关系。容器由一个引擎可以管理多个虚拟主机。每个虚拟主机可以管理多个web应用。每个web应用会有多个Servlet封装器
Tomcat数据流向
Tomcat 服务部署
案例环境
名称 | 说明 |
系统版本 | CentOS7.9(64位) |
Tomcat 版本 | 9.0.8 |
jdk版本 | 1.8.0_171 |
服务器IP地址 | 192.168.10.101 6G 内存 |
Windows 客户端IP地址及其配置 | 192.168.10.10 8G 内存 |
主机名 | localhost.localdomain |
Firewalld | 关闭 |
Selinux | 禁用 |
Jmeter 版本 | 3.1 |
下载并安装 JDK
安装JDK
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# rpm -ivh jdk-8u171-linux-x64.rpm
设置 jdk 的环境变量
[root@localhost ~]# vim /etc/profile
export JAVA_HOME=/usr/java/jdk1.8.0_171-amd64
export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib
export PATH=$JAVA_HOME/bin:$PATH
[root@localhost ~]# source /etc/profile
[root@localhost ~]# java -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)
安装启动 Tomcat
[root@localhost ~]# tar zxvf apache-tomcat-9.0.8.tar.gz
[root@localhost ~]# mv apache-tomcat-9.0.8 /usr/local/tomcat
[root@localhost ~]# /usr/local/tomcat/bin/startup.sh
[root@localhost ~]# netstat -anpt | grep java
tcp6 0 0 127.0.0.1:8005 :::* LISTEN 9591/java
tcp6 0 0 :::8009 :::* LISTEN 9591/java
tcp6 0 0 :::8080 :::* LISTEN 9591/java
注:
-
8005端口是用于命令行关闭Tomcat服务
-
8009 Tomcat服务器通过Connector连接器组件与客户程序建立连接使用的端口
-
8080是Tomcat的web服务端默认口号
浏览器打开 http://192.168.10.101:8080 进行访问会出现 Tomcat 主页
优化 Tomcat 服务启动时间
[root@localhost ~]# vim /usr/java/jdk1.8.0_171-amd64/jre/lib/security/java.security securerandom.source=file:/dev/urandom
##已经存在该参数
urandom
[root@localhost ~]# /usr/local/tomcat/bin/shutdown.sh
[root@localhost ~]# /usr/local/tomcat/bin/startup.sh
Tomcat 目录结构
[root@localhost ~]# ll /usr/local/tomcat/
总用量 92
drwxr-x---. 2 root root 4096 6月 11 08:04 bin
drwx------. 3 root root 254 6月 11 08:04 conf
drwxr-x---. 2 root root 4096 6月 11 08:04 lib
-rw-r-----. 1 root root 57092 4月 28 2018 LICENSE
drwxr-x---. 2 root root 197 6月 11 08:04 logs
-rw-r-----. 1 root root 1804 4月 28 2018 NOTICE
-rw-r-----. 1 root root 6852 4月 28 2018 RELEASE-NOTES
-rw-r-----. 1 root root 16246 4月 28 2018 RUNNING.txt
drwxr-x---. 2 root root 30 6月 11 08:04 temp
drwxr-x---. 7 root root 81 4月 28 2018 webapps
drwxr-x---. 3 root root 22 6月 11 08:04 work
注:
- bin 目录:用于存放启动和关闭 Tomcat 的脚本文件,比较常用的是 catalina.sh、startup.sh、shutdown.sh 三个文件。
- conf 目录:用于存放 Tomcat 服务器的各种配置文件,比较常用的是 server.xml、context.xml、tomcat-users.xml、web.xml 四个文件。
- lib 目录:用于存放 Tomcat 服务器的 jar 包,一般不作任何改动,除非连接第三方服务,比如 redis,那就需要添加相对应的 jar 包。
- logs 目录:用于存放 Tomcat 日志。
- temp 目录:用于存放 Tomcat 运行时产生的文件。
- webapps 目录:用于存放项目资源的目录。
- work 目录:是 Tomcat 工作目录,一般清除 Tomcat 缓存的时候会使用到。
Tomcat 配置与优化
虚拟主机配置
创建 www 和 bbs 项目目录和文件
[root@localhost ~]# mkdir /usr/local/tomcat/webapps/www
[root@localhost ~]# echo "This is www page\!"> /usr/local/tomcat/webapps/www/index.jsp
[root@localhost ~]# mkdir /usr/local/tomcat/webapps/bbs
[root@localhost ~]# echo "This is bbs page\!"> /usr/local/tomcat/webapps/bbs/index.jsp
修改 Tomcat 主配置文件
[root@localhost ~]# vim /usr/local/tomcat/conf/server.xml
<Host name="www.test.com" appBase="/usr/local/tomcat/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="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="bbs.test.com" appBase="/usr/local/tomcat/bbs"
unpackWARs="true" autoDeploy="true">
<Context docBase="/usr/local/tomcat/webapps/bbs" path="" reloadable="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>
[root@localhost ~]# /usr/local/tomcat/bin/shutdown.sh
[root@localhost ~]# /usr/local/tomcat/bin/startup.sh
注:
- <Host name="bbs.test.com" appBase="/usr/local/tomcat/webapps"
- name="bbs.test.com" 网站的服务名称,做基于域名的虚拟主机时,这个参数需要设置如果要做基于端口的虚拟主机,此处的值应修改为原来的localhost
- appBase="/usr/local/tomcat/webapps" 站点目录,这个位置可以不用修改
- path="" 虚拟目录的目录名,URL/path,指的是斜杠后跟的字符串
- reloadable="true" reloadable=true时 当web.xml或者class有改动的时候都会自动重新加载不需要从新启动服务
虚拟主机访问测试
客户端绑定两个域名需要写入本机 hosts 文件
- 192.168.10.101 www.benet.com bbs.benet.com
- 192.168.10.102 www.accp.com
注:
-
tomcat可以实现基于域名的虚拟主机、基于端口的虚拟主机
-
Tomcat不支持基于IP的虚拟主机
Tomcat 优化
- Tomcat 默认安装下的缺省配置并不适合生产环境
- 它会频繁出现假死现象需要重启只有通过不断压测优化才能让它最高效率稳定的运行
优化主要包括三方面
- 分别为操作系统优化(内核参数优化)
- Tomcat配置文件参数优化
- Java虚拟机(JVM)调优
(注:其中最难理解的就是 JM 调优)
Tomcat 配置文件参数优化
- maxThreads:Tomcat 使用线程来处理接收的每个请求,这个值表示 Tomcat 可创建的最大的线程数,默认值是 200
- minSpareThreads:最小空闲线程数,Tomcat 启动时的初始化线程数,表示即使没有人使用也开这么多空线程等待,默认值是10
- maxSpareThreads:最大备用线程数,一旦创建的线程超过这个值,Tomcat 就会关闭不再需要的 socket 线程。默认值是-1(无限制),一般不需要指定。
- URlEncoding:指定 Tomcat 容器的 URL 编码格式,Tomcat 语言编码格式这块不如其它 Web 服务器软件配置方便,需要分别指定。
- connnectionTimeout:网络连接超时,单位:毫秒,设置为0表示永不超时,这样设置有隐患的。通常默认 20000 毫秒就可以。
- enableLookups:是否反查域名,以返回远程主机的主机名,取值为:true或false,如果设置为 false,则直接返回IP 地址,为了提高处理能力,应设置为 false。
- disableUploadTimeout:上传时是否使用超时机制。应设置为true。
- connectionUploadTimeout:上传超时时间,毕竟文件上传可能需要消耗更多的时间,该参数需要根据自己的业务需要自行调整,以使 Servlet有较长的时间来完成它的执行需要与上一个参数一起配合使用才会生效。
- acceptCount:指定当所有可以使用的处理请求的线程都被使用时,可传入连接请求的最大队列长度,超过这个数的请求将不予处理,默认为100个。
- compression:是否对响应的数据进行 GZIP 压缩,off 表示禁止压缩、on 表示允许压缩(文本将被压缩)、force 表示所有情况下都进行压缩,默认值为 off。压缩数据后可以有效的减少页面的大小,一般可以减小 1/3 左右,因而节省带宽。
- compressionMinSize:表示压缩响应的最小值,只有当响应报文大小大于这个值的时候才会对报文进行压缩,如果开启了压缩功能,默认值就是2048。
- compressableMimeType:压缩类型,指定对哪些类型的文件进行数据压缩
- noCompressionUserAgents="gozilla, traviata":对于以下的浏览器,不启用压缩
jmeter 压测工具
客户端安装 JDK
使用客户端 Windows 10,JDK 使用 jdk-8u102-windows-64版本
运行 jmeter 软件
双击运行apache-jmeter-3.1.rar压缩包->bin目录->ApacheJMeter.jar 文件即可打开jmeter软件
打开压测脚本进行压测
点击左上角文件->打开->选择压测脚本
单击第一排绿色三角按钮(鼠标指上去后会显示启动)开始进行压测
压测脚本里设置 20 秒启动 4000 个线程数,并发为 2000,超时时间 50000 毫秒。
也可以根据自己的需求进行修改。从压测结果看只关注聚合报告,聚合报告只关注 Average、90% Line、Error%这三列,因为压测 Tomcat 首页压力不会太大,所以 Error 都是为0属于正常。先看一组优化前(默认的配置)压测截图
(注:bin文件夹下jmeter.bat文件是启动脚本)
-
添加线程组(线程数4,循环次数10000)
-
添加http请求
-
添加监听器
-
配置完成后点击上方启动按钮
优化前测试
优化参数
[root@localhost ~]# vim /usr/local/tomcat/conf/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" />
[root@localhost ~]# /usr/local/tomcat/bin/shutdown.sh
[root@localhost ~]# /usr/local/tomcat/bin/startup.sh
优化后测试
优化前后对比
-
Label:每个 JMeter 的 element(例如 HTTP Request)都有一个 Name 属性,label显示的就是 Name 属性的值
-
#Samples:表示你这次测试中一共发出了多少个请求,如果模拟10个用户,每个用户迭代10次,那么这里显示100,这里显示的应该是150000而不是172649,之所以是172649,是因为我中间点击停止,然后又再原来的基础上重新开始执行
-
Average:平均响应时间——默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以Transaction 为单位显示平均响应时间
-
Median:中位数,也就是 50% 用户的响应时间
-
90% Line:90% 用户的响应时间
-
Min:最小响应时间
-
Max:最大响应时间
-
Error%:本次测试中出现错误的请求的数量/请求的总数
-
Throughput:吞吐量——默认情况下表示每秒完成的请求数(Request per Second),当使用了 Transaction Controller 时,也可以表示类似 LoadRunner 的 Transaction per Second 数
-
KB/Sec:每秒从服务器端接收到的数据量,相当于LoadRunner中的Throughput/Sec这里我们可以看到,在这172649多次的访问之中,tomcat的访问出错率是0.15%,即大概有100多次的请求是由于忙碌而失败了的。当然,这只是一个参考,具体还要根据软硬件的条件才能最终确定下来
常见错误说明
java.lang.OutOfMemoryError: Java heap space —— JVM Heap(堆)溢出
JVM 在启动时
会自动设置 JVM Heap 的值
其初始空间(即-Xms)是物理内存的1/64
最大空间(-Xmx)不可超过物理内存
可利用 JVM 提供的 -Xmn -Xms -Xmx 等选项来进行设置。
Heap 的大小是 Young Generation 和 Tenured Generaion之和
在 JVM中如果 98%的时间是用于 GC,且可用的 Heap size 不足 2%的时候将抛出此异常信息。
解决方法:手动设置 JVM Heap(堆)的大小
java.lang.QutOfMemoryError: PermGen space——PermGen space 溢出
PermGen space 的全称是 Permanent Generation space,指内存的永久保存区域。
(注:为什么会内存溢出?
由于这块内存主要是被 JVM 存放 Class 和 Meta 信息的,Class在被 Load 的时候被放入 PermGen space 区域,它和存放 Instance 的 Heap 区域不同,sun的 GC 不会在主程序运行期对 PermGen space 进行清理。所以,如果你的 APP 会载入很多 CLASS 的话,就很可能出现 PermGen space 溢出。)
解决方法:手动设置 MaxPermSize 大小
java.lang.StackOverflowError——栈溢出
JVM 依然是采用栈式的虚拟机,这个和C与 Pascal 都是一样的。
函数的调用过程都体现在堆栈和退栈上了。调用构造函数的“层”太多了,以致于把栈区溢出了。通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要1K 的空间(这个大约相当于在一个℃函数内声明了 256 个int 类型的变量),那么栈区也不过是需要 1MB 的空间。通常栈的大小是 1-2MB 的。
通常递归也不要递归的层次过多,很容易溢出。
解决方法:修改程序
小阿轩yx-Tomcat 部署及优化