WEB服务-Tomcat
Tomcat
JVM介绍
JVM是Java Virtual Machine(Java虚拟机)的缩写
Java虚拟机本质是就是一个程序,当它在命令行上启动的时候,就开始执行保存在某字节码文件中的指令。Java语言的可移植性正是建立在Java虚拟机的基础上。任何平台只要装有针对于该平台的Java虚拟机,字节码文件(.class)就可以在该平台上运行。这就是“一次编译,多次运行”。
Tomcat介绍
- 什么是Tomcat
Tomcat和我们此前学习的 Nginx 类似,也是一个Web服务器。
- Tomcat与Nginx有什么区别?
Tomcat是一个Java版的Web服务器。
Nginx仅支持静态资源,而Tomcat则支持Java开发的 jsp 动态资源和静态资源。 Nginx适合做前端负载均衡,而Tomcat适合做后端应用服务处理。 通常情况下,企业会使用 Nginx+tomcat 结合使用,由Nginx处理静态资源,Tomcat处理动态资源。
Tomcat快速安装
主机名 | IP | 软件 | 配置 |
---|---|---|---|
tomcat01 | 10.0.0.11 | tomcat,nfs-utils | 1C1G |
tomcat02 | 10.0.0.12 | tomcat,nfs-utils | 1C1G |
lb01 | 10.0.0.5 | nginx,mariadb,redis,nfs | 1C1G |
hostnamectl set-hostname tomcat01
sed -i 's#200#11#g' /etc/sysconfig/network-scripts/ifcfg-eth[01]
安装方法1:rpm包
cd /opt
rz -E
wget https://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.5.61/bin/apache-tomcat-8.5.61.tar.gz
rpm -ivh jdk-8u271-linux-x64.rpm
mkdir -p /app
tar xf apache-tomcat-8.5.61.tar.gz -C /app
/app/apache-tomcat-8.5.61/bin/startup.sh
安装方法2:二进制包
cd /opt
rz -E
wget https://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.5.61/bin/apache-tomcat-8.5.61.tar.gz
tar xf jdk-8u60-linux-x64.tar.gz -C /app/
ln -s /app/jdk1.8.0_60 /app/jdk
sed -i.ori '$a export JAVA_HOME=/app/jdk\nexport PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH\nexport CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar' /etc/profile
source /etc/profile
mkdir -p /app/
tar xf apache-tomcat-8.5.61.tar.gz -C /app
/app/apache-tomcat-8.5.61/bin/startup.sh
注意:容器dockerfile使用ENV时,请用绝对路径
ENV JAVA_HOME=/app/jdk ENV PATH=/app/jdk/bin:/app/jdk/jre/bin:$PATH ENV CLASSPATH=/app/jdk/lib:/app/jdk/jre/lib:/app/jdk/lib/tools.jar
Tomcat启动加速
- 优化前启动时间
[root@tomcat01 opt]# grep 'Server startup' /app/apache-tomcat-8.5.61/logs/catalina.out
03-Aug-2019 03:15:18.225 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 591050 ms
- 优化
vi /usr/java/jdk1.8.0_271-amd64/jre/lib/security/java.security
securerandom.source=file:/dev/urandom
随机数改为使用随机性不高的
/dev/urandom
,产生速度块。
- 优化后启动时间
[root@tomcat01 opt]# grep 'Server startup' /app/apache-tomcat-8.5.61/logs/catalina.out
03-Aug-2019 03:15:18.225 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 591050 ms
03-Aug-2019 03:22:14.112 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1326 ms
Tomcat目录结构介绍
[root@tomcat01 opt]# ll /app/apache-tomcat-8.5.61/
total 128
drwxr-x--- 2 root root 4096 12月 27 10:22 bin # 主要包含启动、关闭tomcat脚本和脚本依赖文件 非常重要
-rw-r----- 1 root root 19318 12月 3 22:07 BUILDING.txt # 安装说明,不重要
drwx------ 3 root root 254 12月 27 10:23 conf # tomcat配置文件目录 非常重要
-rw-r----- 1 root root 5408 12月 3 22:07 CONTRIBUTING.md
drwxr-x--- 2 root root 4096 12月 27 10:22 lib # tomcat运行需要加载的jar包 非常重要
-rw-r----- 1 root root 57011 12月 3 22:07 LICENSE # 版本声明,不重要
drwxr-x--- 2 root root 197 12月 27 10:23 logs # 在运行过程中产生的日志文件 非常重要
-rw-r----- 1 root root 1726 12月 3 22:07 NOTICE # 笔记,不重要
-rw-r----- 1 root root 3257 12月 3 22:07 README.md # 总介绍,不重要
-rw-r----- 1 root root 7136 12月 3 22:07 RELEASE-NOTES # 版本特性,不重要
-rw-r----- 1 root root 16507 12月 3 22:07 RUNNING.txt # 帮助文件,不重要
drwxr-x--- 2 root root 30 12月 27 10:22 temp # 存放临时文件
drwxr-x--- 7 root root 81 12月 3 22:05 webapps # 站点目录 非常重要
drwxr-x--- 3 root root 22 12月 27 10:23 work # tomcat运行时产生的缓存文件
Tomcat配置文件
核心配置文件:/app/apache-tomcat-8.5.61/conf/server.xml
一个tomcat实例化一个server,一个server中包含多个host,一个host中包含多个context。
-
service的作用是:将connector关联至engine(catalina引擎),Connector的主要功能是接受、响应用户请求。
-
host就是一个站点,类似于nginx的多站点。
-
context,类似于nginx的location概念。
Tomcat部署zrlog
cd /opt
wget http://dl.zrlog.com/release/zrlog.war
- 修改配置文件,添加虚拟主机
vi /app/apache-tomcat-8.5.61/conf/server.xml
... ...
<Host name="blog.oldqiang.com" appBase="/html"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="blog.oldqiang.com_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
tomcat日志格式
%a - 远程IP地址 %A - 本地IP地址 %b - 发送的字节数,不包括HTTP头,或“ - ”如果没有发送字节 %B - 发送的字节数,不包括HTTP头 %h - 远程主机名 %H - 请求协议 %l - 远程逻辑从identd的用户名(总是返回' - ') %m - 请求方法 %p - 本地端口 %q - 查询字符串(在前面加上一个“?”如果它存在,否则是一个空字符串 %r - HTTP请求头的第一行 %s - 响应的HTTP状态代码 %S - 用户会话ID %t - 日期和时间,在通用日志格式 %u - 远程用户身份验证 %U - 请求的URL路径 %v - 本地服务器名 %D - 处理请求的时间(以毫秒为单位) %T - 处理请求的时间(以秒为单位) %I (大写的i) - 当前请求的线程名称
" html的空格
显示请求头
curl -v 10.0.0.11:8080 | head -1
- 重启生效
/app/apache-tomcat-8.5.61/bin/shutdown.sh
/app/apache-tomcat-8.5.61/bin/startup.sh
- 热部署
mv zrlog.war /html/ROOT.war
- Windows配置hosts解析
10.0.0.11 blog.oldqiang.com
,访问:http://blog.oldqiang.com:8080/ - lb01安装mariadb,启动并加入开机启动,并创建数据库和用户
yum install mariadb-server -y
systemctl enable mariadb
systemctl start mariadb
mysql -e "create database zrlog;grant all on zrlog.* to zrlog@'10.0.0.%' identified by '123456';"
- 配置数据库信息
- 填写网站信息
- 安装完成
- 安装完成,创建锁文件,下次访问不再跳转安装页面,跳转主页。数据库配置文件:
/html/ROOT/WEB-INF/install.lock # 锁文件
/html/ROOT/WEB-INF/db.properties # 数据库配置文件
Tomcat配置basic认证
- 使用默认basic认证,访问:http://10.0.0.11:8080/,点击Host Manager
- manager默认只允许本机访问:修改配置允许其他IP访问
# 修改前
[root@tomcat01 ~]# grep allow /app/apache-tomcat-8.5.61/webapps/host-manager/META-INF/context.xml
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
# 修改后
[root@tomcat01 ~]# grep allow /app/apache-tomcat-8.5.61/webapps/host-manager/META-INF/context.xml
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1|10\.0\.0\.1" />
- 查看默认basic认证:安全角色admin-gui,配置使用BASIC认证
cat /app/apache-tomcat-8.5.61/webapps/host-manager/WEB-INF/web.xml
<security-constraint>
<web-resource-collection>
<web-resource-name>HTMLHostManager commands</web-resource-name>
<url-pattern>/html/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<!-- NOTE: This role is not present in the default users file -->
<role-name>admin-gui</role-name>
</auth-constraint>
</security-constraint>
<!-- Define the Login Configuration for this Application -->
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Tomcat Host Manager Application</realm-name>
</login-config>
- 添加系统角色
vim /app/apache-tomcat-8.5.61/conf/tomcat-users.xml
... ...
<role rolename="admin-gui"/>
<user username="tomcat" password="123456" roles="admin-gui"/>
</tomcat-users>
- 重启tomcat生效
/app/apache-tomcat-8.5.61/bin/shutdown.sh
/app/apache-tomcat-8.5.61/bin/startup.sh
- 访问:http://10.0.0.11:8080/,点击Host Manager
- 添加系统角色
vi /app/apache-tomcat-8.5.61/conf/tomcat-users.xml
... ...
<role rolename="tomcat-gui"/>
<user username="tomcat" password="123456" roles="tomcat"/>
</tomcat-users>
- 启用basic认证:访问管理后台登录页面需要basic认证,其他页面不需要。
vi /html/ROOT/WEB-INF/web.xml
... ...
<security-constraint>
<web-resource-collection>
<web-resource-name>test</web-resource-name>
<url-pattern>/admin/login/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>tomcat-gui</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Default</realm-name>
</login-config>
</web-app>
- 重启tomcat生效
/app/apache-tomcat-8.5.61/bin/shutdown.sh
/app/apache-tomcat-8.5.61/bin/startup.sh
-
访问:http://blog.oldqiang.com:8080/,点击管理验证。
注意使用无痕窗口,刚才登录了一次,浏览器会记住登录状态。
Nginx+Tomcat集群架构
- tomcat01推送站点代码和tomcat到tomcat02
scp -rp /html root@10.0.0.12:/
scp -rp /app root@10.0.0.12:/
- tomcat02安装JDK
cd /opt
rpm -ivh jdk-8u271-linux-x64.rpm
- lb01安装nginx
yum install nginx -y
- lb01修改nginx配置文件
cat <<EOF >/etc/nginx/nginx.conf
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream tomcat {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
server {
listen 80;
server_name loaclhost;
location / {
proxy_pass http://tomcat;
# 代理传递主机头
proxy_set_header Host \$http_host;
# 代理传递真实IP
proxy_set_header X-Real-IP \$remote_addr;
}
}
}
EOF
- 启动nginx,并加入开机启动
systemctl enable nginx
systemctl start nginx
- tomcat01和tomcat02修改日志格式:
%h
改为%{X-Real-IP}i
vi /app/apache-tomcat-8.5.61/conf/server.xml
... ...
pattern="%{X-Real-IP}i %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
可以将request请求的查询参数、session会话变量值、cookie值或HTTP请求/响应头内容的变量值等内容写入到日志文件。仿照apache的语法:
%{XXX}i xxx代表传入的头(HTTP Request) %{XXX}o xxx代表传出的响应头(Http Resonse) %{XXX}c xxx代表特定的Cookie名 %{XXX}r xxx代表ServletRequest属性名 %{XXX}s xxx代表HttpSession中的属性名
- tomcat01和tomcat02重启tomcat生效
/app/apache-tomcat-8.5.61/bin/shutdown.sh
/app/apache-tomcat-8.5.61/bin/startup.sh
-
Windows修改hosts解析
10.0.0.5 blog.oldqiang.com
,访问http://blog.oldqiang.com/ -
tomcat01和tomcat02查看访问日志
tail -f /app/apache-tomcat-8.5.61/logs/blog.oldqiang.com_access_log.2020-12-27.txt
Tomcat+NFS文件共享
- 所有节点安装
yum install nfs-utils -y
- lb01配置NFS服务
mkdir /data
cat <<EOF > /etc/exports
/data 10.0.0.0/24(rw,sync,no_root_squash,no_all_squash)
EOF
systemctl enable nfs
systemctl start nfs
- tomcat01和tomcat02查看挂载点
showmount -e 10.0.0.5
- tomcat01和tomcat02创建图片目录,并挂载
mkdir -p /html/ROOT/attached
mount -t nfs 10.0.0.5:/data /html/ROOT/attached
- 访问http://blog.oldqiang.com/,上传图片测试
Nginx配置缓存
- 修改nginx配置文件
# http {
# http模块配置缓存路径,目录结构,缓存keys的空间大小
proxy_cache_path /opt/nginx/cache levels=1:2 keys_zone=cache_image:100m;
# server {
# location配置匹配缓存
location ~ ^.*\.(js|css|ico|gif|jpg|jpeg|png)$ {
proxy_cache cache_image;
proxy_cache_key $uri$is_args$args;
# 状态码:200 206 缓存有效期14天
proxy_cache_valid 200 206 14d;
# 设置Response头信息Nginx-Cache,用来分析缓存命中
add_header Nginx-Cache "$upstream_cache_status";
proxy_pass http://tomcat;
# 代理传递主机头
proxy_set_header Host $http_host;
# 代理传递真实IP
proxy_set_header X-Real-IP $remote_addr;
}
- 创建缓存目录并授权
mkdir -p /opt/nginx/cache
chown -R nginx:nginx /opt/nginx/cache
- 重启nginx生效
systemctl restart nginx
-
查看缓存
tree /opt/nginx/cache
-
验证缓存命中:
-
第一次请求访问,Response Headers:Nginx-Cache:MISS
-
第二次请求访问,Response Headers:Nginx-Cache:HIT
-
删除Cache文件,第三次请求访问,Response Headers:Nginx-Cache:MISS
-
Nginx配置Https
- 修改nginx配置文件
# cat /etc/nginx/nginx.conf
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream tomcat {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
proxy_cache_path /opt/nginx/cache levels=1:2 keys_zone=cache_image:100m;
server {
listen 80;
server_name blog.oldqiang.com;
location / {
return 302 https://blog.oldqiang.com$request_uri;
}
}
server {
listen 443 ssl;
server_name blog.oldqiang.com;
ssl_certificate /opt/Nginx/1_blog.oldqiang.com_bundle.crt;
ssl_certificate_key /opt/Nginx/2_blog.oldqiang.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://tomcat;
# 代理传递主机头
proxy_set_header Host $http_host;
# 代理传递真实IP
proxy_set_header X-Real-IP $remote_addr;
}
location ~ ^.*\.(css|ico|gif|jpg|jpeg|png)$ {
proxy_cache cache_image;
proxy_cache_key $uri$is_args$args;
# 状态码:200 206 缓存有效期14天
proxy_cache_valid 200 206 14d;
# 设置Response头信息Nginx-Cache,用来分析缓存命中
add_header Nginx-Cache "$upstream_cache_status";
proxy_pass http://tomcat;
# 代理传递主机头
proxy_set_header Host $http_host;
# 代理传递真实IP
proxy_set_header X-Real-IP $remote_addr;
}
}
}
- 重启nginx生效
systemctl restart nginx
Maven编译Java源码
- tomcat01下载maven二进制包,创建软链接,添加到环境变量
cd /opt
wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
tar xf apache-maven-3.6.3-bin.tar.gz -C /usr/local/
ln -s /usr/local/apache-maven-3.6.3 /usr/local/maven
cat <<EOF > /etc/profile.d/M2.sh
export M2_HOME=/usr/local/maven
export PATH=\${M2_HOME}/bin:\$PATH
EOF
. /etc/profile.d/M2.sh
mvn -v
- 修改仓库地址,使用阿里云nexus仓库
/usr/local/maven/conf/settings.xml
... ...
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
... ...
- 常用命令
mvn clean package # 清理打包缓存
mvn package # 打包
mvn -Dtest package # 跳过测试
- 查看maven缓存
tree /root/.m2
Redisson实现Session共享
- 修改nginx配置文件,不传递主机头,重启nginx生效
#proxy_set_header Host $http_host;
systemctl restart nginx
-
访问:http://10.0.0.5/examples/servlets/servlet/SessionExample,每次刷新session改变
-
lb01安装Redis,监听10.0.0.5:6379,启动并加入开机自启
yum install redis -y
bind 127.0.0.1
sed -i '/^bind 127.0.0.1/c bind 127.0.0.1 10.0.0.5' /etc/redis.conf
systemctl enable redis
systemctl start redis
- tomcat01下载依赖jar包
cd /app/apache-tomcat-8.5.61/lib/
wget https://repository.sonatype.org/service/local/repositories/central-proxy/content/org/redisson/redisson-all/3.14.0/redisson-all-3.14.0.jar
wget https://repository.sonatype.org/service/local/repositories/central-proxy/content/org/redisson/redisson-tomcat-8/3.14.0/redisson-tomcat-8-3.14.0.jar
- tomcat01修改配置文件,添加redisson.conf
vim /app/apache-tomcat-8.5.61/conf/context.xml
... ...
<Manager className="org.redisson.tomcat.RedissonSessionManager"
configPath="${catalina.base}/conf/redisson.conf"
readMode="REDIS" updateMode="DEFAULT" broadcastSessionEvents="false"
keyPrefix=""/>
</Context>
cat <<EOF >/app/apache-tomcat-8.5.61/conf/redisson.conf
singleServerConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
password: null
subscriptionsPerConnection: 5
clientName: null
address: "redis://10.0.0.5:6379"
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 24
connectionPoolSize: 64
database: 0
dnsMonitoringInterval: 5000
threads: 16
nettyThreads: 32
codec: {class: "org.redisson.codec.JsonJacksonCodec"}
transportMode: "NIO"
EOF
- tomcat01重启tomcat生效
/app/apache-tomcat-8.5.61/bin/shutdown.sh
/app/apache-tomcat-8.5.61/bin/startup.sh
- tomcat01将jar包和配置文件推送到tomcat02
scp -rp /app/apache-tomcat-8.5.61/conf/context.xml root@10.0.0.12:/app/apache-tomcat-8.5.61/conf/context.xml
scp -rp /app/apache-tomcat-8.5.61/conf/redisson.conf root@10.0.0.12:/app/apache-tomcat-8.5.61/conf/redisson.conf
scp -rp /app/apache-tomcat-8.5.61/lib/redisson-all-3.14.0.jar /app/apache-tomcat-8.5.61/lib/redisson-tomcat-8-3.14.0.jar root@10.0.0.12:/app/apache-tomcat-8.5.61/lib/
- tomcat02重启tomcat生效
/app/apache-tomcat-8.5.61/bin/shutdown.sh
/app/apache-tomcat-8.5.61/bin/startup.sh
Tomcat监控
zabbix监控tomcat
vim /application/apache-tomcat-8.5.61/bin/catalina.sh
CATALINA_OPTS="$CATALINA_OPTS
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=10.0.0.11
-Dcom.sun.management.jmxremote.port=12345
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false"
a:安装zabbix-java-gateway,10052
b:配置重启zabbix-java-gateway
START_POLLERS=5
c:配置重启zabbix-server
JavaGateway=127.0.0.1
JavaGatewayPort=10052
StartJavaPollers=5
d:zabbix-web添加jmx监控
Tomcat性能优化
JVM调优
vi /app/apache-tomcat-8.5.61/bin/catalina.sh
mkdir /tmp/heap_dump
JAVA_OPTS="$JAVA_OPTS -server -Xms256m -Xmx256m -Xss256k -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap_dump -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/tmp/heap_trace.txt -XX:NewSize=128m -XX:MaxNewSize=128m"
参数说明:
-server
-Xmx3g # 最大堆内存
-Xms3g # 最小堆内存
-Xss # 线程栈的大小
-XX:+HeapDumpOnOutOfMemoryError # 发生OOM错误
-XX:HeapDumpPath=/tmp/heap_dump # 备份HeapDump的路径
-XX:MaxPermSize=128m # 永久代,java8去除永久代的概念,改用元数据空间
-XX:NewRatio=2 # eden/old 的比例
-XX:SurvivorRatio=8 # s/e 的比例
-XX:+UseParallelGC
-XX:ParallelGCThreads=8
-XX:+UseParallelOldGC # 这个是JAVA 6出现的参数选项
-XX:LargePageSizeInBytes=128m # 内存页的大小, 不可设置过大,会影响Perm的大小
-XX:+UseFastAccessorMethods # 原始类型的快速优化
-XX:+DisableExplicitGC # 关闭System.gc()
内存参数:
- 堆内存
- 新生代 eden survivor
- 老年代 tenured
- 非堆内存:metaspace codecache
- GC 垃圾回收:期望回收次数越少越好,回收时间越短越好。
调优:最大堆内存=最小堆内存
-
新生代内存满了,触发局部GC
老年代内存满了,触发全部GC
调优:新生代:老年代=1:4
JVM OOM 排查
- 查看日志,发现故障原因是OOM
grep java.lang.OutOfMemoryError /app/apache-tomcat-8.5.61/logs/catalina.out
- MAT分析堆内存的备份
/tmp/heap_dump