1、Tomcat基础部分

1.1、tomcat配置文件

/app/tools/tomcat/conf/server.xml内容:

<?xml version="1.0" encoding="UTF-8"?>
#8005端口
<Server port="8005" shutdown="SHUTDOWN">
#8005:shutdown端口,连接这个端口输入shutdown,就可以关闭tomcat
  <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">

#8080端口 处理用户的http请求 
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    
#8443端口:用于处理https请求
    <!--
    <Connector protocol="AJP/1.3"
               address="::1"
               port="8009"
               redirectPort="8443" />
    -->
 #engine部分,指定默认的虚拟主机,defaultHost名称要与Host的name一致
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      
#Host部分,虚拟主机的配置,name:域名
      <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 &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

tomcat与nginx虚拟主机对比

虚拟主机对比tomcatnginx
虚拟主机Host部分server{}
域名name=”域名”server_name 域名;
端口Connector部分 port=”8080″listen 80;
站点目录appBase=”webapps”root /app/code/blog;
自动解压unpackWARs=”true”
自动部署autoDeploy=”true”,即加载到jvm中
日志记录<Valve部分 日志记录 directory=”logs” 后半部分suffix=”.txt”access_log /var/log/nginx/access.log main;
日志格式<Valve部分 patten=”%h %l %u %t “%r” %s %b”log_format main ……

1.2、规范tomcat访问日志格式

说明tomcatnginx
定义访问日志的格式Host部分的patten定义http区域log_format部分
客户端ip%h$remote_addr
访问时间%t$local_time
请求起始行(请求方法,URI)%r$request
状态码%s$status
大小%b$body_bytes_sent
从哪里跳转来的(用户如何访问网站)%{Referer}i$http_referer
客户端类型,浏览器%{User-Agent}i$http_user_agent
XFF头记录%{X-Forwarded-For}i$http_x_forwarded_for

注意:

&quot; 表示双引号

日志格式:

pattern="%h %l %u %t &quot;%r&quot; %s %b &quot;%{Referer}i &quot;&quot;%{User-Agent}i&quot;&quot;%{X-Forwarded-For}i&quot;" />

1.3、tomcat与用户请求

虚拟主机部分:

<Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      
#Host部分,虚拟主机的配置,name:域名
      <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 &quot;%r&quot; %s %b" />
      </Host>
    </Engine>

处理用户请求流程:

1、请求与8080端口连接
2、域名与Host部分的name进行匹配
 a)匹配成功,则使用对应的虚拟主机
 b)匹配失败,则使用Engine部分defaultHost指定的默认的虚拟主机进行处理

注意:

tomcat可以处理静态与动态请求
处理静态请求的效率较低,擅长动态
因此,静态的可以交给nginx

2、部署zrlog应用

zrlog:开源的java程序编写的博客程序

官网:https://www.zrlog.com/

2.1、web端

在web01上部署,web01:192.168.10.7

a)下载zrlog代码
[root@web01 ~]#curl -o zrlog.war  https://dl.zrlog.com/release/zrlog-2.2.1-efbe9f9-release.war?attname=ROOT.war&ref=index
b)部署代码包

直接把zrlog.war复制到webapps目录中

[root@web01 ~]#cp zrlog.war /app/tools/tomcat/webapps/

但浏览器访问的时候要加上zrlog。因此:

备份webapps目录中的ROOT目录

把zrlog.war包改名为ROOT.war到tomcat的webapps目录中

[root@web01 ~]#mv /app/tools/tomcat/webapps/ROOT{,.bak}
[root@web01 ~]#mv zrlog.war ROOT.war
[root@web01 ~]#cp ROOT.war /app/tools/tomcat/webapps/

结果如下:

但是,这样操作的话,访问tomcat默认的站点得加上ROOT.bak,如下:

浏览器打开:http://192.168.10.7:8080/ROOT.bak/

2.2、数据库端

数据库服务器:db01:192.168.10.5、172.16.1.51

创建名为zrlog的数据库,用户名:zrlog,密码:12345,白名单:172.16.1.%

[root@db01 ~]#mysql -uroot -p
MariaDB [(none)]> create database zrlog;
MariaDB [(none)]> grant all on zrlog.* to 'zrlog'@'172.16.1.%' identified by '12345';
MariaDB [(none)]> grant all on zrlog.* to 'zrlog'@'localhost' identified by '12345';
MariaDB [(none)]> flush privileges;

2.3、安装zrlog

浏览器打开:192.168.10.7:8080

如下:

填写相关信息,点击下一步,如下:

填写相关信息,点击下一步:

点击完成或点击查看,即可

3、nginx与tomcat

通过nginx的80端口转发到tomcat的8080

web01端提前yum安装好nginx

配置文件:

[root@web01 ~]#vim /etc/nginx/conf.d/zrlog.test.com.conf
server {
   listen 80;
   server_name zrlog.test.com;
   error_log /var/log/nginx/zrlog-error.log notice;
   access_log /var/log/nginx/zrlog-access.log main;

   location / {
      proxy_pass http://127.0.0.1:8080;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-For $http_add_x_forwared_for;
      proxy_set_header X-Real-Ip $remote_addr;
   }
}

重启nginx服务:

[root@web01 ~]#systemctl reload nginx

Windows本地做hosts解析

192.168.10.7 zrlog.test.com

浏览器打开: zrlog.test.com

如下:

4、动静分离

实际上,未来需要开发人员把代码拆分,把静态资源拆分出来单独存放

架构示意图:

4.1、修改zrlog站点目录的权限

由于修改nginx的运行用户为www(默认是nginx),所以修改zrlog站点目录属主属组为www:

[root@web01 ~]#chown -R www.www /app/tools/tomcat/webapps/ROOT/

4.2、配置nginx静态资源处理

zrlog站点目录:/app/tools/tomcat/webapps/ROOT/

修改nginx配置文件:配置静态资源的location规则

[root@web01 ~]#vim /etc/nginx/conf.d/zrlog.test.com.conf
server {
   listen 80;
   server_name zrlog.test.com;
   error_log /var/log/nginx/zrlog-error.log notice;
   access_log /var/log/nginx/zrlog-access.log main;
   
   location / {
      proxy_pass http://127.0.0.1:8080;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-For $http_add_x_forwared_for;
      proxy_set_header X-Real-Ip $remote_addr;
   }
   location ~* \.(html|js|css|png|jpeg|bmp|webp)$ {
      root /app/tools/tomcat/webapps/ROOT/;
      expires 7d;
  }
}

重启nginx,浏览器打开:http://zrlog.test.com/

403报错。权限拒绝。

查看nginx日志:

[root@web01 ~]#tail /var/log/nginx/zrlog-error.log
2023/07/08 21:25:18 [error] 11692#11692: *87075 open() "/app/tools/tomcat/webapps/ROOT/include/templates/default/js/sheshui.js" failed (13: Permission denied), client: 192.168.10.1, server: zrlog.test.com, request: "GET /include/templates/default/js/sheshui.js?t=1624781874000 HTTP/1.1", host: "zrlog.test.com"

关键词:Permission denied,权限拒绝

通过分析发现,/app/tools/tomcat/webapps/权限为750,修改为755即可

[root@web01 ~]#ll -d /app/tools/tomcat/webapps/
drwxr-x--- 9 root root 147 Jul  8 20:43 /app/tools/tomcat/webapps/
[root@web01 ~]#chmod 755 /app/tools/tomcat/webapps/

然后刷新浏览器即可。

ngx+tomcat动静分离目录权限设置问题:

前面中,是修改为www用户。建议使用以下设置权限:

[root@web01 ~]#chown -R root.root /app/tools/tomcat/
[root@web01 ~]#find /app/tools/tomcat/webapps/  -type f | xargs chmod 644
[root@web01 ~]#find /app/tools/tomcat/webapps/  -type d | xargs chmod 755

因为nginx不涉及写的问题,而tomcat是以root身份运行。

5、tomcat多实例

在同一台机子上运行多个tomcat实例

步骤:

1、多个tomcat目录
2、配置文件修改端口(默认是8080,8005)
3、启动

5.1 准备多个Tomcat

例如,再准备2个tomcat(tomcat-8081、tomcat-8082)

[root@web01 ~]#tar xf apache-tomcat-9.0.52.tar.gz 
[root@web01 ~]#cp -r apache-tomcat-9.0.52 tomcat-8081
[root@web01 ~]#cp -r apache-tomcat-9.0.52 tomcat-8082
[root@web01 ~]#mv tomcat-808* /app/tools/

5.2 修改配置

tomcat-8081的端口8080改为8081,8005改成8006

tomcat-8082的端口8080改为8082,8005改为8007

[root@web01 ~]#cd /app/tools/
[root@web01 /app/tools]#sed  -i 's#8080#8081#g' tomcat-8081/conf/server.xml 
[root@web01 /app/tools]#sed  -i 's#8005#8006#g' tomcat-8081/conf/server.xml 
[root@web01 /app/tools]#sed  -i 's#8005#8007#g' tomcat-8082/conf/server.xml 
[root@web01 /app/tools]#sed  -i 's#8080#8082#g' tomcat-8082/conf/server.xml

5.3 测试文件

[root@web01 ~]#echo "java tomcat 8081" > /app/tools/tomcat-8081/webapps/ROOT/test.jsp
[root@web01 ~]#echo "java tomcat 8082" > /app/tools/tomcat-8082/webapps/ROOT/test.jsp

5.4 手动启动tomcat

多实例无法使用systemctl启动tomcat,因此,要手动启动:

[root@web01 ~]#/app/tools/tomcat-8081/bin/startup.sh
[root@web01 ~]#/app/tools/tomcat-8082/bin/startup.sh

可以分别写systemctl配置文件使用systemctl管理8081、8082的tomcat

5.5 测试

浏览器打开:192.168.10.7:8081/test.jsp

浏览器打开:192.168.10.7:8082/test.jsp

OK,多实例tomcat运行成功

未来生成上,可以直接把tomcat+应用整体打包,使用的时候直接解压即可。

6、java远程监控功能

6.1 概述

未来通过各种监控工具(zabbix、grafana、prometheus….)监控tomcat、java

需要开启java远程监控功能(JMX remote)

6.2 步骤

Tomcat配置中修改tomcat启动的选项,开启jmx远程监控功能

交给zabbix就可以了(使用Windows jdk连接tomcat)

在catalina.sh文件中125行后面的CATALINA_OPTS 指定java启动的时候的选项

[root@web01 ~]#vim /app/tools/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.10.7"

参数解析:

开启远程监控功能选项说明
-Dcom.sun.management.jmxremote开启远程监控功能
-Dcom.sun.management.jmxremote.port=12345指定端口
-Dcom.sun.management.jmxremote.authenticate=false关闭认证功能
-Dcom.sun.management.jmxremote.ssl=false关闭ssl功能
-Djava.rmi.server.hostname=192.168.10.7本地网卡的地址,监听的地址(根据实际修改)

温馨提示:

从tomcat8.5开始,配置的每一行要通过\进行续行

重启tomcat

[root@web01 ~]#systemctl restart tomcat

6.3 连接tomcat

在Windows中连接tomcat

windows要安装jdk(安装过程略)

找到jdk的安装目录的bin下的jconsole.exe,双击打开:

输入192.168.10.7:12345,点连接:

点击不安全的连接即可。

此外,jvisualvm.exe也可以连接:

点击确定:

7、java故障案例

7.1 命令

1)jps

jps命令,就是java的ps命令,只显示java进程,类似于:ps -ef | grep java

[root@web01 ~]#jps -lvm | grep tomca
2)jstack

jstack查看java进程内部信息,线程信息

进程:占空间、占系统资源,类似于厂房
线程:厂房里面的工人,处理与用户的请求
需要代码使用多线程技术,通过ps aux查看进程是否支持多线程(是否使用多线程技术)

流程:

1、先过滤出java进程的pid
2、查看java进程的线程信息
  jstack  pid
3、查看java线程状态
  jstack pid | grep -i state

例如:

#1、过滤java进程的pid
[root@web01 ~]#ps aux | grep java | awk '{print $2}'
15008
[root@web01 ~]#
#2、查看线程信息
[root@web01 ~]#jstack 15008
#3、查看线程状态
[root@web01 ~]#jstack 15008 | grep -i state
   java.lang.Thread.State: RUNNABLE
   java.lang.Thread.State: TIMED_WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: RUNNABLE
   java.lang.Thread.State: RUNNABLE
   java.lang.Thread.State: TIMED_WAITING (parking)
   java.lang.Thread.State: WAITING (parking)
....

线程状态解释:

New:新建状态
Runnable:就绪状态
Running:运行状态
Blocked:阻塞状态(io)
Dead:死亡状态

统计每种状态的个数:

[root@web01 ~]#jstack 15008 | grep -i state | sort | uniq -c
3)jmap

jmap:查看或导出jvm信息

jmap -heap java-pid  导出java进程的jvm内存使用情况,例如:
jmap -heap 15008

导出jvm内存镜像:

[root@web01 ~]#jmap -dump:format=b,file=8080.hprof 15008
Dumping heap to /root/8080.hprof ...
Heap dump file created
[root@web01 ~]#ll -h 8080.hprof 
-rw------- 1 root root 30M Jul  8 23:03 8080.hprof
[root@web01 ~]#
4)mat分析工具

Windows的MemoryAnalyzer-1.8.0.20180604-win32.win32.x86_64.zip

下载地址:https://www.eclipse.org/mat/downloads.php

上面导出了8080.hprof,通过该软件进行分析:

双击打开提示:

不知道什么问题,启动不了。

8、java会话共享

会话共享方案说明备注
单机如果单个应用,tomcat不用考虑会话共享问题
session复制功能tomcat进行配置后,可以把session信息复制给其他节点只适用于集群节点较少的情况,比如4个节点以内
通过插件实现会话共享,放在redis中tomcat通过插件,把用户会话保存在指定的服务器中
(redis) tomcat-cluster_session-manager
需要插件,进行配置,代码支持
通过代码直接指定session位置修改代码与增加功能,依赖需要修改代码
使用其他方式替换会话oauth认证,koken认证代码级别

9、tomcat配置https

应用建议:

tomcat可以支持https,可以在tomcat中配置https证书
未来可以在nginx中配置证书加密,tomcat未加密

1、证书申请

2、Tomcat配置

server.xml配置文件,配置8443端口

[root@web01 ~]#vim /app/tools/tomcat/conf/server.xml
....
 <Connector port="8443" 
 protocol="HTTP/1.1"
 SSLEnabled="true"
 scheme="https"
 secure="true"
 keystoreFile="/xxx/xxx.pfx"  #公钥
 keystoreType="PKCS12" 
 keystorePass="xxx"  #密码,相当于私钥
 clientAuth="false"
 SSLProtocol="TLSv1.1+TLSv1.2+TLSv1.3"
 
ciphers="TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBX_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA1256,TLS_RSA_WITH_AES_256_CBC_SHA256"
             
    />
....

浏览器访问:https://ip或域名:8443

说明:

关于tomcat其他类型的证书格式配置,jsk格式:
 keystoreFile="/xxx/xxx.jks"  #公钥
 keystoreType="PKCS12"  #删除这一行
 keystorePass="xxx"  #密码,

3、8080跳转8443

在web.xml的</welcome-file-list>后面添加以下内容:

<login-config>
  <auth-method>CLIENT-CERT</auth-method>
  <realm-name>Client Cert Users-only Area</realm-name>
</login-config>
<security-constraint>
  <web-resoure-collection>
     <web-resource-name>ssl</web-resource-name>
     <url-pattern>/*</url-parren>
  </web-resource-collection>
  <user-data-constraint>
     <transport-guarantee>CONFIDENTIAL</transport-guarantee>
  </user-data-constraint>
</security-constraint>