前言
本文主要是tomcat的学习笔记以及案例跑通记录,主要包括tomcat部署安装、JVM、同nginx协作实现负载均衡,目前工作涉及该方面的内容不多,后续遇到tomcat相关问题再记录。
1. Tomcat基础学习
Tomcat是免费、轻量级的,专门为Java网页设计的服务器
Tomcat的运行过程类似点外卖:你(浏览器)下单 → 外卖小哥(Tomcat)接单 → 厨师(Java代码)做饭 → 小哥把饭(HTML)送回给你
建议使用Nginx和Tomcat配合,Nginx处理静态,Tomcat处理动态程序
1.1 Tomcat安装部署
安装时候选择tomcat软件版本要与程序开发使用的版本一致,而jdk版本要进行与tomcat保持一致
虚拟机上已经安装了JDK,JDK的版本为1.8.0,因此,Tomcat最好选择8.5或者9.0的,比较兼容jdk1.8

1.1.1 解压安装
1、创建一个目录application用于存放tomcat
mdkir -p /data/application
# -p:自动创建父目录,如果data目录不存在,-p会先创建data目录,再在其下创建application
2、下载tomcat压缩包后解压到application文件夹中
wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.96/bin/apache-tomcat-8.5.96.tar.gz
# 从官网上下下载安装包
tar -zxvf apache-tomcat-8.5.96.tar.gz -C /data/application/
# 解压到application文件夹中,-C表示解压到指定目录
cd /data/application
mv apache-tomcat-8.5.96/ tomcat
# 可以把名字重命名为tomcat
3、配置环境变量,我选择在~/.bash_profile中进行配置
# 用户级,永久生效
vim ~/.bash_profile
# Tomcat 环境变量
export CATALINA_HOME=/data/application/tomcat
export PATH=$CATALINA_HOME/bin:$PATH
#生效配置
source ~/.bash_profile
环境变量配置完成,验证显示对应的信息

(4)启动Tomcat
$CATALINA_HOME/bin/startup.sh
# $CATALINA_HOME是tomcat的安装目录,前面环境变量设置了的
# 在浏览器上输入http://localhost:8080,确认tomcat能否正常运行
# 因为设置了环境变量,可以直接启动和关闭
startup.sh # 启动
shutdown.sh # 关闭

