Skip to content

JVM vs JRE vs JDK 的 区别

JVM(Java Virtual Machine)

  • 提供了 Java 程序运行的虚拟环境,实现“一次编译,到处运行”。
  • 只要环境支持 JVM,就能运行 Java 程序,但同时也会消耗较多系统内存,容易引起内存不足(OOM)。

JRE(Java Runtime Environment)

  • 包含 JVM 以及 Java 程序运行所必需的库和依赖,是 Java 应用的运行环境。

JDK(Java Development Kit)

  • 包含 JRE 和开发工具(如编译器、调试工具等),用于 Java 程序的开发和排查问题。

配置JDK和tomcat

shell
#安装JDK
rpm -ivh jdk-8u351-linux-x64.rpm 

java -version

#解压apache-tomcat的tar包 到/app/tools/
mkdir -p /app/tools/

tar -xf apache-tomcat-9.0.52.tar.gz  -C /app/tools/
#当升级 Tomcat 到新版本时,新版本通常会安装在一个带有版本号的目录中,比如 /app/tools/apache-tomcat-9.0.52/。
#如果所有相关配置、脚本和服务引用的是固定的软链接路径(如 /app/tools/tomcat),
#只需要修改软链接的目标指向新版本目录,就能快速切换,无需逐一修改各处引用。
ln -s /app/tools/apache-tomcat-9.0.52/  /app/tools/tomcat 

cd /app/tools/

ll
#检查 Tomcat 版本信息,同时确认 JDK 部署正确。
/app/tools/tomcat/bin/version.sh 

#启动:bin/startup.sh 或 catalina.sh start
#停止:bin/shutdown.sh 或 catalina.sh stop

/app/tools/tomcat/bin/startup.sh 
#查看端口
ss -lntup | grep java
#查看 Java 进程
ps -ef | grep java

java -version

tmocat目录

目录文件说明
bintomcat的管理脚本. catalina.sh 做jvm优化 startup.sh shutdown.sh用于启动、关闭Tomcat以及进行JVM优化等相关操作
confserver.xml 主要配置文件 logging.properties 日志功能配置文件包含Tomcat的主要配置以及日志相关的配置
libtomcat依赖的目录,一般是.jar结尾.存放Tomcat运行所依赖的JAR包
logs日志 catalina.out 应用日志,业务日志. accessxxxlog访问日志记录Tomcat运行过程中的各种日志信息,包括应用日志、业务日志和访问日志等,查看时一般关注业务/应用日志中的关键词如error、failed、exception等
webapps站点目录用于部署Web应用程序
work加载jvm中的文件信息.存放Tomcat在运行时加载到JVM中的文件相关信息

systemctl配置

shell
pkil java
ps -ef | grep java
ss -lntup | grep java

vim  /usr/lib/systemd/system/tomcat.service
###########################
[Unit]
Description=Tomcat  java web container #描述服务(如“Tomcat java web container”)。
After=network.target #确保网络服务启动后再启动 Tomcat。

[Service]
Type=forking   #表示该服务采用 fork 模式启动(启动脚本会创建子进程)。
#EnvironmentFile=/etc/sysconfig/tomcat
ExecStart=/app/tools/tomcat/bin/startup.sh#分别指向 Tomcat 的启动和关闭脚本。
ExecStop=/app/tools/tomcat/bin/shutdown.sh#指定服务在哪个运行级别下自动启动。


[Install]
WantedBy=multi-user.target

################################
#重新加载systemctl 配置
systemctl daemon-reload tomcat 
#然后systemctl 管理tomcat开机自启动与启动服务
systemctl enable --now  tomcat

Java 业务部署流程

完整部署流程

  • 开发到部署的基本流程:
    1. 开发源代码
    2. 编译打包:将源代码编译后打成 war 包或 jar 包。
    3. 部署:
      • war 包:通常部署到 Tomcat 中,由 Tomcat 解析和运行。
      • jar 包:可直接使用 java -jar xxx.jar 运行,其中 jar 内部可能已经集成了嵌入式容器(如 Tomcat 或 Jetty)。
  • 系统服务管理
    • 在部署完成后,通过 systemctl 对 Tomcat 或 Java 服务进行管理,实现自动重启、开机自启等功能。

