Tomcat

安装Tomcat

JDK https://www.oracle.com/java/technologies/downloads/archive/OpenJDK https://jdk.java.net/21/ 或 https://learn.microsoft.com/zh-cn/java/openjdk/downloadTomcat https://tomcat.apache.org/注意:Tomcat/conf/startup.sh 配置文件错误时不会报错。Tomcat/conf/shutdown.sh 重复关闭时会报错。

// 安装Tomcat

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

]# ls apache-tomcat-8.0.30.tar.gz

apache-tomcat-8.0.30.tar.gz

]# yum install -y java-1.8.0-openjdk-devel // Tomcat使用Java开发,依赖包含java-1.8.0-openjdk

]# tar -xf apache-tomcat-8.0.30.tar.gz

]# mv apache-tomcat-8.0.30 /usr/local/tomcat // 解压即用

]# cd /usr/local/tomcat

tomcat]# bin/startup.sh // 配置文件错误时不会报错,需手动检验是否成功开启

tomcat]# ss -ntulp | grep java

tcp LISTEN 0 100 *:8080 *:* users:(("java",pid=1424,fd=48)) // HTTP端口

tcp LISTEN 0 1 [::ffff:127.0.0.1]:8005 *:* users:(("java",pid=1424,fd=78)) // 关闭服务端口

tcp LISTEN 0 100 *:8009 *:* users:(("java",pid=1424,fd=53)) // AJP端口

// Tomcat启动需要从/dev/random读取大量的随机数据,若启动速度较慢,可以创建软连接`ln -s /dev/urandom /dev/random`,否则可能由于/dev/random随机数据不足而导致的虽然监听端口但无法正常提供服务

tomcat]# mv /dev/random{,.ori}

tomcat]# ln -s /dev/urandom /dev/random

tomcat]# bin/shutdown.sh

tomcat]# bin/startup.sh

tomcat]# ls

bin conf lib LICENSE logs NOTICE RELEASE-NOTES RUNNING.txt temp webapps work

tomcat]# bin/version.sh

Using CATALINA_BASE: /usr/local/tomcat

Using CATALINA_HOME: /usr/local/tomcat

Using CATALINA_TMPDIR: /usr/local/tomcat/temp

Using JRE_HOME: /usr

Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar

Server version: Apache Tomcat/8.0.30

Server built: Dec 1 2015 22:30:46 UTC

Server number: 8.0.30.0

OS Name: Linux

OS Version: 4.18.0-372.9.1.el8.x86_64

Architecture: amd64

JVM Version: 1.8.0_332-b09

JVM Vendor: Red Hat, Inc.

tomcat]# java -version

openjdk version "1.8.0_332"

OpenJDK Runtime Environment (build 1.8.0_332-b09)

OpenJDK 64-Bit Server VM (build 25.332-b09, mixed mode)

tomcat]# cp conf/server.xml{,.default}

systemd.service

https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html

// 创建tomcat.service

// 情况一:YUM安装jdk或openjdk

[root@tomcat ~]# which java

/usr/bin/java

[root@tomcat ~]# cat /usr/lib/systemd/system/tomcat.service

#/usr/lib/systemd/system/tomcat.service

[Unit]

Description=Tomcat Service

After=network-online.target remote-fs.target nss-lookup.target

Wants=network-online.target

[Service]

Type=forking

ExecStart=/usr/local/tomcat/bin/startup.sh

ExecStop=/usr/local/tomcat/bin/shutdown.sh

ExecReload=/usr/local/tomcat/bin/startup.sh && sleep 2 && /usr/local/tomcat/bin/shutdown.sh

[Install]

WantedBy=multi-user.target

[root@tomcat ~]# systemctl daemon-reload

// 情况二:自定义安装jdk或openjdk

[root@tomcat ~]# tar -xf jdk-8u361-linux-x64.tar.gz

[root@tomcat ~]# ln -s /root/jdk1.8.0_361/ /usr/local/jdk

[root@tomcat ~]# cat /etc/sysconfig/tomcat

JAVA_HOME=/usr/local/jdk

PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:${JAVA_HOME}/bin:${JAVA_HOME}/jre/bin

CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar

[root@tomcat ~]# cat /usr/lib/systemd/system/tomcat.service

#/usr/lib/systemd/system/tomcat.service

[Unit]

Description=Tomcat Service

After=network-online.target remote-fs.target nss-lookup.target

Wants=network-online.target

[Service]

Type=forking

EnvironmentFile=/etc/sysconfig/tomcat

ExecStart=/usr/local/tomcat/bin/startup.sh

ExecStop=/usr/local/tomcat/bin/shutdown.sh

ExecReload=/usr/local/tomcat/bin/startup.sh && sleep 2 && /usr/local/tomcat/bin/shutdown.sh

[Install]

WantedBy=multi-user.target

[root@tomcat ~]# systemctl daemon-reload

// 验证

[root@tomcat ~]# systemctl enable tomcat.service --now

Created symlink /etc/systemd/system/multi-user.target.wants/tomcat.service → /usr/lib/systemd/system/tomcat.service.