1.1.2 将war包部署到tomcat上
1、首先要将需要部署的程序打包成war包,然后复制到tomcat的实例webapps目录中(打包的war包有.war这样的后缀)
mv itemDubbo.war /tomcat/webapps/
# 类似这样的,把war包移动到tomcat/webapps目录下
将war包移动到该目录下它自己就自动部署了,你能在该目录下看到一个同名的文件目录
2、对相关文件进行配置,这个主要是根据需求进行配置,本次操作没有什么配置需要更改,因此都是默认的配置
3、tomcat自动部署后,可以关闭重新启动以下tomcat,然随后在浏览器上输入对应的网址,就可以看到静态页面展示了(比如localhost:8080/war包名/静态页面)
PS.后面有tomcat全流程实践的记录,这一部分有点不清楚的,后面有详细的操作步骤
1.2 Java虚拟机(JVM)
JVM是Java程序的“运行环境”,把Java代码翻译成机器能懂的语言,Java代码能在Windows、Mac、Linux上跑,因为JVM会适配不同系统(一次编写,到处运行)
它能够合理分配内存,避免爆仓,同时会定期回收垃圾,保持环境整洁,以通过参数调整它的行为
1.2.1 JVM内存分区
(1)程序计数器(PC Register)
PC寄存器记录当前线程所执行的字节码指令的地址,由于执行是连续的,当前指令的完成必然导向下一条指令,因此它间接包含了下一步信息
每个线程都有独立的程序计数器,内存最小,没有内存溢出问题,几乎不会出错
(2)虚拟机栈(Stack)
每个线程运行时所需要的内容被成为虚拟机栈,由多个栈帧组成,对应着每次方法调用时所占用的内容,方法结束会自动清理
每个线程只能有一个活动栈帧,对应着当前正在执行的方法,栈是私有的,可能会出现栈溢出(StackOverflowError)和栈扩展失败(OutOfMemoryError)异常
(3)本地方法栈(Native Method Stack)
存“调用本地方法(C/C++代码)的记录”,和虚拟机栈作用相似,区别在于它为Native方法服务,普通Java开发者很少直接接触
类比工厂里偶尔需要请外部专家(C语言程序员)帮忙,他们的记录单独存
(4)堆(Heap)
JVM管理的最大一块内存区域,被所有线程共享,在虚拟机启动时创建,也是垃圾收集器管理的主要区域,当堆无法分配内存且无法扩展时,抛出OutOfMemoryError(容易爆满)
分代管理:
新生代(Young Generation):新对象创建区域
Eden区:对象初次分配区
Survivor区:经过Minor GC后存活的对象
老年代(Old Generation):长期存活的对象
(5)方法区(Method Area)
所有线程共享方法区,存储已被虚拟机加载的类型信息、常量、静态变量等数据,当方法区无法满足内存分配需求时,抛出OutOfMemoryError
永久代→元空间:
JDK7及之前:永久代(PermGen),堆里面固定的特殊书架,存放不会变动的"经典书籍"(包含运行时常量池:存放编译期生成的各种字面量和符号引用)
JDK8+:元空间(Metaspace),使用本地内存的弹性云书架(动态性:运行期间也可以将新的常量放入池中)
1.2.2 垃圾回收(GC)
JVM派“清洁工”(GC)定期打扫,扔掉无用对象
(1)可达性分析:从“根对象”(如栈中的变量、静态变量)出发,画一条路径能到达的对象就是“有用”的,否则视为垃圾
(2)常见的GC算法:
Serial GC:单线程打扫,适合小程序(像一个人慢慢扫地)
Parallel GC:多线程打扫,适合大程序(像一群人一起扫地,速度快但可能撞到一起)
G1 GC:把仓库分成小块,按需打扫(像用吸尘器分区清洁,适合大内存)
CMS/ZGC:清洁工边打扫边让工人绕行,几乎不停产(高并发场景)
(3)GC的“两阶段”:标记(Mark)-标记哪些对象是垃圾;清除(Sweep)-清理标记的垃圾
(4)GC的“副作用”:停顿(Stop-The-World)-打扫时工厂暂停生产(应用暂停响应);目标-减少停顿时间,提高吞吐量(比如1秒内GC用0.1秒,吞吐量90%)。
1.2.3 内存管理
(1)内存管理的任务:
合理分配空间(给新物品找位置);跟踪物品使用情况(记录哪些物品还在用);及时清理垃圾(扔掉没用的,腾出空间)
(2)目标:
避免仓库塞满(内存溢出);快速找到需要的物品(高效访问);减少清理时间(低GC停顿)
(3)分区:堆和非堆
堆:主仓库,存放所有对象实例,内存最大,由GC自动管理
堆(Heap)
├── 新生代(Young Generation) (默认占堆的1/3)
│ ├── Eden区 (新对象默认分配这里-临时货架,很快可能被扔掉)
│ ├── Survivor 0(From区) (Minor GC后存活对象临时存放-试用货架,用了一段时间还没坏,暂时保留)
│ └── Survivor 1(To区) (与From区交替使用,始终有一个为空)
└── 老年代(Old Generation) (长期存活对象或大对象直接进入-长期储物柜,贵重或常用的物品,很少清理)
非堆:工具间,存放方法区、运行时常量池、JIT编译代码,内存小,单生命周期长,不由GC管理
1.2.4 调优
(1)核心目标:让内存分配合理,减少Full GC次数;让GC更快完成,减少停顿时间(提高GC效率);避免极端情况,保障系统稳定运行
(2)调优的三个关键步骤:观察现状(Minor GC频率、Full GC频率、GC停顿时间);调整参数(年轻代调优-解决Minor GC问题,年老代调优-解决Full GC问题,选择垃圾回收器-换打扫工具);验证效果(压测验证、日志分析)
(3)常见场景调优方案:
a. Web应用(eg.Spring Boot)响应慢,Full GC频繁,停顿时间>200ms
启用 G1 回收器:-XX:+UseG1GC
增大堆内存:-Xms2g -Xmx2g
调整 G1 参数:-XX:MaxGCPauseMillis=100(目标停顿 100ms)
b. 批处理任务(如大数据计算)吞吐量低,Minor GC 太频繁,CPU 占用高
增大年轻代:-Xmn1g
使用 Parallel GC(默认):-XX:+UseParallelGC
调整并行线程数:-XX:ParallelGCThreads=4(根据 CPU 核心数设置)
c. 内存溢出(OOM),老年代或元空间不足,应用崩溃
增大堆内存:-Xms4g -Xmx4g
检查是否有内存泄漏(如缓存未清理、静态集合无限增长)
元空间溢出时:-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
2. Tomcat案例跑通记录
2.1 Tomcat简单部署
写一个简单的JAVA程序,有一个静态显示“Hello World!”的界面,将该程序进行打包后,打开已经安装好tomcat的虚拟机,将war包放进虚拟机中(如果是用主机,可以直接把war包扔进在用户目录下安装的tomcat的webapps文件目录中)