jar包部署

shell
#查看日志
cat /app/tools/tomcat/logs/catalina.out 

#前台运行
java -jar -Dfile.encoding=UTF-8 nginxWebUI-3.4.0.jar --server.port=8848 --project.home=/app/code/ngx/

#后台运行
nohup java -jar -Dfile.encoding=UTF-8 nginxWebUI-3.4.0.jar --server.port=8848 --project.home=/app/code/ngx/ &


1. nohup
作用:nohup 命令用于在 Linux/Unix 系统中运行一个进程,使其不受挂起(hangup)信号的影响,即使你退出终端,该进程仍会继续运行。
用途:常用于需要长时间运行、后台执行的任务。
2. java -jar
作用:java -jar 命令用来启动一个 Java 应用程序,该程序以 JAR(Java ARchive)文件的形式打包。
说明:在这里,nginxWebUI-3.4.0.jar 是待执行的 JAR 文件,代表一个特定版本(3.4.0)的 Nginx WebUI 应用。
3. -Dfile.encoding=UTF-8
作用:这是一个 JVM 参数,用来设置 Java 程序的默认字符编码为 UTF-8。
原因:设置为 UTF-8 可保证程序在处理文本(尤其是中文)时不会出现编码问题,从而避免乱码现象。
4. 参数说明:--server.port=8848 --project.home=/app/code/ngx/
--server.port=8848:
作用:指定应用程序启动时所监听的服务器端口为 8848。也就是说,程序启动后会在此端口上提供服务。
--project.home=/app/code/ngx/:
作用:设定程序运行时的项目根目录或配置目录为 /app/code/ngx/。这个参数通常用于让程序知道在哪个目录下查找配置文件、日志或其他资源。
5. & (后台运行)
作用:在命令末尾添加 &,表示将该命令放入后台运行,这样终端就不会被该进程占用,可以继续执行其他命令。

部署简单的应用

  • 创建zrlog库,添加zrlog用户并配置密码.
  • zrlog.war放在tomcat webapps目录下.

- 数据库

shell
#数据库处理
[root@db01 ~]# mysql -u root -p

MariaDB [(none)]> create database zrlog
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> GRANT ALL ON zrlog.* TO 'zrlog'@'172.16.1.%' IDENTIFIED BY 'lidao';
Query OK, 0 rows affected (0.001 sec)

MariaDB [(none)]> GRANT ALL ON zrlog.* TO 'zrlog'@'localhost' IDENTIFIED BY 'lidao';
Query OK, 0 rows affected (0.000 sec)

MariaDB [(none)]> exit

--将 应用部署为 Tomcat 的默认(ROOT)站点

shell
#移动 war 文件到 webapps 目录
mv zrlog.war /app/tools/tomcat/webapps/
systemctl stop tomcat

rm -rf ROOT

#zrlog成ROOT目录,解压后的 zrlog 应用目录被重命名为 ROOT,
#这样 Tomcat 将其作为默认站点处理(即通过直接访问服务器 IP 或域名时,会访问这个应用)。
mv zrlog ROOT
#重启 Tomcat 后,Tomcat 会以 ROOT 为上下文路径部署该应用。
mv zrlog.war ROOT.war

systemctl start tomcat

--- nginx 与 Tomcat 实现动静分离

通过 nginx 作为前端反向代理,将请求转发到 Tomcat 上,从而实现负载均衡、静态资源缓存等

接入NGINX方便对静态资源做处理

shell
#配置 Nginx 软件仓库
[root@web01 ~]# cat /etc/yum.repos.d/ngx.repo 
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[root@web01 ~]# yum -y install nginx

#修改default.conf
#default_server:表示当前 server 块是 默认的虚拟主机。
#当客户端请求的域名或 IP 地址与所有 server_name 都不匹配时,
#Nginx 会使用该 default_server 来处理请求。

[root@web03 ~]# cat  /etc/nginx/conf.d/zrlog.oldblinux.cn.conf 
server {
	listen 80;
	server_name zrlog.oldboylinux.cn;
	#accesslog
  #eccorlog
	
	location / {
	proxy_pass http://127.0.0.1:8080;
	proxy_set_header Host $http_host;
	proxy_set_header X-Fordwarded-for $proxy_add_x_forwarded_for;
	proxy_set_header X-Real-Ip $remote_addr;
	}
  location ~* \.(html|css|js|jpg|png|jpeg)$ {
		root /app/tools/tomcat/webapps/ROOT/;
		expires 7d;	
	}
}

#Tomcat有权限问题,目录755,文件644如果文件名中可能包含空格或特殊字符
#使用 -print0 和 xargs -0 来确保正确处理文件名:
{root@web03 ~]# find /app/tools/tomcat/webapps/ -type f -print0 | xargs -0 chmod 644 --
[root@web03 ~]# find /app/tools/tomcat/webapps/ -type d -print0 | xargs -0 chmod 755 --
或者
#find /app/tools/tomcat/webapps/ -type f -exec chmod 644 {} \;
#find /app/tools/tomcat/webapps/ -type f -exec chmod 644 {} \;

#检测配置文件
nginx -t 
#windows host解析

tomcat vs nginx对比

tomcat vs nginx对比tomcatnginx
web端口Connector=8080listen 80/443
站点/虚拟主机<Host></Host>
部分
server{}部分
域名name="localhost"server_name
站点目录appBase="webapps"root
自动解压(war包解压目录) zip压缩包unpackWARs="true"
自动部署(加载jvm)autoDeploy="true"

Tomcat 配置文件-访问日志格式

访问日志格式项说明Tomcat对应配置项
客户端ip地址记录访问客户端的IP地址%h
访问的时间记录请求访问的时间%t
请求起始行(请求方法,URI)包含请求的方法(如GET、POST等)和请求的URI%r
状态码记录服务器响应的状态码(如200、404等)%s
大小记录响应内容的大小(以字节为单位)%b
从哪里跳转来的(用户如何访问网站)记录请求的来源引用地址%{Referer}i
客户端类型,浏览器记录客户端使用的浏览器类型等信息%{User-Agent}i
XFF头记录记录X-Forwarded-For头信息,用于获取客户端真实IP(在经过代理时)%{X-Forwarded-For}i
shell
tar -xf apache-tomcat-9.0.52.tar.gz 

cp -r apache-tomcat-9.0.52 tomcat_8081
cp -r apache-tomcat-9.0.52 tomcat_8082

sed -i 's/8080/8081/g' tomcat_8081/conf/server.xml 
sed -i 's/8080/8082/g' tomcat_8082/conf/server.xml 
sed -i 's/8085/8086/g' tomcat_8081/conf/server.xml 
sed -i 's/8085/8087/g' tomcat_8082/conf/server.xml 

echo 8081tomcat > tomcat_8081/webapps/ROOT/index.jsp 
echo 8082tomcat > tomcat_8082/webapps/ROOT/index.jsp 

mv tomcat_808* /app/tools/

cd /app/tools/
cd tomcat_8081
cd bin/

./startup.sh 
/app/tools/tomcat_8082/bin

./startup.sh 

[root@web03 /app/tools/tomcat_8082/bin]# curl http://10.0.0.9:8081/index.jsp
8081tomcat
[root@web03 /app/tools/tomcat_8082/bin]# curl http://10.0.0.9:8082/index.jsp
8082tomcat

Java 进程和线程监控命令

查看 Java 进程信息:

- `ps`: 查看所有进程
- `jps -lvm`: 列出所有 Java 进程及其详细信息
- `jstack <PID>`: 查看进程的线程信息

进程和线程基本概念:

- 进程:是正在运行的程序实例,具有独立的内存空间、资源(文件描述符、网络连接等)和执行环境。进程间相互隔离。
- 线程:是进程内的最小执行单元,同一进程内的线程共享内存和资源。多线程提高资源利用率,但要注意线程安全问题。

查看线程状态:

- `jstack <PID> | grep -i thread.state`: 查看线程的状态,如 `RUNNABLE`, `WAITING`, `TIMED_WAITING`。
- `jstack <PID> | grep -i thread.state | awk '{print $2}'`: 提取线程的状态。
- `top -H -p <PID>`: 查看进程内的线程。
- `ps aux` 或 `ps -efL`: 列出进程和线程。
shell
[root@web03 /app/tools/tomcat_8082/bin]# jstack 4637| grep -i thread.state
   java.lang.Thread.State: RUNNABLE
   java.lang.Thread.State: TIMED_WAITING (sleeping)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: RUNNABLE
   java.lang.Thread.State: TIMED_WAITING (parking)
   java.lang.Thread.State: TIMED_WAITING (sleeping)
   java.lang.Thread.State: TIMED_WAITING (parking)
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
   java.lang.Thread.State: WAITING (on object monitor)
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
   java.lang.Thread.State: WAITING (parking)
   java.lang.Thread.State: TIMED_WAITING (parking)
   java.lang.Thread.State: WAITING (on object monitor)
   java.lang.Thread.State: RUNNABLE

线程状态解释:

- `NEW`: 线程已创建但尚未启动。
- `RUNNABLE`: 线程正在运行或准备运行。
- `BLOCKED`: 线程被阻塞,等待监视器锁。
- `WAITING`: 线程无限期等待。
- `TIMED_WAITING`: 线程在指定时间内等待。
- `TERMINATED`: 线程执行完毕,已终止。
状态描述
NEW线程已创建但尚未启动(未调用start()方法)。
RUNNABLE线程正在运行或准备运行,等待CPU调度。
BLOCKED线程被阻塞,等待获取监视器锁(例如,进入同步块或方法)。
WAITING线程无限期等待,直到被其他线程显式唤醒(例如,调用object.wait())。
TIMED_WAITING线程在指定时间内等待(例如,调用Thread.sleep()或object.wait(timeout))。
TERMINATED线程已执行完毕,终止状态。

内存和堆转储:

- `jmap -heap <PID>`: 查看堆内存情况。
- `jmap -dump:format=b,file=<file_path> <PID>`: 将堆内存转储到文件。
shell
jmap -heap 803
jmap -dump:format=b,file=/root/test.hprof 803

使用 MAT(Memory Analyzer Tool)分析堆内存转储。

mat #windows 桌面

Java 负载排查流程

  1. 查看系统负载:
    • uptimetop: 检查系统负载情况,查看 load average。
    • 高 load average:可能表示 CPU 或 I/O 瓶颈。
  2. 检查 CPU 使用情况:
    • top -o %CPU: 查看 CPU 使用率。
    • htop: 更直观地查看系统状态(需安装)。
    • 关注 %CPU 高的进程 和 wa(I/O 等待)高的情况。
  3. 检查内存使用情况:
    • free -h: 查看内存使用情况,注意 available 是否低。
    • swapon -s: 查看 swap 使用情况。
  4. 检查磁盘 I/O:
    • iostat -x 1: 查看磁盘 I/O 使用情况,关注 await%util
    • iotop: 实时查看 I/O 占用高的进程。
  5. 检查网络:
    • iftop -nPnload: 查看网络流量。
    • ss -s: 查看网络连接统计。

进程分析

  1. 判断进程做什么:
    • ps aux | grep <PID>: 查看进程信息。
    • top -p <PID>: 查看特定进程的 CPU 使用情况。
    • 查看进程文件句柄:ls /proc/<PID>/fd/
    • 查看进程命令行参数:cat /proc/<PID>/cmdline
    • 查看进程使用的库:ldd /proc/<PID>/exe
    • 查看进程调用的系统资源:strace -p <PID>(如果有大量 openread/write,表示进程在读写文件)。
    • 查看进程的网络连接:ss -ntp | grep <PID>
  2. 判断进程的文件写入:
    • 使用 lsof -p <PID>:列出进程打开的所有文件。
    • 监控进程的文件写入:strace -p <PID> -e write
    • 使用 iotop 结合 lsof:先用 iotop 发现高 I/O 的进程,再用 lsof 查找它打开的文件。