[root@tomcat ~]# ss -ntulp |grep java

tcp LISTEN 0 1 [::ffff:127.0.0.1]:8005 *:* users:(("java",pid=1734,fd=77))

tcp LISTEN 0 100 *:8009 *:* users:(("java",pid=1734,fd=53))

tcp LISTEN 0 100 *:8080 *:* users:(("java",pid=1734,fd=48))

注意:使用systemctl启动的不能使用路径关闭,使用路径启动的不能使用systemctl关闭

管理端网页

// 设置管理端网页。但生产环境中为安全一般禁用

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

浏览器访问 http://192.168.88.88:8080

可以通过Server Status、Manager App、Host Manager管理Tomcat

Tomcat 8.5以后,默认只能本地环回地址访问127.0.0.1

// 开启功能并设置用户密码

[root@tomcat tomcat]# vim conf/tomcat-users.xml // 管理网页配置文件

39 # 开启功能

40 # 开启功能

41 # 设置用户密码

42

[root@tomcat tomcat]# bin/shutdown.sh

[root@tomcat tomcat]# bin/startup.sh

// Tomcat 8.5默认限制管理端的访问IP

[root@tomcat tomcat]# curl -u tomcat:tomcat http://127.0.0.1:8080/manager/status

[root@tomcat tomcat]# curl -u tomcat:tomcat http://127.0.0.1:8080/host-manager/html

[root@tomcat tomcat]# curl -u tomcat:tomcat http://127.0.0.1:8080/host-manager/html // 403

// 修改访问IP的限制,不是Tomcat的配置文件所以修改后不用重启服务

[root@tomcat tomcat]# find . -name context.xml

./conf/context.xml

./webapps/host-manager/META-INF/context.xml

./webapps/manager/META-INF/context.xml

[root@tomcat tomcat]# less webapps/host-manager/META-INF/context.xml

allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /># 8.5版本之后限制只能通过127.0.0.1访问

[root@tomcat tomcat]# less webapps/manager/META-INF/context.xml

allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /># 8.5版本之后限制只能通过127.0.0.1访问

[root@tomcat tomcat]# sed -i 's,"127,"\\d,' webapps/host-manager/META-INF/context.xml webapps/manager/META-INF/context.xml

[root@tomcat tomcat]# curl -u tomcat:tomcat http://127.0.0.1:8080/host-manager/html // 正常

// 生产环境中禁用管理端网页

[root@tomcat tomcat]# vim conf/server.xml // 注释或删除conf/tomcat-users.xml相关的配置

[root@tomcat tomcat]# bin/shutdown.sh

[root@tomcat tomcat]# bin/startup.sh

[root@tomcat tomcat]# curl -u tomcat:tomcat http://127.0.0.1:8080/host-manager/html // 404

主配置文件server.xml

[root@tomcat tomcat]# cat conf/server.xml # 去除注释之后的有效内容

#

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" />

connectionTimeout="20000"

redirectPort="8443" />

resourceName="UserDatabase"/>

unpackWARs="true" autoDeploy="true">

prefix="localhost_access_log" suffix=".txt"

pattern="%h %l %u %t "%r" %s %b" />

8005是shutdown端口:`telnet 127.0.0.1 8005`后输入SHUTDOWN

8080是HTTP端口

8443是HTTPS端口,默认关闭

8009是AJP端口,用于tomcat和apache的交互,8.5版本后默认关闭

Tomcat处理用户请求的流程:

用户发出请求——》请求达到Tomcat——》处理http请求——》交给的虚拟主机处理——》处理完成返回给用户

日志格式

访问日志内容的格式TomcatNginx客户端IP地址%h$remote_addr用户名%l用户名%u日期和时间%t$local_time用户请求的起始行(请求方法和URI)%r$request状态码%s$status服务端响应的大小%b$body_bytes_sent用户从哪里跳转来的%{Referer}i$http_referer用户的客户端%{User-Agent}i$http_user_agent用户的真实IP地址%{X-Forwarded-For}i$http_x_forwarded_for

虚拟主机

中的 中的参数:

name:虚拟主机名称,也是域名。appBase:网页目录。unpackWARs:是否自动解WAR包,默认为true。autoDeploy:是否自动部署,默认为true。 注意:如果配置了[降权启动](# 降权启动(监牢模式)),那么要修改数据的所有者所属组。

// 虚拟主机

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

// 配置

[root@tomcat tomcat]# cp server.xml{.default,}

[root@tomcat tomcat]# vim conf/server.xml // 在添加两个虚拟主机

unpackWARs="true" autoDeploy="true">

prefix="localhost_access_log" suffix=".txt"

pattern="%h %l %u %t "%r" %s %b" />

unpackWARs="true" autoDeploy="true">

prefix="test_access_log" suffix=".log"

pattern="%h %l %u %t "%r" %s %b" />

unpackWARs="true" autoDeploy="true">

prefix="test_access_log" suffix=".log"

pattern="%h %l %u %t "%r" %s %b" />

[root@tomcat tomcat]# bin/shutdown.sh > /dev/null

[root@tomcat tomcat]# bin/startup.sh > /dev/null

// 创建index.jsp。注意:如果部署了降权启动(假设运行用户为tomcat),那么要修改数据的所有者所属组

[root@tomcat tomcat]# mkdir -p test_{a,b}/ROOT

[root@tomcat tomcat]# mkdir test_logs

[root@tomcat tomcat]# echo 'test_a~~' > test_a/ROOT/index.jsp

[root@tomcat tomcat]# echo 'test_b~~' > test_b/ROOT/index.jsp

注意:如果部署了降权启动(假设运行用户为tomcat),那么要修改数据的所有者所属组

// 验证

客户端(192.168.88.5):

[root@client ~]# echo '192.168.88.88 www.a.com www.b.com' >> /etc/hosts

[root@client ~]# curl www.a.com:8080

test_a~~

[root@client ~]# curl www.b.com:8080

test_b~~

[root@tomcat tomcat]# cat test_logs/test_access_log.2023-10-25.log

192.168.88.5 - - [25/Oct/2023:18:58:41 +0800] "GET / HTTP/1.1" 200 9

192.168.88.5 - - [25/Oct/2023:18:58:45 +0800] "GET / HTTP/1.1" 200 9

访问路径

注意:如果配置了[降权启动](# 降权启动(监牢模式)),那么要修改数据的所有者所属组。 中的 中的属性 appBase 的使用:

不定义appBase,指向 Tomcat/webappsappBase="",指向 Tomcat/appBase="相对路径",指向 Tomcat/相对路径appBase="绝对路径",指向 绝对路径/

属性appBase不使用IP地址:8080IP地址:8080/test/,这里test是目录IP地址:8080/test,这里test是文件不定义,为webappswebapps/ROOT/index.jspwebapps/test/index.jspwebapps/ROOT/test空 ""ROOT/index.jsptest/index.jspROOT/test相对路径 "app"app/ROOT/index.jspapp/test/index.jspapp/ROOT/test绝对路径 "/app"/app/ROOT/index.jsp/app/test/index.jsp/app/ROOT/test

中的 中的

属性 path(精确匹配,支持*和?)的使用:只有当客户端访问的URI匹配path时,才配置生效

path的值可以为空"",也可以为"/路径"(必须以/开头且不能以/结尾) - 当path为空""时,可以不定义docBase。此时,只有匹配不含目录的URI,才配置生效

当path不为空"/路径"时,就必须定义docBase。此时,只有URI匹配"/路径"时,才配置生效 定义了appBase,就必须定义path。即,在中,属性path是必须的。 path=""时,只匹配不含目录的URI。

属性path(假设appBase=“app”)属性docBaseIP地址:8080IP地址:8080/test,这里test是文件IP地址:8080/test/,这里test是目录IP地址:8080/test/abc,path=""不匹配包含目录的URI空 ""不定义,为ROOTapp/ROOT/index.jspapp/ROOT/testapp/test/index.jspapp/test/abc空 ""空 ""app/index.jspapp/testapp/test/index.jspapp/test/abc空 ""相对路径 "doc"app/doc/index.jspapp/doc/testapp/test/index.jspapp/test/abc空 ""绝对路径 "/doc"/doc/index.jsp/doc/testapp/test/index.jspapp/test/abc

path="/字符串A"时,字符串匹配URI。

属性path(假设appBase=“app”)属性docBaseIP地址:8080/pa/IP地址:8080/pa/test/,这里test是目录IP地址:8080/pa/test,这里test是文件绝对路径 "/pa"空 ""app/index.jspapp/test/index.jspapp/test绝对路径 "/pa"相对路径 "doc"app/doc/index.jspapp/doc/test/index.jspapp/doc/test绝对路径 "/pa"绝对路径 "/doc"/doc/index.jsp/doc/test/index.jsp/doc/test

// 访问路径

appBase的使用:

- 不定义appBase,指向 Tomcat/webapps

- appBase="",指向 Tomcat/

- appBase="相对路径",指向 Tomcat/相对路径

- appBase="绝对路径",指向 绝对路径

path(精确匹配,支持*和?)的使用:只有当客户端访问的URI匹配path时,才配置生效

- path的值可以为空"",也可以为"/路径"(必须以`/`开头且不能以`/`结尾)

org.apache.catalina.core.StandardContext.setPath A context path must either be an empty string or start with a '/' and do not end with a '/'.

- 当path为空""时,可以不定义docBase。此时,只有匹配不含目录的URI, 才生效。

- 当path不为空"/路径"时,就必须定义docBase。此时,只有URI匹配"/路径"时, 才生效。

- 定义了appBase,就必须定义path。

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

// 配置

[root@tomcat tomcat]# \cp server.xml{.default,}

[root@tomcat tomcat]# vim conf/server.xml // 配置虚拟主机localhost、tapp{,0,1,2}、tpa{,0,1,2}、tth{0,1,2}

unpackWARs="true" autoDeploy="true">

prefix="localhost_access_log" suffix=".txt"

pattern="%h %l %u %t "%r" %s %b" />

# tapp:8080 ——》webapps/ROOT/index.jsp

# tapp0:8080 ——》ROOT/index.jsp

# tapp1:8080 ——》app/ROOT/index.jsp

# tapp2:8080 ——》/app/ROOT/index.jsp

# tpa:8080 ——》app/ROOT/index.jsp

# tpa0:8080 ——》app/index.jsp

# tpa1:8080 ——》app/doc/index.jsp

# tpa2:8080 ——》/doc/index.jsp

# tth0:8080/pa/ ——》app/index.jsp,tth0:8080/pa/test/ ——》app/test/index.jsp

# tth1:8080/pa/ ——》app/doc/index.jsp,tth1:8080/pa/test/ ——》app/doc/test/index.jsp

# tth2:8080/pa/ ——》/doc/index.jsp,tth2:8080/pa/test/ ——》/doc/test/index.jsp

[root@tomcat tomcat]# systemc restart tomcat.service

// 创建index.jsp。注意:如果部署了降权启动(假设运行用户为tomcat),那么要修改数据的所有者所属组

[root@tomcat tomcat]# mkdir -p ROOT

[root@tomcat tomcat]# mkdir -p app/{ROOT,doc}

[root@tomcat tomcat]# mkdir -p /app/ROOT

[root@tomcat tomcat]# mkdir -p /doc/ROOT

[root@tomcat tomcat]# echo 'webapps/ROOT/index.jsp' > webapps/ROOT/index.jsp

[root@tomcat tomcat]# echo 'ROOT/index.jsp' > ROOT/index.jsp

[root@tomcat tomcat]# echo 'app/index.jsp' > app/index.jsp

[root@tomcat tomcat]# echo 'app/ROOT/index.jsp' > app/ROOT/index.jsp

[root@tomcat tomcat]# echo 'app/doc/index.jsp' > app/doc/index.jsp

[root@tomcat tomcat]# echo '/app/ROOT/index.jsp' > /app/ROOT/index.jsp

[root@tomcat tomcat]# echo '/doc/index.jsp' > /doc/index.jsp

[root@tomcat tomcat]# echo '/doc/ROOT/index.jsp' > /doc/ROOT/index.jsp

[root@tomcat tomcat]# mkdir app/test app/doc/test /doc/test

[root@tomcat tomcat]# echo 'app/test/index.jsp' > app/test/index.jsp

[root@tomcat tomcat]# echo 'app/doc/test/index.jsp' > app/doc/test/index.jsp

[root@tomcat tomcat]# echo '/doc/test/index.jsp'> /doc/test/index.jsp

客户端:

[root@client ~]# echo '192.168.88.88 tapp tapp0 tapp1 tapp2' >> /etc/hosts

[root@client ~]# echo '192.168.88.88 tpa tpa0 tpa1 tpa2' >> /etc/hosts

[root@client ~]# echo '192.168.88.88 tth0 tth1 tth2' >> /etc/hosts

[root@client ~]# curl 192.168.88.88:8080

app/ROOT/index.jsp

// 1.验证appBase的使用

[root@client ~]# curl tapp:8080

app/ROOT/index.jsp

[root@client ~]# curl tapp0:8080

ROOT/index.jsp

[root@client ~]# curl tapp1:8080

webapps/ROOT/index.jsp

[root@client ~]# curl tapp2:8080

/app/ROOT/index.jsp

// 2.验证path=""

[root@client ~]# curl tpa:8080

app/ROOT/index.jsp

[root@client ~]# curl tpa0:8080

app/index.jsp

[root@client ~]# curl tpa1:8080

app/doc/index.jsp

[root@client ~]# curl tpa2:8080

/doc/index.jsp

// 3.验证path="/pa"

// 3.1.不匹配path则不生效

[root@client ~]# curl tth0:8080

app/ROOT/index.jsp

[root@client ~]# curl tth1:8080

app/ROOT/index.jsp

[root@client ~]# curl tth2:8080

app/ROOT/index.jsp

// 3.2.匹配path时才生效。注意:以`/`结尾则默认为目录,返回该目录下的index.jsp。没有以`/`结尾则为文件,返回该文件。

// 3.2.1.以`/`结尾则默认为目录,返回该目录下的index.jsp

[root@client ~]# curl tth0:8080/pa/

app/index.jsp

[root@client ~]# curl tth1:8080/pa/

app/doc/index.jsp

[root@client ~]# curl tth2:8080/pa/

/doc/index.jsp

[root@client ~]# curl tth0:8080/pa/test/

app/test/index.jsp

[root@client ~]# curl tth1:8080/pa/test/

app/doc/test/index.jsp

[root@client ~]# curl tth2:8080/pa/test/

/doc/test/index.jsp

// 3.2.2.没有以`/`结尾则为文件,返回该文件。

[root@client ~]# curl tth0:8080/pa

[root@client ~]# curl tth1:8080/pa

[root@client ~]# curl tth2:8080/pa

[root@client ~]# curl tth0:8080/pa/test

[root@client ~]# curl tth1:8080/pa/test

[root@client ~]# curl tth2:8080/pa/test

SSL

// SSL(https,8443)

keytool -genkeypair -alias 密钥对别名 -keyalg RSA -keystore 密钥库文件

* keytool命令由jdk提供

* 选项-genkeypair是keytool的选项,用于生成密钥对并存储在密钥库文件中

* 选项-alias是-genkeypair的子选项,定义密钥对别名

* 选项-keyalg是-genkeypair的子选项,指定生成密钥对使用的算法

* 选项-keystore是-genkeypair的子选项,指定存储密钥对的密钥库文件

注意:一个密钥库文件中可以有多个密钥对。

在配置Tomcat的SSL时,

必须:关键字keystoreFile指定密钥库文件,关键字keystorePass指定密钥库文件密码

选用:关键字keyAlias指定密钥库文件中的密钥对(省略默认为第一个密钥对),关键字keyPass指定密钥对密码(省略默认同keystorePass)

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

// 创建密钥对

[root@tomcat tomcat]# keytool -genkeypair -alias testkey -keyalg RSA -keystore key

Enter keystore password: // 设置密钥库文件密码

Re-enter new password: // 重复密码

What is your first and last name?

[Unknown]: xingming

What is the name of your organizational unit?

[Unknown]: gongsi

What is the name of your organization?

[Unknown]: bumen

What is the name of your City or Locality?

[Unknown]: shi

What is the name of your State or Province?

[Unknown]: sheng

What is the two-letter country code for this unit?

[Unknown]: zh

Is CN=xingming, OU=gongsi, O=bumen, L=shi, ST=sheng, C=zh correct?

[no]: y

Enter key password for // 设置密钥对密码,回车同密钥库文件密码

(RETURN if same as keystore password):

Re-enter new password: // 重复密码

Warning:

The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore key -destkeystore key -deststoretype pkcs12".

// 配置Tomcat

[root@tomcat tomcat]# echo 'webapps/ROOT/index.jsp' > webapps/ROOT/index.jsp

[root@tomcat tomcat]# \cp conf/server.xml.default conf/server.xml

[root@tomcat tomcat]# vim conf/server.xml

85

86 maxThreads="150" SSLEnabled="true" scheme="https" secure="true"

87 clientAuth="false" sslProtocol="TLS"

88 keystoreFile="/usr/local/tomcat/key" // keystoreFile指定密钥库文件位置,相对路径是Tomcat/

89 keystorePass="123456" // keystorePass指定密钥库文件密码

90 keyAlias="testkey" // keyAlias指定密钥库文件中的密钥对,省略默认为第一个密钥对

91 keyPass="123456" />// keyPass指定密钥对密码,省略默认同密钥库文件密码

[root@tomcat tomcat]# systemctl restart tomcat.service

客户端:

[root@client ~]# curl -k https://192.168.88.88:8443

webapps/ROOT/index.jsp

解析动态网站

// 解析动态网站

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

浏览器访问 https://www.zrlog.com/ 下载war包

[root@tomcat tomcat]# ls ~/zrlog-2.2.1-efbe9f9-release.war

/root/zrlog-2.2.1-efbe9f9-release.war

[root@tomcat tomcat]# cp ~/zrlog-2.2.1-efbe9f9-release.war webapps/zrlog.war

[root@tomcat tomcat]# ss -ntulp | grep 8080

tcp LISTEN 0 100 *:8080 *:* users:(("java",pid=1460,fd=48))

[root@tomcat tomcat]# ls webapps/

docs examples host-manager manager ROOT zrlog zrlog.war

浏览器访问 http://192.168.88.88:8080/zrlog/,跳转 http://192.168.88.88:8080/zrlog/install/ 选择数据库并安装使用。论坛的文章存储在数据库,图片存储在本地网页目录

Tomcat多实例

// 多实例,在一台服务器运行多个tomcat服务,通过端口区分服务

nginx需要安装使用,可以通过导入配置文件来配置管理多个网站。Tomcat直接解压即用,可以在配置文件中配置多个网站,也可以直接通过多实例来配置管理多个网站。

Tomcat中配置多个虚拟主机:共享一个Tomcat进程和线程池,集中管理维护,共同启动停止。

Tomcat多实例:每一个Tomcat实例启动一个独立的进程和线程池,管理和维护相对独立,单独启动、停止。

// 思路

Tom多实例:已经部署好webapps/zrlog

1.共用jdk环境

2.复制多份tomcat并修改每个tomcat的端口(8080,8005,8443):tomcat_8081 tomcat_8082

3.指定不同的代码目录(推荐每个代码放在tomcat 默认的webapps/ROOT)

tomcat

conf/server.xml(8080,8005)

webapps/zrlog

tomcat_8081

conf/server.xml(8081,8006)

webapps/zrlog

tomcat_8082

conf/server.xml(8082,8007)

webapps/zrlog

// 部署

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

[root@tomcat ]# cd /usr/local

[root@tomcat local]# cp -r tomcat/ tomcat_8081

[root@tomcat local]# cp -r tomcat/ tomcat_8082

[root@tomcat local]# sed -i 's#8080#8081#g' tomcat_8081/conf/server.xml

[root@tomcat local]# sed -i 's#8005#8006#g' tomcat_8081/conf/server.xml

[root@tomcat local]# sed -i 's#8080#8082#g' tomcat_8082/conf/server.xml

[root@tomcat local]# sed -i 's#8005#8007#g' tomcat_8082/conf/server.xml

[root@tomcat local]# grep -P 'port="\d+"' tomcat_808*/conf/server.xml

tomcat_8081/conf/server.xml:

tomcat_8081/conf/server.xml:

tomcat_8082/conf/server.xml:

tomcat_8082/conf/server.xml:

[root@tomcat local]# tomcat/bin/startup.sh

[root@tomcat local]# tomcat_8081/bin/startup.sh

[root@tomcat local]# tomcat_8082/bin/startup.sh

此时,在192.168.88.88:8080/zrlog/、192.168.88.88:8081/zrlog/、192.168.88.88:8082/zrlog/ 上发表文章,文字存储在同一数据库,图片存储在Tomcat本地目录,可以使用挂载存储服务器,实现静态数据的一致。

监控Java应用

// 监控Java应用

// 命令行工具(由openjdk-devel或jdk-devel提供)

jps -lvm

jmap PID :查看jvm信息、内存信息

jstack PID :查看进程信息

jstat -gc PID :查看进程信息

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

[root@tomcat ~]# jps

2018 Bootstrap

2613 Jps

[root@tomcat ~]# jps -l

2625 sun.tools.jps.Jps

2018 org.apache.catalina.startup.Bootstrap

[root@tomcat ~]# jps -lv

2018 org.apache.catalina.startup.Bootstrap -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp

2637 sun.tools.jps.Jps -Dapplication.home=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el8_5.x86_64 -Xms8m

[root@tomcat ~]# jps -lvm

2018 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp

2649 sun.tools.jps.Jps -lvm -Dapplication.home=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el8_5.x86_64 -Xms8m

[root@tomcat ~]# jstat -gc 2018

[root@tomcat ~]# jstack 2018

[root@tomcat ~]# jmap 2018

// 图形工具

jconsole

jvisualvm

CATALINA_OPTS="$CATALINA_OPTS \

-Dcom.sun.management.jmxremote \ # jmxremote 开启功能

-Dcom.sun.management.jmxremote.port=12345 \ # 指定端口号 12345固定端口 +2个随机端口

-Dcom.sun.management.jmxremote.authenticate=false \ # 是否开启认证功能,一般使用内网访问无需认证

-Dcom.sun.management.jmxremote.ssl=false \ # 是否启用ssl,一般使用内网访问无需ssl

-Djava.rmi.server.hostname=内网IP地址" # 监听的IP,选择内网IP,使用内网访问

Tomcat服务器(192.168.88.88,Tomcat目录为/usr/local/tomcat):

[root@tomcat tomcat]# bin/catalina.sh // 注释行后增加六行

CATALINA_OPTS="$CATALINA_OPTS \

-Dcom.sun.management.jmxremote \

-Dcom.sun.management.jmxremote.port=12345 \

-Dcom.sun.management.jmxremote.authenticate=false \

-Dcom.sun.management.jmxremote.ssl=false \

-Djava.rmi.server.hostname=192.168.88.88"

[root@tomcat tomcat]# ss -ntulp | grep 12345

tcp LISTEN 0 50 *:12345 *:* users:(("java",pid=3010,fd=22))

开发在Windows找到jconsole或jvisualvm所在的路径,运行后使用连接192.168.88.88的12345端口

故障案例

开启自启失败或定时任务重启失败

Tomcat没有创建systemd.service,而是通过在/etc/rc.d/rc.local写入手动启动的命令`Tomcat目录/bin/startup.sh`,开机后Tomcat没有运行。

可能原因:如果JDK不是通过YUM安装的,而是手动安装后自定义PATH,则系统开机或定时任务运行时不会加载自定义的PATH路径,无法检测到JDK,因而无法启动Tomcat

解决方法一:YUM安装JDK

解决方法二:将自定义PATH写入脚本(开机运行的/etc/rc.d/rc.local,或定时任务的自定义脚本),让系统识别JDK后再启动Tomcat

服务器运行时占用大量swap,内存占用较少

服务器运行时占用大量swap,占用物理内存较少

原因:代码问题,需要查看并修改程序代码

临时解决:临时增大swap以免服务器宕机,再通过调整内核参数使系统优先使用物理内存

[root@tomcat ~]# echo 'vm.swappiness = 0' >> /etc/sysctl.conf // vm.swappiness是swap亲和性,越大越优先使用swap,越小越优先使用内存

[root@tomcat ~]# sysctl -p

高负载排查

高负载情况的排查命令1.整体排查,找到出问题的进程PIDps aux或top2.查看问题进程下的线程负载情况,找到出问题的线程PIDtop -Hp 线程PID3.将线程的PID转换为十六进制的NID`echo ‘obase=16;线程PID’4.查看问题进程的详细信息,过滤具体的线程`jstack 进程PID5.查看jvm的内存使用情况jmap -heap 进程PID6.导出jvm的内存使用情况jmap -dump:format=b,file=/root/tomcatjvm.bin 进程PID7.将导出文件给开发人员开发人员通过Windows的mat软件(Eclipse Memory Analyzer Tool)分析

// 高负载排查

// 1.整体排查,找到出问题的进程PID

[root@tomcat ~]# top 或 ps aux // 假设高负载的是Tomcat604

……省略一万字

[root@tomcat ~]# jps // 如果确定是java的进程也可以通过jps查看PID

744 Jps

604 Bootstrap

// 2.查看问题进程下的线程负载情况,找到出问题的线程PID

[root@tomcat ~]# top -Hp 604 // 假设高负载的是线程605

……省略一万字

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

604 root 20 0 2937200 250820 18700 S 0.0 12.7 0:00.00 java

605 root 20 0 2937200 250820 18700 S 80.0 12.7 0:00.55 java

……省略一万字

// 3.线程的PID转换为十六进制的NID

[root@tomcat ~]# yum install -y bc

[root@tomcat ~]# echo 'obase=16;605' | bc // jstack中的线程PID是十六进程的NID

25D

// 4.查看问题进程的详细信息,过滤具体的线程

[root@tomcat ~]# jstack 604

……省略一万字

"main" #1 prio=5 os_prio=0 tid=0x00007f59b404d800 nid=0x25d runnable [0x00007f59bb59f000]

java.lang.Thread.State: RUNNABLE

at java.net.PlainSocketImpl.socketAccept(Native Method)

at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)

at java.net.ServerSocket.implAccept(ServerSocket.java:560)

at java.net.ServerSocket.accept(ServerSocket.java:528)

……省略一万字

[root@tomcat ~]# jstack 604| grep -i -A2 25D // 过滤进程信息中的线程信息

"main" #1 prio=5 os_prio=0 tid=0x00007f59b404d800 nid=0x25d runnable [0x00007f59bb59f000]

java.lang.Thread.State: RUNNABLE

at java.net.PlainSocketImpl.socketAccept(Native Method)

// 5.查看jvm的内存使用情况

[root@tomcat ~]# jmap -heap 604

Attaching to process ID 604, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 25.332-b09

using thread-local object allocation.

Parallel GC with 2 thread(s)

Heap Configuration:

……省略一万字

Heap Usage:

……省略一万字

11209 interned Strings occupying 961752 bytes.

// 6.导出jvm的内存使用情况

[root@tomcat ~]# jmap -dump:format=b,file=/root/tomcatjvm.bin 604

Dumping heap to /root/tomcatjvm.bin ...

Heap dump file created

[root@tomcat ~]# ll /root/tomcatjvm.bin

-rw------- 1 root root 120920576 Oct 26 16:52 /root/tomcatjvm.bin

[root@tomcat ~]# file /root/tomcatjvm.bin

/root/tomcatjvm.bin: Java HPROF dump, created Thu Oct 26 08:52:57 2023

// 7.将导出文件给开发人员,开发人员通过Windows的mat软件(Eclipse Memory Analyzer Tool)分析

Tomcat优化

安全优化

修改shutdown端口

[root@tomcat tomcat]# vim conf/server.xml

# 修改前

# 修改后

修改AJP端口

[root@tomcat tomcat]# vim conf/server.xml

# 修改前 // 8.5起已经被注释

禁用管理端

// 注释或删除server.xml中关于管理端的配置

[root@tomcat tomcat]# vim conf/server.xml

[root@tomcat tomcat]# systemctl restart tomcat.service

// 删除管理端的相关文件

[root@tomcat tomcat]# rm -rf webapps/host-manager

[root@tomcat tomcat]# rm -rf webapps/manager

降权启动(监牢模式)

linux中 1-1024是特权端口,只能root管理与运行,因此如果nginx要使用非root启动则需要修改监听端口。

让普通用户启动和运行服务:

1.root关闭tomcat

2.修改tomcat目录的所有者所属组

3.授权用户使用systemctl重启tomcat

4.修改systemctl的运行用户

5.如果不配置3、4,也可以使用路径启动关闭服务

// 1.root关闭tomcat,根据对应的启动方式关闭

[root@tomcat ~]# systemctl stop tomcat.service

[root@tomcat ~]# /usr/local/tomcat/bin/shutdown.sh

[root@tomcat ~]# ss -ntulp | grep 8080

[root@tomcat ~]# jps

1426 Jps

// 2.修改tomcat目录的所有者所属组

[root@tomcat ~]# useradd tomcat

[root@tomcat ~]# chown -R tomcat:tomcat /usr/local/tomcat/

// 3.授权用户使用systemctl重启tomcat

[root@tomcat ~]# visudo // 末尾增加一行

tomcat ALL=(ALL) NOPASSWD:/bin/systemctl restart tomcat

// 4.修改systemctl的运行用户

[root@tomcat ~]# vim /usr/lib/systemd/system/tomcat.service // 在[Service]内增加一行

[Service]

User=tomcat

[root@tomcat ~]# systemctl daemon-reload

// 验证

[root@tomcat ~]# su - tomcat

[tomcat@tomcat ~]$ sudo systemctl restart tomcat.service

[tomcat@tomcat ~]$ ss -ntulp | grep 8080

tcp LISTEN 0 100 *:8080 *:* users:(("java",pid=1630,fd=52))

[tomcat@tomcat ~]$ jps

1660 Jps

1630 Bootstrap

[tomcat@tomcat ~]$ logout

[root@tomcat ~]# systemctl stop tomcat.service

[root@tomcat ~]# ps aux | grep java // 可以看到tomcat运行tomcat

// 如果不配置3、4,也可以使用路径启动关闭服务

[tomcat@tomcat ~]$ /usr/local/tomcat/bin/startup.sh

[tomcat@tomcat ~]$ ss -ntulp | grep 8080

tcp LISTEN 0 100 *:8080 *:* users:(("java",pid=1761,fd=52))

[tomcat@tomcat ~]$ jps

1761 Bootstrap

1791 Jps

隐藏版本信息

与Nginx不同,Tomcat需要手动修改涉及版本信息的所有网页文件

修改响应头信息

[root@tomcat tomcat]# vim conf/server.xml

connectionTimeout="20000"

redirectPort="8443" />

Server="Nginx/1.20.2" // 修改响应头信息

connectionTimeout="20000"

redirectPort="8443" />

[root@tomcat tomcat]# systemctl restart tomcat.service

访问限制

[root@tomcat tomcat]# vim conf/server.xml // path匹配URI

debug="0" reloadable="false" crossContext="true">

allow="61.148.18.138,61.135.165.*" deny="*.*.*.*"/>

[root@tomcat tomcat]# systemctl restart tomcat.service

性能优化

工作模式(io模型)

模式英文含义bioblocking iotomcat 7及之前,同步,阻塞,一个线程处理一个请求,缺点:并发量高时,线程数较多,浪费资源。nionew iotomcat 8及以后,异步,非阻塞,nio1(默认)、 nio2,可以通过少量的线程处理大量的请求aprApache Portable Runtime应对高并发场景 Tomcat对静态文件的处理性能。Tomcat apr也是在Tomcat上运行高并发应用的首选模式

// 查看效果

[root@tomcat tomcat]# vim logs/catalina.out

30-Nov-2021 11:17:14.578 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]

