一、Tomcat 架构
- Tomcat 是一个基于 Java 的
WEB
容器,其实现了JavaEE
中的Servlet
与Jsp
规范。- 与
Nginx
、Apache
服务器不同,在于一般用于 动态请求处理。- 在架构设计上,采用 面向组件 的方式设计。
- 即整体功能是通过 组件的方式 拼装完成。
- 另外 每个组件 都可以被替换以保证灵活性。
二、Tomcat 组件及关系
核心组件。
Server
:服务器(1个)。
Service
:服务(n个)。
Connector
:连接器(n个)。
指对外开放的端口号,有三种协议。
- HTTP/1.1。
- SSL https。
- AJP/1.3:Apache 私有协议,二进制传输(Apache JServ Protocol)。
用于 Apache 反向代理 Tomcat。
Engine
:引擎(1个)。
默认:Catalina。
Host
:虚拟机(n个)。
基于域名(name)分发请求(默认:localhost)。
Context
:指每个 WEB 应用(n个)。
基于路径(path)分发请求(默认:ROOT)。
每个 Context 的 ClassLoader 都是独立。
- 其他组件(
Component
)。
Manager
:管理器。logger
:日志管理。loader
:载入器。pipeline
:管道。Valve
:管道的阀门。
三、server.xml 配置
- BIO:同步阻塞 模型(Tomcat-6.X)。
- NIO:同步非阻塞 模型(Tomcat-7.X)。
- AIO:基于事件,异步非阻塞 模型(Tomcat-8.X)。
<?xml version="1.0" encoding="UTF-8"?>
<!-- `Server`服务器(1个) -->
<!-- `port`执行关闭命令的端口号 -->
<!-- `shutdown`服务器的关闭命令 -->
<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`服务(n个,默认:`Catalina`),将多个`Connector`与一个`Engine`组合成一个服务 -->
<Service name="Catalina">
<!-- `Connector`连接器(n个,默认:`8080`),用于接收指定协议的连接,并指定给唯一的`Engine`进行处理 -->
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
<!-- `port`连接的端口号 -->
<!-- `protocol`监听的协议(默认:http/1.1) -->
<!-- `redirectPort`重定向端口号(指服务器正在处理`Http`请求时,收到了一个`SSL`传输`Https`请求后重定向的端口号) -->
<!-- `SSLEnabled`是否开启`SSL`认证(在`Https`访问时需要开启) -->
<!-- `enableLookups`为`true`进行`DNS`查询得到远程客户端的实际主机名,为`false`则不进行`DNS`查询而是返回其`IP`地址(`request.getRemoteHost()`获取主机名) -->
<!-- `minSpareThreads`最小备用线程数(默认:10,服务器启动时,创建的处理请求线程数) -->
<!-- `maxThreads`最大线程数(`Worker`线程) -->
<!-- `acceptCount`同时接收最大连接(默认:100),当所有处理请求的线程都被使用时,可以放入处理队列中的请求数,超过这个数的请求将不予处理 -->
<!-- `connectionTimeout`连接超时的时间(单位:毫秒),指在`acceptCount`停留最大时间 -->
<!-- `URIEncoding`对`URI`编码 -->
<!-- `useBodyEncodingForURI`响应的`Body`是否与`URIEncoding`相同编码 -->
<!-- `compression`开启对静态资源压缩 -->
<!-- `compressionMinSize`压缩最小值 -->
<!-- `compressableMimeType`压缩类型 -->
<!-- 自定义`Connector` -->
<Connector port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8444" enableLookups="false"
minSpareThreads="200" maxThreads="1024" acceptCount="800" connectionTimeout="20000"
URIEncoding="UTF-8" useBodyEncodingForURI="true"
compression="on" compressionMinSize="2048" compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css,application/x-json,application/json,application/x-javascript" />
<!-- `Engine`引擎(1个,默认:`Catalina`),用于处理连接的执行器 -->
<!-- `name`引擎名称 -->
<!-- `defaultHost`默认`Host` -->
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" />
</Realm>
<!-- `Host`虚拟机(n个,默认:`localhost`),基于域名匹配虚拟机,类似`Nginx`的`server`模块 -->
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<!-- `Valve`阀门(可以理解成的过滤器),具体配置要基于`Valve`接口的子类,以下为一个访问日志的`Valve` -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
</Host>
<!-- `appBase`类似`Nginx`的`root`模块(绝对路径或相对路径,相对`TOMCAT_HOME`根目录) -->
<!-- `unpackWARs`解压`war`包 -->
<!-- `autoDeploy`自动部署 -->
<!-- 自定义`Host` -->
<Host name="www.qs.com" appBase="E:/root/tomcat" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="www.qs.com_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />
<!-- `Context`应用上下文(n个),每个`Context`都有其独立的`classPath`,避免冲突 -->
<!-- `path`:请求路径 -->
<!-- `docBase`:绝对路径或相对路径(`E:/root/tomcat/qs`) -->
<Context path="/qshome" docBase="qs" reloadable="true" />
</Host>
</Engine>
</Service>
<!-- 自定义`Service` -->
<Service name="qs">
<!-- 自定义 -->
</Service>
</Server>
# 启动`Tomcat`
./bin/catalina.sh start
# 停止`Tomcat`
./bin/catalina.sh stop
# 从新加载配置
./bin/catalina.sh configtest
# 远程关闭`Tomcat`
telnet 127.0.0.1 8005
SHUTDOWN
- http://127.0.0.1:8080:访问
$TOMCAT_HOME/webapps/ROOT
目录。- http://127.0.0.1:8081:访问
$TOMCAT_HOME/webapps/ROOT
目录。- http://www.qs.com:8080:访问
E:/root/tomcat/ROOT
目录。- http://www.qs.com:8080/qs:访问
E:/root/tomcat/qs
目录。- http://www.qs.com:8080/qshome:访问
E:/root/tomcat/qs
目录。- http://www.qs.com:8080/wy:访问
E:/root/tomcat/wy
目录。
<!-- `E:\root\tomcat\ROOT.xml` -->
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/wy" docBase="E:/root/tomcat/wy" reloadable="true" />
<!-- `E:\java\tomcat\apache-tomcat-learn\conf\Catalina\www.qs.com\wyb.xml` -->
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/wyb" docBase="E:/root/tomcat/wy" reloadable="true" />
- http://www.qs.com:8080/wyb:访问
E:/root/tomcat/wy
目录。
四、Tomcat 脚本
- 手动部署
war
项目。
- 复制
war
包至Tomcat_Home.webapps
目录。- 执行
starut.bat
脚本启动。- 启动过程中
war
包会被自动解压装载。
- 在 Eclipse 或 Idea 中,启动 WEB 项目的时候。
- 也是把
war
包复制到webapps
目录解压吗?
- 显然不是,真正做法是在 Tomcat 程序文件之外,创建了一个 部署目录。
- 在生产环境中也是这么做的,即:Tomcat 程序目录 和 部署目录 是分开 。
- 只需要在启动时,指定
CATALINA_HOME
与CATALINA_BASE
参数即可实现。
启动参数 | 描述说明 |
---|---|
JAVA_OPTS | JVM 启动参数,设置内存、编码等(-Xms100m 堆内存最小值、-Xmx200m 、-Dfile.encoding=UTF-8 编码) |
JAVA_HOME | 指定 JDK 目录,如果未设置从 Java 环境变量当中去找 |
CATALINA_HOME | Tomcat 程序根目录 |
CATALINA_BASE | 应用部署目录(默认为:$CATALINA_HOME ) |
CATALINA_OUT | 应用日志输出目录(默认:$CATALINA_BASE/log ) |
CATALINA_TMPDIR | 应用临时目录(默认:$CATALINA_BASE/temp ) |
1. 启动停止脚本
mkdir /root/qs
cd /root/qs
cp -r /root/apache-tomcat-8/conf /root/qs/
mkdir logs
mkdir weebapps
tomcat.sh
#!/bin/bash
export JAVA_OPTS="-Xms100m -Xmx200m"
export JAVA_HOME=/root/jdk/
# 采用软连接`/root/apache-tomcat`指向`/root/apache-tomcat-8`
#export CATALINA_HOME=/root/apache-tomcat-8
export CATALINA_HOME=/root/apache-tomcat
# `pwd`当前脚本目录`/root/qs`
export CATALINA_BASE="`pwd`"
case $1 in
start)
$CATALINA_HOME/bin/catalina.sh start
echo start success!!
;;
stop)
$CATALINA_HOME/bin/catalina.sh stop
echo stop success!!
;;
restart)
$CATALINA_HOME/bin/catalina.sh stop
echo stop success!!
sleep 3
$CATALINA_HOME/bin/catalina.sh start
echo start success!!
;;
version)
$CATALINA_HOME/bin/catalina.sh version
;;
configtest)
$CATALINA_HOME/bin/catalina.sh configtest
;;
esac
exit 0
./tomcat start
./tomcat stop
./tomcat restart
./tomcat version
./tomcat configtest
2. 自动部署脚本
deploy.sh
#!/bin/bash -e
export now_time=$(date +%Y-%m-%d_%H-%M-%S)
echo "deploy time:$now_time"
app=$1
version=$2
mkdir -p war/
# 从`SVN`下载程序至`war`目录
war=war/${app}_${version}.war
echo "$war"
svn export svn://192.168.0.147/release/${app}_${version}.war $war
deploy_war() {
# 解压版本至当前目录
target_dir=war/${app}_${version}_${now_time}
unzip -q $war -d $target_dir
rm -f appwar
ln -sf $target_dir appwar
target_ln=`pwd`/appwar
echo '<?xml version="1.0" encoding="UTF-8" ?>
<Context docBase="'$target_ln'" allowLinking="false">
</Context>' > conf/Catalina/localhost/ROOT.xml
# 重启`Tomcat`服务
./tomcat.sh restart
}
# 部署`war`
deploy_war
./deploy.sh qs v1.0
./deploy.sh qs v2.0
# 版本回滚
rm -rf appwar
lb -s war/qs_v1.0_2022-04-14_10-20-30/
./tomcat.sh restart
五、Spring Boot 配置
server:
tomcat:
uri-encoding: UTF-8
# 最大工作线程数(默认:200)
# 操作系统做线程之间的切换调度是有系统开销的,所以不是越多越好。
max-threads: 1000
# 等待队列长度(默认:100)
accept-count: 1000
max-connections: 20000
# 最小工作空闲线程数(默认10)适当增大一些,以便应对突然增长的访问量
min-spare-threads: 100