Java 负载均衡排查

  1. IO 定位:
    • ps aux | grep tomcat: 查找 Tomcat 进程。
    • cat /proc/<PID>/io: 查看进程的 I/O 使用情况。
    • lsof -p <PID>: 查看进程打开的文件。
    • iotop -o -P: 查看进程的 I/O 使用情况。
    • ll /proc/<PID>/fd: 查看进程打开的文件句柄。
  2. strace 排查:
    • strace -p <PID>:跟踪进程系统调用,帮助判断进程正在执行什么操作。

Tomcat 配置 https

shell
mkdir -p /app/tools/tomcat/cert/

unzip 17542969_ssl.oldboylinux.cn_tomcat.zip 

#修改server.xml
vim server.xml 
 <Connector port="8443"   
    protocol="HTTP/1.1"
    SSLEnabled="true"
    scheme="https"
    secure="true"
    keystoreFile="/app/tools/tomcat/cert/ssl.oldboylinux.cn.pfx" 
    keystoreType="PKCS12"
    keystorePass="3kw46im6"  
    clientAuth="false"
    SSLProtocol="TLSv1.1+TLSv1.2+TLSv1.3"
  ciphers="TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256"/>


systemctl restart tomcat

vim /etc/hosts

curl -Lv https://ssl.oldboylinux.cn:8443/admin/login
curl https://10.0.0.9:8443

部署 Zrlog 集群模式,实现动静分离

角色/功能描述详细信息/说明
lb负载均衡keepalived
Web服务器web03, web04
数据库服务器db
存储目录attached目录
备份backup

部署 Zrlog

shell
# 在 web01 上下载并上传 Zrlog WAR 包至指定目录

# 1. 创建 /zrlog 目录用于存放 WAR 包
mkdir /zrlog

# 2. 进入该目录
cd /zrlog/

# 3. 下载 Zrlog WAR 包
wget https://dl.zrlog.com/release/zrlog.war

# 4. 重命名下载的 WAR 包为 ROOT.war(Tomcat 默认部署文件名)
mv zrlog.war ROOT.war

# 5. 重启 Tomcat 应用以自动部署 ROOT.war 包
/soft/tomcat/bin/shutdown.sh
/soft/tomcat/bin/startup.sh

# 6. 检查 Tomcat 启动日志,确认 Zrlog 部署是否成功
tail -f /soft/tomcat/logs/catalina.out

# 7. 修改 Windows 的 hosts 文件,添加解析
# 编辑 C:\Windows\System32\drivers\etc\hosts,添加如下内容:
# 10.0.0.7 zrlog.oldboy.com

# 8. 解压 WAR 包(如果需要)到 /zrlog 目录下
# 例如:
# unzip /zrlog/ROOT.war -d /zrlog/

# 配置远程数据库连接

# 9. 创建 Zrlog 数据库并授权远程访问(在 MariaDB 中执行)
MariaDB [(none)]> create database zrlog charset utf8;

# 10. 创建用户并授权远程访问(确保 MySQL 远程连接已授权)
MariaDB [(none)]> grant all privileges on *.* to 'lzy'@'%' identified by 'lzy123.com';

# 11. 访问 Zrlog 站点:通过浏览器访问 zrlog.oldboy.com

前后端分离

shell
# 创建后台和前端的文件夹
[root@web03 ~]# mkdir -p /app/code/exam/{backend,fronend}

# 解压并移动前端文件到正确目录
[root@web03 ~]# unzip exam-web-前端.zip 
[root@web03 ~/exam-web-前端]# mv admin/ student/ /app/code/exam/fronend/

# 启动 Spring Boot 应用,设置时区和使用生产环境配置文件
[root@web03 ~]# java -Duser.timezone=Asia/Shanghai -jar -Dspring.profiles.active=prod xzs-3.9.0.jar

# 查看日志,确认应用是否启动
[root@web03 /app/code/exam/backend]# cat xzs.20250312.log 

# 配置 Nginx 服务,使得前端和后端请求可以通过域名访问
[root@web03 /etc/nginx/conf.d]# cat /etc/nginx/conf.d/exam.conf
server {
    listen 80;
    server_name admin.oldboylinux.cn; 
    root  /app/code/exam/front/admin/;
    location / {
        index index.html;
    }
    location /api/ {
        proxy_pass  http://localhost:8000;
    }
}
server {
    listen 80;
    server_name stu.oldboylinux.cn;
    root  /app/code/exam/front/student/;
    location / {
        index index.html;
    }
    location /api/ {
        proxy_pass  http://localhost:8000;
    }
}

# 测试 Nginx 配置文件的语法是否正确
[root@web03 /app/code/exam]# nginx -t 

# 重启 Nginx 使配置生效
[root@web03 /app/code/exam]# systemctl restart nginx

配置负载均衡

shell
# 定义负载均衡池 zrlog_pools,其中包括两个后端服务器 10.0.0.9 和 10.0.0.10
# 负载均衡会将流量轮流分发到这两个服务器上
upstream zrlog_pools {
    server 10.0.0.9:80;  # 后端服务器 1
    server 10.0.0.10:80; # 后端服务器 2
}

server {
    listen 80;  # 监听 80 端口,即 HTTP 请求
    server_name zrlog.oldboylinux.cn;  # 设置服务器域名,用于接收域名 zrlog.oldboylinux.cn 的请求

    # 以下两行可以用于启用错误日志和访问日志
    # error_log /var/log/nginx/error.log;
    # access_log /var/log/nginx/access.log;

    location / {
        # 将所有请求转发给 upstream zrlog_pools 配置的后端服务器
        proxy_pass http://zrlog_pools;

        # 设置请求头,以确保后端服务器能够获取到客户端的真实信息
        proxy_set_header Host $http_host;  # 设置 Host 头,确保后端获取到原始请求的域名
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 将客户端的真实 IP 地址传递给后端服务器(可能经过负载均衡器时)
        proxy_set_header X-Real-Ip $remote_addr;  # 设置 X-Real-Ip 头,传递客户端的真实 IP 地址

        # 注意:如果你需要在访问日志中显示客户端的真实 IP 地址, 
        # 你需要修改 Nginx 的 log_format 配置,增加 `$http_x_real_ip` 变量
    }
}

配置 NFS

shell
# 在 nfs01 上配置 NFS 服务

# 1. 配置 NFS 共享目录
# 编辑 /etc/exports 文件,指定共享目录及访问权限
echo "/nfs/blog/ 172.16.1.0/24(rw,all_squash,anonuid=1999,anongid=1999)" >> /etc/exports

# 2. 重启 NFS 服务
systemctl restart nfs

# 3. 检查共享状态,确认配置成功
cat /var/lib/nfs/etab

# 4. 设置共享目录的权限,确保 Web 服务器能够访问
chown -R nobody.nobody /nfs/zrlog/

# 在 web03 和 web04 上挂载 NFS 共享目录

# 5. 挂载 NFS 共享目录到 Tomcat 的 attached 目录
mount -t nfs nfs01:/nfs/zrlog/ /app/tools/tomcat/webapps/ROOT/attached

# 6. 验证挂载成功,查看挂载的文件系统
df -Th

# 7. 将静态文件移入挂载目录,确保所有服务器都能访问
mv attached-bak/* attached/
rm -rf attached-bak/

# 8. 配置永久挂载,修改 /etc/fstab 文件确保系统重启后挂载
echo "nfs01:/nfs/zrlog/ /app/tools/tomcat/webapps/ROOT/attached nfs defaults 0 0" >> /etc/fstab

# 9. 重启 Web 服务器后,挂载将自动生效。也可以手动挂载:
# mount -a

感谢阅读,欢迎交流!