tomcat自动部署后,可以关闭重新启动以下tomcat,然随后在浏览器上输入对应的网址,就可以看到静态页面展示了

2.2 Tomcat后端服务配置连接
2.2.1 配置文件
2.2.1.1server.xml 文件
配置 Tomcat 的全局行为,如监听端口、主机名、应用部署路径等
(1)位置:tomcat/conf/server.xml
(2)核心结构和参数配置:
<Server port="8005" shutdown="SHUTDOWN"> # Tomcat 的顶层容器,管理生命周期
# port:关闭 Tomcat 的监听端口(默认的管理端口为8005,如果8005端口被其他程序占用,需要修改)
# shutdown:关闭指令(发送 SHUTDOWN 到该端口会关闭 Tomcat)
<Service name="Catalina"> # 关联 <Connector> 和 <Engine>,一个 <Service> 可以包含多个连接器
<Connector # 监听端口,处理 HTTP/HTTPS/AJP 请求
port="8080" # HTTP默认8080,HTTPS默认8443
# 如果Nginx反向代理到Tomcat,需确保Nginx配置的proxy_pass指向正确的Tomcat端口(如 http://localhost:8080)
protocol="HTTP/1.1" # 协议类型(如 HTTP/1.1、HTTP/2、AJP)
connectionTimeout="20000" # 连接超时时间(毫秒)
redirectPort="8443" # 需要 SSL 重定向时的端口(如 HTTP → HTTPS)
maxThreads="200" # 最大线程数(并发处理能力)
acceptCount="100" # 等待队列长度(当线程忙时,新请求在此排队)
compression="on" # 启用压缩(on/off/force)
# 启用 HTTP 压缩,减少网络传输数据量,提升性能,适用于文本类资源(HTML、CSS、JS、JSON等)
compressableMimeType="text/html,text/xml" # 压缩的MIME 类型
/>
<Engine name="Catalina" defaultHost="localhost"> # 处理请求的核心引擎,关联一个或多个虚拟主机
# defaultHost:默认虚拟主机(当请求的域名不匹配任何 <Host> 时使用,确保所有请求都能被某个虚拟主机处理)
# 当请求的域名不匹配任何<Host>时,使用默认虚拟主机
<Host # 定义虚拟主机,允许一个Tomcat实例托管多个域名(如 example.com和example.org)
name="localhost" # 主机名(如localhost或 example.com)
appBase="webapps" # 应用存放目录(默认webapps)
unpackWARs="true" # 是否自动解压 WAR 文件
autoDeploy="true" # 是否自动部署新应用
>
<Context # 定义 Web 应用的上下文路径和配置
docBase="/path/to/app" # 应用目录或 WAR 文件路径
path="/myapp" # 访问路径(如 /myapp)
reloadable="true" # 是否自动重新加载(开发环境设为 true)
/>
</Host>
</Engine>
</Service>
</Server>
修改了Connector的port和Host的name