[root@tomcat tomcat]# vim conf/server.xml

connectionTimeout="20000"

redirectPort="8443" />

connectionTimeout="20000"

redirectPort="8443" />

[root@tomcat tomcat]# systemctl restart tomcat.service

禁用DNS逆向解析

[root@tomcat tomcat]# vim conf/server.xml

connectionTimeout="20000"

redirectPort="8443" />

enableLookups="false" // 禁用DNS逆向解析

connectionTimeout="20000"

redirectPort="8443" />

[root@tomcat tomcat]# systemctl restart tomcat.service

开启压缩功能gzip

nginx使用gzip on;

tomcat使用compression;

compression="on" # 开启压缩功能静态文本资源 html js css

compressionMinSize="2048" # 压缩文件,最小2048字节要求(未达2048字节不压缩)

compressableMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf" # 压缩哪些类型的文件 文本类型 js,css,html

[root@tomcat tomcat]# vim conf/server.xml

connectionTimeout="20000"

redirectPort="8443" />

compression="on"

compressionMinSize="2048"

compressableMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf"

connectionTimeout="20000"

redirectPort="8443" />

[root@tomcat tomcat]# systemctl restart tomcat.service

验证:浏览器——》F12——》Network——》Response Headers——》Content-Encoding

线程数量

maxThreads="500" # 最大的线程数量 200-400之间

minSpareThreads="10" # 空闲时候最小的线程数量

acceptCount="500" # 当达到最大线程数量时的队列长度,一般与maxThreads一致。多于maxThreads的在acceptCount排队

acceptorThreadCount="2" # 每个线程接受的连接请求数量,一般与cpu核心总数一致或2倍,默认是1

[root@tomcat tomcat]# vim conf/server.xml

connectionTimeout="20000"

redirectPort="8443" />

maxThreads="500"

minSpareThreads="10"

acceptCount="500"

acceptorThreadCount="2"

connectionTimeout="20000"

redirectPort="8443" />

[root@tomcat tomcat]# systemctl restart tomcat.service

jvm内存调整

-Xms # start,初始内存

-Xmx # max,最大内存

官方建议 jvm初始内存大小是物理内存1/64,jvm最大内存大小是物理内存的1/4

实际使用 jvm最大内存大小是初始内存大小的一到两倍,因为有gc垃圾回收,差距太大造成浪费

[root@tomcat tomcat]# vim bin/catalina.sh // 增加一行

JAVA_OPTS='-Xms1024m -Xmx1024m -Xloggc:/var/log/tomcat_gc.log'

end

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: