配置Tomcat多实例、动静分离、监控、Session会话保持(三)
14. 配置多实例Tomcat
复制多份Tomcat并重新命名目录
[root@web01 ~]# cd /server/soft/
[root@web01 soft]# ll
total 188248
-rw-r--r-- 1 root root 11524133 Mar 27 23:16 apache-tomcat-9.0.52.tar.gz
-rw-r--r-- 1 root root 181238643 Mar 27 22:53 jdk-8u60-linux-x64.tar.gz
[root@web01 soft]# tar xf apache-tomcat-9.0.52.tar.gz
[root@web01 soft]# cp -r apache-tomcat-9.0.52 /app/tools/tomcat-8081
[root@web01 soft]# cp -r apache-tomcat-9.0.52 /app/tools/tomcat-8082
修改配置文件(端口信息)
[root@web01 soft]# sed -i "s#8080#8081#g" /app/tools/tomcat-8081/conf/server.xml
[root@web01 soft]# sed -i "s#8005#8006#g" /app/tools/tomcat-8081/conf/server.xml
[root@web01 soft]# sed -i "s#8080#8082#g" /app/tools/tomcat-8082/conf/server.xml
[root@web01 soft]# sed -i "s#8005#8007#g" /app/tools/tomcat-8082/conf/server.xml
书写Tomcat的systemctl配置文件,先查看现有的配置
[root@web01 soft]# cat /usr/lib/systemd/system/tomcat.service
[Unit]
Description=java tomcat service
After=network.target
[Service]
Type=forking
EnvironmentFile=/etc/sysconfig/tomcat
ExecStart=/app/tools/tomcat/bin/startup.sh
ExecStop=/app/tools/tomcat/bin/shutdown.sh
Reload=/app/tools/tomcat/bin/shutdown.sh && sleep 3 && /app/tools/tomcat/bin/startup.sh
[Install]
WantedBy=multi-user.target
复制现有的配置进行修改
[root@web01 ~]# cd /usr/lib/systemd/system/
[root@web01 system]# cp tomcat.service tomcat-8081.service
[root@web01 system]# cp tomcat.service tomcat-8082.service
[root@web01 system]# sed -i 's#/tomcat/#/tomcat-8081/#g' tomcat-8081.service
[root@web01 system]# sed -i 's#/tomcat/#/tomcat-8082/#g' tomcat-8082.service
重新加载systemd配置文件
[root@web01 ~]# systemctl daemon-reload
创建测试文件
[root@web01 ~]# echo tomcat 8081 > /app/tools/tomcat-8081/webapps/ROOT/index.jsp
[root@web01 ~]# echo tomcat 8082 > /app/tools/tomcat-8082/webapps/ROOT/index.jsp
启动服务并访问测试
[root@web01 ~]# systemctl start tomcat-8081
[root@web01 ~]# systemctl start tomcat-8082
#检查端口情况
[root@web01 ~]# ss -lntup | grep java
tcp LISTEN 0 1 [::ffff:127.0.0.1]:8005 [::]:* users:(("java",pid=89689,fd=64))
tcp LISTEN 0 1 [::ffff:127.0.0.1]:8006 [::]:* users:(("java",pid=103960,fd=63))
tcp LISTEN 0 1 [::ffff:127.0.0.1]:8007 [::]:* users:(("java",pid=103992,fd=63))
tcp LISTEN 0 50 [::ffff:127.0.0.1]:41513 [::]:* users:(("java",pid=89713,fd=19))
tcp LISTEN 0 50 [::ffff:127.0.0.1]:21513 [::]:* users:(("java",pid=89713,fd=14))
tcp LISTEN 0 100 [::]:8080 [::]:* users:(("java",pid=89689,fd=55))
tcp LISTEN 0 100 [::]:8081 [::]:* users:(("java",pid=103960,fd=55))
tcp LISTEN 0 100 [::]:8082 [::]:* users:(("java",pid=103992,fd=55))
tcp LISTEN 0 50 [::ffff:127.0.0.1]:51513 [::]:* users:(("java",pid=89713,fd=13))
浏览器访问测试,OK!
15. 动静分离
环境准备 | 说明 |
---|---|
web01 | nginx(处理静态)、tomcat(处理动态) |
db01 | 存储数据信息 |
nfs01 | 暂且忽略,理应把用户上传的内容挂载到存储上 |
Tips:web01安装nginx、tomcat,db01安装mariadb数据库,参考之前的命令!
通过部署zrlog博客来实现动静分离,首先在web01上安装nginx、tomcat并书写好systemctl配置文件。下面下载一个java博客war包,点这!。将war上传到/app/tools/tomcat/webapps目录下。
#上传war包到指定目录,已自动解压
[root@web01 ~]# cd /app/tools/tomcat/webapps/
[root@web01 webapps]# ll
total 10988
drwxr-x--- 15 root root 4096 Mar 27 23:17 docs
drwxr-x--- 7 root root 99 Mar 27 23:17 examples
drwxr-x--- 6 root root 79 Mar 27 23:17 host-manager
drwxr-x--- 6 root root 114 Mar 27 23:17 manager
drwxr-x--- 3 root root 41 Mar 28 02:44 memtest
-rw-r--r-- 1 root root 643 Mar 28 02:44 memtest.war
drwxr-x--- 2 root root 6 Mar 29 09:18 ROOT
drwxr-x--- 9 root root 126 Mar 29 03:56 zrlog-2.2.1-efbe9f9-release
-rw-r--r-- 1 root root 11243048 Mar 29 03:54 zrlog-2.2.1-efbe9f9-release.war
#复制所有代码文件到ROOT目录下
[root@web01 webapps]# cp -r zrlog-2.2.1-efbe9f9-release/* ROOT/
#创建nginx目录
[root@web01 ~]# mkdir -p /app/code/zrlog/static
#复制所有代码文件到nginx目录下
[root@web01 ~]# cp -r /app/tools/tomcat/webapps/zrlog-2.2.1-efbe9f9-release/* /app/code/zrlog/static/
#赋予权限
[root@web01 ~]# chown -R nginx.nginx /app/code/zrlog/static/
#为什么这么做呢,因为动态代码和静态代码没有做分离,同时在nginx配置文件中root直接指tomcat的webapps/ROOT目录会直接报403错误!所以在部署这样子的项目,前期构建项目时就要进行做动静分离代码。
修改Server.xml配置文件
[root@web01 tomcat]# pwd
/app/tools/tomcat
[root@web01 tomcat]# cat conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<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" />
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="zrlog.yinjay.com">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="zrlog.yinjay.com" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="zrlog_access" suffix=".log"
pattern="%h %l %u %t"%r" %s %b "%{Referer}i""%{User-Agent}i" "%{X-Forwarded-For}i"" />
</Host>
</Engine>
</Service>
</Server>
启动tomcat服务
systemctl start tomcat
在MariaDB数据库上进行创建zrlog数据库和创建授权用户。
create database zrlog;
grant all on zrlog.* to 'zrlog'@'172.16.1.%' identified by 'Huawei@123';
flush privileges;
书写nginx的配置文件
[root@web01 ~]# cat /etc/nginx/conf.d/zrlog.yinjay.com.conf
server {
listen 80;
server_name zrlog.yinjay.com;
location / {
proxy_pass http://10.0.0.7:8080;
proxy_set_header Host $http_host;
}
location ~* \.(html|css|js|png|jpg|jpeg)$ {
root /app/code/zrlog/static/;
expires 30d;
}
}
Tisp:记得在/etc/nginx/nginx.conf把server区块注释!
启动nginx服务
systemctl start nginx
宿主机进行访问zrlog.yinjay.com
测试,测试看出已经动静分离进行处理。
下面是查看nginx的访问日志
下面是查看tomcat的访问日志
16. 监控Tomcat
通过命令获取java进程信息,jvm信息。
java管理的命令 | |
---|---|
java命令 | 用于启动代码,启动jar包或tomcat启动war,背后都会用java命令。 |
jps | java ps命令,查看显示java进程。 |
jstack | java进程和线程信息,运行状态等等。 |
jmap | 查看jvm内存使用情况,导出jvm内存(用于故障分析)。 |
16.1 jps查看当前机器上已装载的jvm
[root@web01 ~]# jps -lvm
16.2 jstack查看java进程与线程信息
jstack命令主要用来查看Java线程的调用堆栈的,可以用来分析线程问题(如死锁)。
用法:jstack java进程的pid(可通过jps -lvm获取,下面就取上面已经得出来的pid)
[root@web01 ~]# jstack 112379
2023-03-31 08:56:49
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode):
-----------(忽略大部分输出)------------
#更多的是关注下面的线程状态
"main" #1 prio=5 os_prio=0 tid=0x00007f4dd8009000 nid=0x1b6fe runnable [0x00007f4de1d8c000]
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:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at org.apache.catalina.core.StandardServer.await(StandardServer.java:602)
at org.apache.catalina.startup.Catalina.await(Catalina.java:864)
at org.apache.catalina.startup.Catalina.start(Catalina.java:810)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476)
"VM Thread" os_prio=0 tid=0x00007f4dd806d800 nid=0x1b6ff runnable
"VM Periodic Task Thread" os_prio=0 tid=0x00007f4dd80b9000 nid=0x1b706 waiting on condition
JNI global references: 453
通常流程先查出最耗费CPU的线程
top -Hp 进程pid
[root@web01 ~]# top -Hp 112379
比如下面这条线程最耗费CPU
先将线程pid进行转换成十六进制
[root@web01 ~]# printf "%x\n" 112429
1b72d
先将信息输出到文件,然后通过上面转换的十六进制信息进行查找。
[root@web01 ~]# jstack 112379 > info.txt
在文件中进行定位到指定位置,就能看到该线程的状态。
值得关注的线程状态有:
① 死锁:Deadlock(重点关注)
② 执行中:Runnable
③ 等待资源:Waiting on condition(重点关注)
④ 等待获取监视器:Waiting on monitor entry(重点关注)
⑤ 暂停:Suspended
⑥ 对象等待中:Object.wait() 或 TIMED_WAITING
⑦ 阻塞:Blocked(重点关注)
⑧ 停止:Parked
16.3 jmap查看Jvm内存使用情况
jmap命令可以获得运行中的jvm的堆的快照,从而可以离线分析堆,以检查内存泄漏,检查一些严重影响性能的大对象的创建,检查系统中什么对象最多,各种对象所占内存的大小等等。
用法:jmap -heap java进程的pid
[root@web01 ~]# jmap -heap 112379
Attaching to process ID 112379, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.60-b23
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 478150656 (456.0MB)
NewSize = 10485760 (10.0MB)
MaxNewSize = 159383552 (152.0MB)
OldSize = 20971520 (20.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 12451840 (11.875MB)
used = 3106144 (2.962249755859375MB)
free = 9345696 (8.912750244140625MB)
24.945261101973685% used
Eden Space:
capacity = 11075584 (10.5625MB)
used = 2096104 (1.9990005493164062MB)
free = 8979480 (8.563499450683594MB)
18.925448987610945% used
From Space:
capacity = 1376256 (1.3125MB)
used = 1010040 (0.9632492065429688MB)
free = 366216 (0.34925079345703125MB)
73.39041573660714% used
To Space:
capacity = 1376256 (1.3125MB)
used = 0 (0.0MB)
free = 1376256 (1.3125MB)
0.0% used
tenured generation:
capacity = 27480064 (26.20703125MB)
used = 16588880 (15.820388793945312MB)
free = 10891184 (10.386642456054688MB)
60.366962755254136% used
20025 interned Strings occupying 2180064 bytes.
生成内存dump文件,未来通过专用的jvm内存分析工具,打开分析这个文件即可。
用法:jmap -dump:file=文件名.hprof, format=b java进程pid
[root@web01 ~]# jmap -dump:file=/root/test.hprof,format=b 112379
Dumping heap to /root/test.hprof ...
Heap dump file created
16.4 开启java远程监控功能
来通过各种监控工具(Zabbix/Grafana/Promethues/...),监控Tomcat/java,或者用于开发调试代码与查看Java状态。
开启流程:
- 修改java配置(tomcat配置的catalina.sh)
- 重启java(tomcat)
- 监控(可从监控插件或者window下启动java工具查看)
修改tomcat/bin目录下的catalina.sh,添加下列内容。CATALINA_OPTS就是java变量修改tomcat启动的时候参数,本质就是给java命令增加些参数。
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=10.0.0.7"
jmxremote选项说明 | |
---|---|
Dcom.sun.management.jmxremote | 开启远程监控功能 |
Dcom.sun.management.jmxremote.port=12345 | 指定功能的端口号:12345 |
Dcom.sun.management.jmxremote.authenticate=false | 是否开启认证功能,关闭 |
Dcom.sun.management.jmxremote.ssl=false | 是否开启ssl证书,关闭 |
Djava.rmi.server.hostname=10.0.0.7 | 指定本机的内网或公网ip |
重启tomcat服务,然后查看端口情况
jps -lvm查看,已经加载
在宿主机通过jvisualvm工具进行监控(模拟zabbix监控java)
16.5 高负载排查过程
排障流程 | 具体命令和方法 |
---|---|
通过监控得知系统负载高,登录这台机器进行初步分析原因 | 通过监控或告警 |
分析cpu导致还是磁盘io导致 | top命令关注下面情况 us、sy数值高为CPU导致 wa数值高为IO导致 |
查出对应进程出现异常(此处指java导致时) | CPU导致可在top信息中看CPU利用率高的对应进程PID IO导致可以用iotop -P命令看最高IO读写的进程PID |
查看jvm内存情况,导出jvm内存进行分析 | 内存情况: jmap -heap java的PID 导出jvm内存:dump:file=xxx.hprof,format=b java的PID |
分析jvm内存,需要开发参与 | 通过内存分析工具:Memory Analyzer Tool |
分析应用日志 catalina.out 分析网站日志 xxxx.log |
看日志是否有异常 |
找出原因 | 解决与处理 |
17. Session会话共享保持
环境 | 说明 | ip |
---|---|---|
lb01 | nginx实现负载均衡 | 10.0.0.5、172.16.1.5 |
web01 | web服务,tomcat | 172.16.1.7 |
web02 | web服务,tomcat | 172.16.1.8 |
db01 | 数据库、redis | 172.16.1.51 |
Tips:本实验使用不到数据库,只是在数据库的机器上部署redis!
17.1 下载插件并修改配置文件
tomcat-cluster-redis-session插件下载地址:https://github.com/ran-jit/tomcat-cluster-redis-session-manager/ 选择适合的版本下载后上传到tomcat主机上(web01、web02)
以下步骤web01、web02都进行相同的修改。
[root@web01 ~]# cd /server/soft/
[root@web01 soft]# ll
total 189148
drwxr-xr-x 9 root root 220 Mar 29 07:57 apache-tomcat-9.0.52
-rw-r--r-- 1 root root 11524133 Mar 27 23:16 apache-tomcat-9.0.52.tar.gz
-rw-r--r-- 1 root root 181238643 Mar 27 22:53 jdk-8u60-linux-x64.tar.gz
drwxr-xr-x 3 root root 96 Mar 31 23:17 __MACOSX
drwxr-xr-x 4 root root 64 Aug 12 2019 tomcat-cluster-redis-session-manager
-rw-r--r-- 1 root root 921429 Mar 31 23:16 tomcat-cluster-redis-session-manager.zip
[root@web01 soft]# tree tomcat-cluster-redis-session-manager
tomcat-cluster-redis-session-manager
├── conf
│ └── redis-data-cache.properties #连接redis的配置文件
├── lib #依赖,tomcat-redis-session管理插件
│ ├── commons-pool2-2.6.2.jar
│ ├── jedis-3.0.1.jar
│ ├── slf4j-api-1.7.26.jar
│ └── tomcat-cluster-redis-session-manager-4.0.jar
└── readMe.txt
2 directories, 6 files
复制jar包到tomcat的lib目录中,复制配置文件到tomcat的conf目录中。
[root@web01 soft]# cp tomcat-cluster-redis-session-manager/lib/*.jar /app/tools/tomcat/lib/
[root@web01 soft]# cp tomcat-cluster-redis-session-manager/conf/redis-data-cache.properties /app/tools/tomcat/conf/
修改配置文件
[root@web01 ~]# vim /app/tools/tomcat/conf/redis-data-cache.properties
redis.hosts=172.16.1.51:6379
[root@web01 ~]# vim /app/tools/tomcat/conf/context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
#在Context里面增添下列两行
<Valve className="tomcat.request.session.redis.SessionHandlerValve" />
<Manager className="tomcat.request.session.redis.SessionManager" />
</Context>
17.2 安装redis并修改配置
db01下进行
yum install -y redis
更改redis服务监听地址
[root@db01 ~]# grep -n '^bind' /etc/redis.conf
61:bind 127.0.0.1
[root@db01 ~]# sed -i '61s/127.0.0.1/172.16.1.51/' /etc/redis.conf
[root@db01 ~]# grep -n '^bind' /etc/redis.conf
61:bind 172.16.1.51
启动redis服务并设置开机自启
[root@db01 ~]# systemctl start redis
[root@db01 ~]# systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.
检查服务状态
[root@db01 ~]# ps -ef |grep redis
redis 75726 1 0 23:43 ? 00:00:00 /usr/bin/redis-server 172.16.1.51:6379
root 75730 74049 0 23:43 pts/2 00:00:00 grep --color=auto redis
查询redis中的数据,目前为空
[root@db01 ~]# redis-cli -h 172.16.1.51
172.16.1.51:6379> keys *
(empty list or set)
172.16.1.51:6379>
17.3 书写测试文件并重启服务访问
web01书写测试文件
[root@web01 ~]# cat /app/tools/tomcat/webapps/ROOT/session.jsp
<body>
<%
System.out.println(session.getCreationTime());
out.println("<br> web01.yinjay.com SESSIONID:" + session.getId() + "<br>");
out.println("Session created time is :" + session.getCreationTime()+ "<br>");
%>
</body>
web02书写测试文件
[root@web02 ~]# cat /app/tools/tomcat/webapps/ROOT/session.jsp
<body>
<%
System.out.println(session.getCreationTime());
out.println("<br> web02.yinjay.com SESSIONID:" + session.getId() + "<br>");
out.println("Session created time is :" + session.getCreationTime()+ "<br>");
%>
</body>
web01、web02重启服务
systemctl restart tomcat
进行单独访问测试,redis查询到各自的session。
17.4 接入负载均衡
在lb01上进行修改配置文件并重新加载配置。
[root@lb01 ~]# cat /etc/nginx/conf.d/lb01.conf
upstream tomcat_pools {
server 172.16.1.7:8080;
server 172.16.1.8:8080;
}
server {
listen 80;
server_name tomcat.yinjay.com;
location / {
proxy_pass http://tomcat_pools;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
}
}
[root@lb01 ~]# systemctl reload nginx
在宿主机添加host记录10.0.0.5 tomcat.yinjay.com
后并进行浏览器访问。第一次负载到web01,第二次负载到web02,然后进行查询redis都是同一个session,实现会话共享保持!