2.2.1.2 context.xml
配置应用的全局资源(如数据库连接池、安全约束),可作用于单个应用或全局
(1)位置:tomcat/conf/context.xml(全局配置);META-INF/context.xml(独立配置-独立配置可隔离差异,优先级高)
(2)核心作用:
a. 应用级配置隔离:全局配置适用于所有应用共享的同游设置(日志格式、全局安全约束等);独立配置适用于应用特有的资源定义(如数据库连接池、JMS 队列等)
b. 资源管理:定义数据库连接池、JMS队列等共享资源,配置JNDI资源
c. 性能优化:调整会话管理、缓存策略、线程池等参数
(3)关键参数:
<Context
path="/myapp" # 定义应用的访问路径,默认从文件名推断
docBase="/path/to/myapp" # 指定应用目录或War包路径(绝对或相对路径)
reloadable="true"
# 开发环境设置为true,自动检测WEB-INF/classes/和WEB-INF/lib/的变化并重新加载应用(默认为false)
# 生产环境必须设为false,避免性能损耗和潜在内存泄漏
crossContext="false" # 是否允许跨应用访问(默认禁用,安全风险),true为允许同一 Tomcat 实例下的不同应用共享ServletContext对象
privileged="false" # 是否允许访问服务器内部资源(如Tomcat管理接口),防止恶意应用通过 file:// 协议读取 /etc/passwd 或访问Tomcat管理界面
swallowOutput="true" # 否将System.out/err重定向到日志(默认true)
>
<Manager # 会话管理(跟踪用户状态,解决 HTTP 无状态问题)
pathname="/WEB-INF/session.ser" # 会话持久化文件路径(可选)
maxActiveSessions="1000" # 最大会话数(默认-1,无限制)
minIdleSwap="120" # 会话空闲多久后交换到磁盘(秒,0表示禁用)
saveOnRestart="true" # 服务器重启时是否保存会话
/>
<Resource # 数据库连接池,连接池可以复用数据库连接,减少连接建立和销毁的开销
name="jdbc/mydb" # JNDI名称,应用中通过此名称引用(格式通常为 java:comp/env/jdbc/mydb)
auth="Container" # 认证方式(Container:由容器管理资源;Application:由应用管理)
type="javax.sql.DataSource" # 资源类型(这里是数据库连接池的DataSource接口)
driverClassName="com.mysql.jdbc.Driver" # JDBC驱动类
url="jdbc:mysql://localhost:3306/mydb" # 数据库UR
username="root" # 数据库用户名
password="123456" # 数据库密码
maxTotal="50" # 最大连接数(连接池参数:总连接数上限)
maxIdle="10" # 最大空闲连接数(连接池参数:空闲时保留的连接数)
maxWaitMillis="10000" # 获取连接超时时间(毫秒,超过此时间未获取到连接则抛出异常)
/>
# JNDI资源映射
# 映射环境变量
<Environment
name="app.env"
value="production"
type="java.lang.String"
override="false" # 是否覆盖已有同名变量
/>
# 映射JavaMail会话(JMS队列)
<Resource
name="mail/Session"
type="javax.mail.Session"
auth="Container"
mail.smtp.host="smtp.example.com"
mail.smtp.user="user@example.com"
mail.smtp.password="password"
/>
# 安全约束
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="192\.168\.1\.\d+" # 允许访问的IP正则表达式
deny="" /> # 拒绝访问的IP(可选)
# 基于角色限制
<SecurityConstraint>
<WebResourceCollection>
<WebResourceName>Protected Area</WebResourceName>
<UrlPattern>/admin/*</UrlPattern> # 保护/admin路径
</WebResourceCollection>
<AuthConstraint>
<RoleName>admin</RoleName> # 仅允许admin角色访问
</AuthConstraint>
</SecurityConstraint>
</Context>
2.2.1.3 web.xml
为所有 Web 应用提供默认的 Servlet、Filter、MIME 类型映射等,定义 Tomcat 级别的公共行为(如默认欢迎页面、错误页面、字符编码等),优先级低于应用自身的 WEB-INF/web.xml
(1)位置:tomcat/conf/web.xml
(2)大多数修改的是WEB-INF/web.xml的配置,一般是开发人员开发的时候进行配置的
2.2.2 数据库连接
首先Java代码需要用InitialContext查找 JNDI 资源,确保代码中的JNDI名称和context中的一致
确保了Java代码中的内容,接下来就要根据Java代码和数据库设置context的参数了,MySQL的url大概长这样(jdbc:mysql://localhost:3306/mydb)

保存修改后的参数后,重新启动tomcat,随后在浏览器输入对应的地址,就能看到网页上显示数据库连接成功

2.2.3 JVM
2.2.3.1 JVM的组成(3个核心模块)
(1)类加载器(ClassLoader):把.class文件(Java字节码)招聘进JVM,并检查“入职资格”(安全性验证)
类加载子系统采用双亲委派模型,即当一个类加载器加载一个类时,它首先会将请求委派给父类加载器,只有当父类加载器无法完成加载任务时,才会尝试自己加载,这种模型保证了Java核心类库的稳定性和安全性。
(2)执行引擎(Execution Engine):将字节码逐行翻译成机器语言,并执行指令
是JVM的核心组件之一,它负责执行JVM中的字节码指令,执行过程可以分为三个阶段:字节码解析-指令执行(解释执行和即时编译执行)-结果输出
(3)运行时数据区(Runtime Data Area):划分内存区域,存放程序运行时的数据(对象、变量、线程栈等)
运行时数据区是JVM在运行Java程序时使用的内存区域,它被划分为几个不同的部分,每个部分都有其特定的用途,主要包括:程序计数器、虚拟机栈、本地方法栈、堆、方法区
2.2.3.2 垃圾回收
(1)流程:标记(从根出发,标记所有存活对象–能直接或间接找到的对象)-- 清理(扫描整个仓库,把没有标记的对象清理掉)-- 整理(可选,如果仓库变得碎片化,把存活的对象集中摆放,腾出连续空间)
(2)垃圾回收算法:
标记-清除(Mark-Sweep):最基础的算法
工作原理:从根出发,标记所有存活的对象后,扫描整个仓库,把未标记的对象清理掉,腾出空间
优点:简单直接,适合小仓库(小内存)
缺点:内存碎片(清理后,仓库里会留下零散的空位,新商品可能无法连续存放),效率低(每次清理都要扫描整个仓库,耗时较长)
复制算法(Copying):新生代的常用策略
工作原理:把仓库分成AB两区,初始只是用A区,清理时把A区所有存活对象复制到B区,按顺序拜访后直接清空A区,下次清理时角色互换
优点:无碎片(商品始终集中存放,新商品可以连续分配),高效(制存活对象比扫描整个仓库更快,尤其当存活对象少时)
缺点:空间浪费(始终有一半空间闲置),复制开销(如果存活对象很多,复制成本高)
适用场景:新生代-因为新生代对象大多短命,存活率低,复制成本低
标记-整理(Mark-Compact):老年代的优化策略
工作原理:标记阶段标记存活对象,在整理阶段把存活对象向仓库一端移动,腾出连续空间,然后清理另一端垃圾
优点:无碎片(商品集中摆放,新商品可以连续分配),适合老年代(老年代对象存活率高,复制算法成本高,标记-整理更高效)
缺点:移动对象耗时(整理阶段需要移动对象,可能增加停顿时间)
适用场景:老年代
分代收集(Generational Collection):现代JVM的核心思想
根据对象生命周期不同,新生代对象短命,存活率低,老年代对象长命,存活率高,因此新生代 用复制算法,高效清理短命对象,老年代用标记-清理或标记-整理算法,减少移动长命对象的开销
现代高效算法:G1和ZGC
G1(Garbage-First):把仓库分成多个小区域(Region),优先清理垃圾最多的区域,平衡吞吐量和暂停时间,适合大内存(如8GB+)
阶段:并发标记(部分工作在营业时完成),混合清理(同时处理新生代和老年代)
ZGC:超低延迟(暂停时间<10ms),适合超大内存(如TB级),使用染色指针和读屏障技术,几乎不停业
(3)常见的垃圾回收器:
Serial GC(单线程管理员):一个管理员独自完成标记、清理、整理,适合小仓库(小内存)、单核CPU,缺点是清理时仓库暂停营业(STW,Stop-The-World)
Parallel GC(多线程管理员):多个管理员一起工作,加快清理速度,适合大仓库(大内存)、多核CPU,优点是吞吐量高(总清理时间短),缺点是仍然会暂停营业,但每次暂停时间较短
CMS GC(并发清理,已废弃):部分工作(如标记)在营业时进行,减少暂停时间,碎片化严重,且JDK9+已废弃
G1 GC(分区管理员):把仓库分成多个区域(Region),优先清理垃圾多的区域,适合大仓库(大内存)、低延迟需求,优点是平衡吞吐量和暂停时间
ZGC/Shenandoah(超低延迟):几乎不停业(暂停时间<10ms),适合超大仓库,适合金融交易、实时系统
(4)垃圾回收的代价:
暂停营业(STW):清理垃圾时,仓库暂停服务(应用卡顿)
CPU开销:管理员工作需要消耗资源
内存碎片:清理后可能留下零散空位,影响新商品摆放
(5)优化目标:
减少垃圾产生:避免频繁创建无用对象(如循环内创建临时对象)
选择合适的GC算法:根据仓库大小(内存)和客流量(并发量)选择
调优参数:如-Xms(初始仓库大小)、-Xmx(最大仓库大小)、-Xmn(新生代区域大小)
(6)JVM默认的垃圾回收策略
Java 8及之前版本
新生代:默认使用 Parallel Scavenge(复制算法,多线程高吞吐)
老年代:默认使用 Parallel Old(标记-整理算法,多线程高吞吐)
整体策略:-XX:+UseParallelGC(Parallel GC组合,适合吞吐量优先的场景)
Java 9+ 默认策略变化
Java 9-14:默认使用 G1 GC(分区管理,平衡延迟和吞吐量)
Java 15+:G1成为更稳定的默认选项,部分版本开始支持ZGC作为实验性功能
Java 17+:G1是主流默认,ZGC/Shenandoah需手动启用
2.2.3.3 JVM堆内存修改
(1)基础参数:定义堆的“杯子大小”
-Xms:堆的初始容量,表示JVM启动时立即分配的堆内存大小(默认物理内存的1/64)
-Xmx:堆的最大容量,堆内存上限(默认物理内存的1/4)
-Xmn(新生代的专属杯子):新生代是堆中的“小杯子”,设置新生代大小,专门存放新对象(默认占堆的1/3)
调优建议:建议-Xms和-Xmx设为相同值(如-Xms2g -Xmx2g),避免动态扩容导致的性能抖动;高并发场景增大新生代(如-Xmn1g),减少Minor GC频率,大对象多时适当减小新生代,避免大对象直接进入老年代
(2)分代参数:精细控制“杯子里的隔层”
-XX:NewRatio(新生代与老年代的比例):NewRatio决定上下层容量比,新生代:老年代 = 1:NewRatio(默认2,即新生代占1/3)
-XX:SurvivorRatio(Eden与Survivor区的比例):SurvivorRatio决定Eden与单个Survivor区的比例,Eden:Survivor = SurvivorRatio:1(默认8,即Eden占8/10)
调优建议:对象存活率高时,增大老年代(如-XX:NewRatio=3),减少Full GC,对象存活时间短,增大Eden区(如-XX:SurvivorRatio=10),减少Minor GC次数;对象存活时间长,减小Eden区,让对象更快晋升到老年代
(3)GC相关参数:优化“倒水速度”
-XX:+UseSerialGC :Serial(复制) + Serial Old(整理),适合小内存(<100MB)、单核CPU
-XX:+UseParallelGC:Parallel Scavenge(多线程+复制) + Parallel Old(多线程+整理),适合高吞吐(如批处理、科学计算)
-XX:+UseG1GC:G1(统一管理新生代/老年代),优先回收垃圾多的区域,平衡吞吐量和延迟,适合大堆(4GB+)
-XX:+UseZGC:ZGC(统一管理),超低延迟(<10ms)、超大内存(TB级)
-XX:+UseShenandoahGC:Shenandoah(统一管理),低延迟(类似ZGC),Linux优化
-XX:+PrintGCDetails:记录“倒水日志”,开启GC日志,记录每次倒水的耗时和剩余水量
示例:
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/tmp/gc.log MyApp
# 通过日志分析GC频率和停顿时间,优化参数
(4)高级参数:应对极端场景
-XX:MaxTenuringThreshold(控制对象“晋升年龄”):对象在新生代“住满多少天”才能搬到老年代,默认15次Minor GC后晋升(范围0-15)
调优建议:对象存活时间短,减小阈值(如-XX:MaxTenuringThreshold=5),减少老年代碎片
-XX:+AlwaysPreTouch(预分配“虚拟内存”):启动时提前“灌满水杯”,避免运行时动态扩容,减少JVM启动后首次Full GC的停顿
示例:一个延迟敏感型应用,设为-XX:+AlwaysPreTouch -Xms8g -Xmx8g。
2.2.3.4 JVM堆内存调优
(1)位置:tomcat/bin/catalina.sh (用tomcat修改)
(2)修改:JAVA_OPTS或CATALINA_OPTS变量定义位置(若不存在则手动添加,看了下tomcat的catalina.sh文件,没有这两个变量,如果需要用tomcat修改,那么需要手动添加变量和相关参数)
# 堆内存8G,电商网站配置调优实践
JAVA_OPTS="-server -Xms8g -Xmx8g -Xmn4g \
-XX:+UseG1GC -XX:MaxGCPauseMillis=100 \
-XX:+PrintGCDetails -Xloggc:/logs/gc.log"
# -Xms8g -Xmx8g:避免动态扩容,确保内存稳定
# -Xmn4g:新生代4GB,老年代4GB,平衡Minor GC和Full GC。
# -XX:+UseG1GC:G1回收器适合大堆内存(8GB),平衡吞吐量和延迟
# -XX:MaxGCPauseMillis=100:目标最大GC停顿时间100ms
# -Xloggc:记录GC日志,便于后续分析
(3)JVM堆内存调优的核心是“平衡”,堆大小要够(避免OOM),但别浪费(避免内存闲置),新生代和老年代要分工明确,GC算法要因材施教(G1适合大堆,ParallelGC适合吞吐量有限),还需要通过监控GC日志和性能指标(如吞吐量、延迟)不断调整参数
2.3 tomcat作为前端容器
Tomcat 是一个开源的 Servlet 容器(也称为 Web 容器),主要用于部署和运行 Java Web 应用程序(如 JSP、Servlet),它不仅可以作为后端服务的容器,还可以作为 前端应用的容器,支持静态资源(HTML/CSS/JS)和动态内容(JSP/Servlet)的混合托管
2.3.1 tomcat处理静态资源
(1)支持文件类型:HTML、CSS、JavaScript、图片(JPG/PNG/GIF)、字体文件等。
(2)部署方式:将静态文件放在 ” webapps/war包解压后的文件夹/ “ 这个目录下
(3)访问地址:localhost:8080/war包解压文件/静态文件(如果是放在webapps/ROOT/这个目录下,就不用写war包解压文件)

最开始对tomcat进行部署然后显示helloworld界面就是采用的tomcat处理静态资源的类型
2.3.2 tomcat动态内容托管
(1)JSP(JavaServer Pages):允许在HTML中嵌入 Java代码,动态生成内容
(2)Servlet:处理 HTTP 请求(如REST API),返回JSON或重定向到前端页面,以下就是通过servlet进行映射,界面显示hello world


(3)可以直接访问.jsp的界面,也可以采用servlet进行转发,访问映射的文件地址(@WebServlet(“/api/data”) 这个注解来实现),不过关于这俩内容的访问和跳转,需要结合Java代码进行实现
2.3.3 反向代理与负载均衡
(1)首先,抓一下包测试一下三台主机网是不是通的(可以用ip a 查询主机IP),本虚拟机就是nginx所在的主机,ip地址为192.168.11.132,其余两台主机就是tomcat部署的主机,ip地址分别为192.168.11.139和192.168.11.140,因为没有域名,所以之后采用nginx的ip进行访问tomcat上面部署的hello world的界面

(2)接下来是关于tomcat配置文件的设置,主要是server.xml文件的Connecto的port,默认是8080,我们这边也没有去改变端口,如果8080端口被占用了就需要修改,另外,如果发现Server的端口port=8005被占用了,也需要进行修改,因为是两台新建的虚拟机,这些都不需要修改。然后host的参数,因为没有申请域名,这个也是默认的,不进行修改,如果有域名,可以添加域名的host参数。如果对tomcat的参数进行了修改,需要重启一下tomcat。(context.xml就根据之前进行数据库连接的时候修改就行,如果用不上也可以不改,关于JVM的设置,因为目前程序简单,就没有进行修改)
(3)最重要的是nginx的修改,需要修改nginx.conf中的内容。proxy_set_header是默认的,表示将原始请求的Host头传递给后端,当 Nginx 作为反向代理时,它会修改原始请求的某些信息(如目标地址),但需要保留原始 Host 头传递给后端(Tomcat),否则会导致Tomcat 无法正确匹配虚拟主机、影响应用上下文路径、安全性问题等(后端服务器只接受特定域名,或需要覆盖客户端原始 Host 头的时候,&host才可能修改,一般就默认)

(4)修改完nginx的配置文件后,重启一下nginx,然后输入nginx的ip和war就可以看到对应的界面啦

(5)验证是否完成了负载均衡,抓8080端口的包,核实两台主机的IP是交替进行的,表示是进行轮询访问的

总结
以上便是tomcat相关的学习笔记以及案例跑通的操作记录,关于JVM的部分概念较多,适合想起来的时候翻翻看
430

被折叠的 条评论
为什么被折叠?



