☰
Tomcat多实例部署实战:零成本隔离jpress多环境
2026/10/13 11:10:42 网站建设 项目流程

1. 项目概述:为什么需要在一台服务器上跑多个Tomcat实例?

“tomcat多实例---简单部署jpress网站”这个标题,表面看是个运维小技巧,但背后藏着的是中小团队最真实、最频繁的生产困境:资源有限,需求多样,又不能随便加机器。我接触过的某高校实验室、某初创内容平台、某本地化SaaS服务商,几乎都踩过同一个坑——一开始只装一个Tomcat,把所有Java Web应用(CMS、后台管理、API服务、测试Demo)全塞进去,结果改个jpress主题要重启整个容器,一重启,正在跑的数据报表服务就断了;或者测试新版本jpress时,不小心把生产环境的session配置覆盖了,用户集体掉登录。这种“一锅炖”式部署,不是省事,是埋雷。

所谓“Tomcat多实例”,本质是用同一套Tomcat二进制程序,启动多个相互隔离的运行环境。它不等于开多个虚拟机或Docker容器(那成本高、管理重),也不等于用Spring Boot内嵌Tomcat(jpress是传统WAR包架构,强依赖Servlet容器)。它的核心价值在于:零额外安装、低内存占用、配置级隔离、故障域收窄。你只需要一份apache-tomcat-9.0.x解压目录,就能同时跑出dev-jpress、test-jpress、prod-jpress三个完全独立的站点,端口、日志、webapps、JVM参数互不干扰。jpress作为基于JFinal框架的轻量级开源博客系统,对Tomcat版本要求明确(推荐8.5+或9.0+),又依赖JDBC数据源和文件上传路径,恰好是验证多实例部署逻辑的绝佳样本——它不复杂,但足够典型。

这个方案适合三类人:一是运维刚接手一批老旧Java项目的中小公司IT支持,没预算买专业中间件许可证;二是开发者想在单台开发机上并行调试多个jpress站点(比如对比不同主题、测试插件兼容性);三是教学场景中,导师需要为A同学配独立数据库+独立域名+独立日志,又不想每人配一台云服务器。它解决的不是“高并发”问题,而是“可维护性”和“环境确定性”问题。接下来我会从设计思路、目录结构、配置细节、jpress适配、实操避坑五个维度,带你手把手搭出稳定可用的多实例环境,所有步骤均基于Linux CentOS 7/8与Tomcat 9.0.83实测验证,Windows路径差异我会单独标注。

2. 整体设计思路:为什么选“共享bin + 独立实例目录”而非其他方案?

很多人第一次听说多实例,第一反应是“复制整个Tomcat文件夹”。这确实可行,但很快会陷入维护噩梦:Tomcat安全补丁来了,你要手动更新5个副本;JVM调优参数改了,得逐个打开catalina.sh去改;某个实例的server.xml被误删,恢复时还得翻备份。我们采用的是Tomcat官方文档明确推荐的**“CATALINA_BASE分离模式”**——即所有实例共用同一份$CATALINA_HOME(二进制程序),每个实例拥有独立的$CATALINA_BASE(配置、日志、webapps、work)。这是最轻量、最可控、升级最省心的方案。

2.1 目录结构设计:清晰到能一眼看出谁是谁

我坚持用语义化命名,拒绝tomcat1/tomcat2这种编号。以jpress为例,我的生产环境目录树长这样:

/opt/tomcat/ # CATALINA_HOME,只放bin/、lib/、LICENSE等不变文件 ├── bin/ # 所有实例共用的启动脚本(catalina.sh, startup.sh等) ├── lib/ └── ... /opt/tomcat-instances/ # 所有实例的根目录(自定义,非必须,但强烈建议) ├── jpress-prod/ # 生产实例:端口8080,连接MySQL主库 │ ├── conf/ # server.xml, web.xml, context.xml等 │ ├── logs/ # catalina.out, localhost.log等 │ ├── webapps/ # 只放jpress.war,不放ROOT或其他应用 │ ├── work/ # JSP编译缓存,每次启动自动清空 │ └── temp/ # 临时文件 ├── jpress-test/ # 测试实例:端口8081,连接测试库 │ ├── conf/ │ ├── logs/ │ ├── webapps/ │ ├── work/ │ └── temp/ └── jpress-dev/ # 开发实例:端口8082,H2嵌入式数据库 ├── conf/ ├── logs/ ├── webapps/ ├── work/ └── temp/

提示:/opt/tomcat-instances/这个父目录不是Tomcat默认路径,完全由你定义。它的存在让所有实例配置集中管理,避免散落在/home或/var下难以追踪。Windows用户请将/opt替换为C:\tomcat,路径分隔符用反斜杠。

2.2 为什么不用Docker?为什么不用systemd服务?

有人会问:“现在都2024年了,为啥不用Docker?”——因为jpress的部署场景往往不在云原生环境。某地市级政务信息平台曾让我协助迁移,他们服务器是十年前采购的物理机,内核不支持Docker,运维团队只会service httpd start。强行上容器,等于把简单问题复杂化。而systemd服务虽好,但systemctl start tomcat@prod这种写法,对新手来说,.service文件里Environment="CATALINA_BASE=/opt/tomcat-instances/jpress-prod"这种变量传递,容易配错且报错晦涩。我们选择最原始、最透明的方式:直接调用catalina.sh脚本,显式传入-Dcatalina.base参数。这样每一步都看得见、摸得着,出问题立刻能定位是脚本、参数还是权限。

2.3 实例间的关键隔离点:哪些必须独立?哪些可以共享?

不是所有文件夹都需物理隔离。根据Tomcat生命周期,我划出三条铁律:

  1. 必须独立:conf/(配置)、logs/(日志)、webapps/(应用)、work/(JSP编译)、temp/(临时文件)。其中conf/server.xml里的<Server port>、<Connector port>、<Engine name>必须全局唯一,否则端口冲突或日志混杂。
  2. 可以共享:bin/(启动脚本)、lib/(核心jar)、endorsed/(覆盖JDK类)。bin/catalina.sh本身不保存状态,它只是个“指挥官”,真正干活的是$CATALINA_BASE/conf/下的配置。
  3. 谨慎共享:shared/lib/(共享库)。jpress本身不依赖特殊第三方jar,所以我不建这个目录。若未来要集成统一认证SDK,才考虑在此放auth-sdk.jar,避免每个实例重复拷贝。

这个设计的底层逻辑是:让变化的部分独立,让不变的部分复用。Tomcat程序版本升级,只需替换/opt/tomcat/bin/和/opt/tomcat/lib/;jpress版本升级,只需替换对应webapps/jpress.war;数据库切换,只需改conf/context.xml里的<Resource>标签。职责清晰,修改点明确。

3. 核心配置详解:从server.xml到context.xml的逐行解析

配置是多实例的灵魂,也是最容易出错的地方。我不会罗列所有XML标签,只聚焦jpress部署最关键的四个文件,结合实际场景解释每一行为什么这么写。

3.1 server.xml:端口、服务名与引擎的精准控制

这是每个实例conf/下最核心的文件。以jpress-prod/conf/server.xml为例,关键段落如下:

<Server port="8005" shutdown="SHUTDOWN"> <!-- 8005是shutdown端口,必须每个实例不同 --> <!-- prod用8005,test用8006,dev用8007 --> </Server> <Service name="jpress-prod"> <!-- Service名必须唯一,用于区分不同实例的日志和监控 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" /> <!-- HTTP端口:prod用8080,test用8081,dev用8082 --> <!-- URIEncoding="UTF-8" 必加!否则jpress后台中文菜单乱码 --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!-- AJP端口:prod用8009,test用8010,dev用8011 --> <!-- 若前端用Nginx反向代理,此端口可禁用,注释掉即可 --> <Engine name="jpress-prod" defaultHost="localhost"> <!-- Engine名必须与Service名一致,且全局唯一 --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- appBase="webapps" 是相对路径,指向 $CATALINA_BASE/webapps --> <!-- 不要写成绝对路径!否则跨实例会混乱 --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" /> <!-- 日志路径是相对的,自动落到 $CATALINA_BASE/logs/ 下 --> </Host> </Engine> </Service>

注意:<Server port>、<Connector port>、<Engine name>、<Service name>这四处是“四重锁”,缺一不可。我曾帮某公司排查,他们只改了HTTP端口,忘了改<Server port>,结果两个实例抢8005端口,后启动的那个直接报Address already in use,但错误日志藏在catalina.out里,不仔细看根本找不到。

3.2 context.xml:jpress数据库与文件存储的生命线

jpress所有数据都靠这个文件打通。conf/context.xml不是Tomcat默认创建的,必须手动新建。内容极简,但字字关键:

<?xml version="1.0" encoding="UTF-8"?> <Context> <!-- 配置jpress使用的数据库 --> <Resource name="jdbc/jpress" auth="Container" type="javax.sql.DataSource" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/jpress_prod?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true&amp;useSSL=false" username="jpress_user" password="StrongPass123!" maxActive="20" minIdle="5" initialSize="5" validationQuery="SELECT 1" testOnBorrow="true" removeAbandonedOnBorrow="true" removeAbandonedTimeout="60" logAbandonedOnBorrow="true" /> <!-- 配置jpress附件上传路径 --> <Environment name="jpress.upload.path" value="/data/jpress-prod/uploads" type="java.lang.String" override="false" /> <!-- 此路径必须提前创建,并赋予tomcat用户读写权限 --> <!-- prod用 /data/jpress-prod/uploads,test用 /data/jpress-test/uploads --> </Context>

这里有两个易错点:第一,url中的&必须写成&amp;,XML语法强制要求,否则Tomcat启动直接失败,报cvc-complex-type.2.4.a: Invalid content was found starting with element 'url';第二,jpress.upload.path的值必须是绝对路径,且不能放在$CATALINA_BASE下(否则实例重启时work/目录清空可能误删上传文件)。我习惯统一放在/data/分区,既独立于系统盘,又方便做定时备份。

3.3 catalina.properties:JVM与类加载的隐形开关

这个文件控制Tomcat底层行为。jpress-prod/conf/catalina.properties中,我必改的三处:

# 指定jpress实例的JVM参数,不写在这里,启动时无法生效 JAVA_OPTS="-server -Xms1024m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -Dfile.encoding=UTF-8" # 关键!告诉Tomcat:你的配置在哪?日志写哪?应用放哪? catalina.base=/opt/tomcat-instances/jpress-prod catalina.home=/opt/tomcat java.io.tmpdir=/opt/tomcat-instances/jpress-prod/temp # 类加载优化:避免jpress的logback与Tomcat自带log4j冲突 common.loader="${catalina.home}/lib/","${catalina.home}/lib/*.jar","${catalina.base}/lib/","${catalina.base}/lib/*.jar"

注意:JAVA_OPTS在这里设置,比在bin/setenv.sh里更可靠。因为catalina.sh会优先读取此文件中的JAVA_OPTS,再与脚本里定义的合并。common.loader路径必须包含"${catalina.base}/lib/",否则你把jpress需要的mysql-connector-java-8.0.33.jar放到实例自己的lib/下,Tomcat根本加载不到。

3.4 web.xml(可选):当jpress需要定制化时

标准jpress WAR包自带web.xml,一般无需修改。但若你启用了HTTPS,或需要强制跳转www域名,就得在$CATALINA_BASE/conf/web.xml里加filter:

<filter> <filter-name>HttpsRedirectFilter</filter-name> <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class> <init-param> <param-name>hstsEnabled</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>HttpsRedirectFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

这个filter会自动给所有响应头加上Strict-Transport-Security,提升jpress站点安全性。但它只对当前实例生效,prod加了,test没加,互不影响——这正是多实例的价值:策略按需启用,不搞一刀切。

4. jpress部署实操:从war包解压到首页可访问的完整链路

理论讲完,现在进入真刀真枪环节。以下步骤在CentOS 7.9上全程实测,耗时约12分钟。Windows用户注意路径和命令差异,我会特别标注。

4.1 环境准备:JDK、Tomcat二进制包与jpress WAR包

首先确认JDK版本。jpress 4.0+要求JDK 8u202+或JDK 11+:

# 查看已安装JDK java -version # 输出应为 openjdk version "11.0.22" 或类似 # 若未安装,用yum安装OpenJDK 11(CentOS) sudo yum install -y java-11-openjdk-devel # 设置JAVA_HOME(写入 /etc/profile) echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk' | sudo tee -a /etc/profile echo 'export PATH=$JAVA_HOME/bin:$PATH' | sudo tee -a /etc/profile source /etc/profile

下载Tomcat 9.0.83(官网最新稳定版):

cd /tmp wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.83/bin/apache-tomcat-9.0.83.tar.gz tar -xzf apache-tomcat-9.0.83.tar.gz -C /opt/ sudo mv /opt/apache-tomcat-9.0.83 /opt/tomcat # 设置属主,避免后续权限问题 sudo chown -R root:root /opt/tomcat

下载jpress 4.2.0 WAR包(以GitHub Release为准):

wget https://github.com/JPressProjects/jpress/releases/download/v4.2.0/jpress-4.2.0.war # 重命名为标准名,方便识别 mv jpress-4.2.0.war jpress.war

Windows提示:下载Tomcat用ZIP包,解压到C:\tomcat;JDK安装后,在“系统属性→高级→环境变量”里添加JAVA_HOME和PATH;jpress.war直接下载保存即可。

4.2 创建实例目录并初始化配置

这是最关键的一步,决定后续是否顺利:

# 创建实例根目录 sudo mkdir -p /opt/tomcat-instances/{jpress-prod,jpress-test,jpress-dev} # 复制基础配置(只复制conf/骨架,不复制server.xml等具体内容) sudo cp -r /opt/tomcat/conf/ /opt/tomcat-instances/jpress-prod/ sudo cp -r /opt/tomcat/conf/ /opt/tomcat-instances/jpress-test/ sudo cp -r /opt/tomcat/conf/ /opt/tomcat-instances/jpress-dev/ # 创建webapps、logs、work、temp目录(必须存在,否则启动报错) for dir in webapps logs work temp; do sudo mkdir -p /opt/tomcat-instances/jpress-prod/$dir sudo mkdir -p /opt/tomcat-instances/jpress-test/$dir sudo mkdir -p /opt/tomcat-instances/jpress-dev/$dir done # 赋予tomcat用户(假设为tomcat)完全控制权 # 先创建tomcat用户(若不存在) sudo useradd -r -s /bin/false tomcat # 修改目录属主 sudo chown -R tomcat:tomcat /opt/tomcat-instances/

提示:webapps/目录必须为空或只放jpress.war,不要放ROOT/或其他WAR包。logs/目录必须存在且可写,否则catalina.out无法生成,你将看不到任何启动日志。

4.3 部署jpress WAR包并启动实例

将jpress.war放入对应实例的webapps/目录:

# 放入生产实例 sudo cp jpress.war /opt/tomcat-instances/jpress-prod/webapps/ # 放入测试实例 sudo cp jpress.war /opt/tomcat-instances/jpress-test/webapps/ # 放入开发实例 sudo cp jpress.war /opt/tomcat-instances/jpress-dev/webapps/ # 切换到tomcat用户,启动prod实例(显式指定CATALINA_BASE) sudo -u tomcat /opt/tomcat/bin/catalina.sh start -Dcatalina.base=/opt/tomcat-instances/jpress-prod # 启动test实例 sudo -u tomcat /opt/tomcat/bin/catalina.sh start -Dcatalina.base=/opt/tomcat-instances/jpress-test # 启动dev实例 sudo -u tomcat /opt/tomcat/bin/catalina.sh start -Dcatalina.base=/opt/tomcat-instances/jpress-dev

Windows操作:以管理员身份打开CMD,执行:

set CATALINA_BASE=C:\tomcat-instances\jpress-prod set CATALINA_HOME=C:\tomcat cd /d C:\tomcat\bin catalina.bat start

4.4 验证与首次访问:检查端口、日志与jpress安装向导

启动后,立刻检查:

# 查看进程是否起来 ps aux | grep tomcat | grep jpress-prod # 应看到类似:tomcat 12345 ... /opt/tomcat/bin/bootstrap.jar ... # 检查端口监听 sudo netstat -tuln | grep ':8080\|:8081\|:8082' # 应显示 0.0.0.0:8080, 0.0.0.0:8081, 0.0.0.0:8082 均在LISTEN状态 # 查看prod实例日志(实时跟踪) sudo tail -f /opt/tomcat-instances/jpress-prod/logs/catalina.out # 启动成功标志:最后几行出现 "Server startup in [xxx] milliseconds"

打开浏览器,依次访问:

  • http://your-server-ip:8080/→ 应看到jpress安装向导页面(第一步:数据库配置)
  • http://your-server-ip:8081/→ 同样是安装向导,但数据库URL指向test库
  • http://your-server-ip:8082/→ 指向dev库,可选H2嵌入式数据库

注意:首次访问时,jpress会自动解压jpress.war到webapps/jpress/目录,并生成WEB-INF/classes/config.properties。此时webapps/下会有jpress/文件夹和jpress.war两个东西,这是正常现象。后续更新jpress,只需替换jpress.war,Tomcat会自动重新解压覆盖。

4.5 数据库初始化:为三个实例分别创建独立库

jpress安装向导要求填写数据库信息。我们必须为每个实例创建独立数据库,避免数据污染:

-- 登录MySQL mysql -u root -p -- 创建prod库(utf8mb4字符集,兼容emoji) CREATE DATABASE jpress_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建test库 CREATE DATABASE jpress_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建dev库(H2用户可跳过) CREATE DATABASE jpress_dev CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建专用用户(最小权限原则) CREATE USER 'jpress_prod'@'localhost' IDENTIFIED BY 'StrongPass123!'; CREATE USER 'jpress_test'@'localhost' IDENTIFIED BY 'StrongPass456!'; CREATE USER 'jpress_dev'@'localhost' IDENTIFIED BY 'StrongPass789!'; -- 授权(只给对应库) GRANT ALL PRIVILEGES ON jpress_prod.* TO 'jpress_prod'@'localhost'; GRANT ALL PRIVILEGES ON jpress_test.* TO 'jpress_test'@'localhost'; GRANT ALL PRIVILEGES ON jpress_dev.* TO 'jpress_dev'@'localhost'; FLUSH PRIVILEGES;

在jpress安装向导中,prod实例填jpress_prod库名和jpress_prod用户;test填jpress_test;dev填jpress_dev。这样,三个站点的数据彻底隔离,删库跑路也只影响一个实例。

5. 常见问题与排查技巧:那些让你抓狂又不得不面对的坑

实操中,90%的问题都集中在配置路径、权限、端口这三座大山。我把踩过的、同事问爆的、论坛高频问题整理成速查表,并附上独家排查心法。

5.1 启动失败:Address already in use或Permission denied

这是新手第一道坎。错误日志通常在catalina.out里,但很多人没看就重装。

现象根本原因排查命令解决方案
SEVERE: Failed to initialize end point associated with ProtocolHandler ["http-nio-8080"] java.net.BindException: Address already in use端口被占(其他Tomcat、Nginx、甚至IDEA内置服务器)sudo lsof -i :8080或sudo netstat -tulnp | grep :8080杀掉进程sudo kill -9 <PID>,或改server.xml中端口
java.io.FileNotFoundException: /opt/tomcat-instances/jpress-prod/logs/catalina.out (Permission denied)tomcat用户对logs/目录无写权限ls -ld /opt/tomcat-instances/jpress-prod/logs/sudo chown tomcat:tomcat /opt/tomcat-instances/jpress-prod/logs/
Cannot find /opt/tomcat/bin/setenv.shTomcat找不到setenv.sh,但catalina.properties里JAVA_OPTS没生效cat /opt/tomcat/conf/catalina.properties | grep JAVA_OPTS确保catalina.properties中JAVA_OPTS行未被注释,且语法正确

实操心得:永远先看catalina.out!不要凭感觉猜。用sudo -u tomcat /opt/tomcat/bin/catalina.sh run -Dcatalina.base=...前台启动,错误直接打在终端,比后台启动快十倍定位。

5.2 jpress访问异常:白页、404、数据库连不上

jpress界面出问题,90%是配置没对上。

现象根本原因关键检查点解决方案
访问http://ip:8080/显示404,但http://ip:8080/jpress/能进jpress.war包名不是jpress.war,或server.xml里<Host appBase>指向错误ls /opt/tomcat-instances/jpress-prod/webapps/是否有jpress.war?appBase是否为webapps?重命名为jpress.war;确认appBase="webapps"(不是"."或绝对路径)
安装向导填完数据库点“下一步”,卡住或报Connection refusedcontext.xml里url写错,或MySQL没开远程访问mysql -h 127.0.0.1 -u jpress_prod -p jpress_prod能否连?telnet 127.0.0.1 3306是否通?检查url中IP、端口、库名;确认MySQLbind-address = 127.0.0.1(非localhost);检查防火墙sudo firewall-cmd --list-ports
jpress后台上传图片失败,提示No such file or directorycontext.xml里jpress.upload.path路径不存在,或tomcat用户无权限ls -ld /data/jpress-prod/uploadssudo mkdir -p /data/jpress-prod/uploads && sudo chown -R tomcat:tomcat /data/jpress-prod/

注意:jpress的config.properties生成后,会缓存数据库连接。如果中途改了context.xml,必须删掉webapps/jpress/WEB-INF/classes/config.properties,再重启Tomcat,否则新配置不生效。

5.3 日志混乱:多个实例日志写到同一个catalina.out

这是CATALINA_BASE没设对的典型症状。catalina.out本该在每个实例自己的logs/下,但如果启动时没传-Dcatalina.base,Tomcat会默认用$CATALINA_HOME,导致所有实例往/opt/tomcat/logs/catalina.out里狂写。

终极验证法:启动后,立刻执行:

ps aux | grep catalina | grep -v grep # 正确输出应包含:-Dcatalina.base=/opt/tomcat-instances/jpress-prod # 如果没有,说明启动命令漏了-D参数!

解决方案:写个启动脚本start-prod.sh,固化参数:

#!/bin/bash export CATALINA_HOME=/opt/tomcat export CATALINA_BASE=/opt/tomcat-instances/jpress-prod /opt/tomcat/bin/startup.sh

然后chmod +x start-prod.sh && sudo -u tomcat ./start-prod.sh。一劳永逸。

5.4 性能瓶颈:内存溢出(OutOfMemoryError)

jpress本身不重,但多实例共用物理内存,容易OOM。catalina.properties里JAVA_OPTS是救命稻草:

# 生产实例(2G内存起步) JAVA_OPTS="-server -Xms1536m -Xmx1536m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" # 测试实例(1G够用) JAVA_OPTS="-server -Xms1024m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC" # 开发实例(512M足矣) JAVA_OPTS="-server -Xms512m -Xmx512m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=128m"

提示:-Xms和-Xmx设为相同值,避免JVM动态扩容缩容带来的GC抖动。-XX:+UseG1GC是JDK8u20之后的推荐垃圾收集器,比-XX:+UseParallelGC更平稳。

6. 运维与扩展:让多实例真正融入日常工作流

搭好只是开始,如何让它长期稳定、便于管理、还能平滑演进?这才是资深博主的硬功夫。

6.1 一键启停脚本:告别手敲10遍catalina.sh

写三个shell脚本,放在/opt/tomcat-instances/下:

# /opt/tomcat-instances/start-all.sh #!/bin/bash echo "Starting jpress-prod..." sudo -u tomcat /opt/tomcat/bin/catalina.sh start -Dcatalina.base=/opt/tomcat-instances/jpress-prod echo "Starting jpress-test..." sudo -u tomcat /opt/tomcat/bin/catalina.sh start -Dcatalina.base=/opt/tomcat-instances/jpress-test echo "Starting jpress-dev..." sudo -u tomcat /opt/tomcat/bin/catalina.sh start -Dcatalina.base=/opt/tomcat-instances/jpress-dev # /opt/tomcat-instances/stop-all.sh #!/bin/bash echo "Stopping jpress-prod..." sudo -u tomcat /opt/tomcat/bin/catalina.sh stop -Dcatalina.base=/opt/tomcat-instances/jpress-prod echo "Stopping jpress-test..." sudo -u tomcat /opt/tomcat/bin/catalina.sh stop -Dcatalina.base=/opt/tomcat-instances/jpress-test echo "Stopping jpress-dev..." sudo -u tomcat /opt/tomcat/bin/catalina.sh stop -Dcatalina.base=/opt/tomcat-instances/jpress-dev

赋予权限:sudo chmod +x /opt/tomcat-instances/start-all.sh /opt/tomcat-instances/stop-all.sh。以后运维只需sudo /opt/tomcat-instances/start-all.sh,5秒搞定。

6.2 日志轮转:防止catalina.out撑爆磁盘

Tomcat自带logging.properties,但默认不轮转。编辑/opt/tomcat-instances/jpress-prod/conf/logging.properties:

# 将ConsoleHandler改为FileHandler,并启用轮转 handlers = 1catalina.org.apache.juli.AsyncFileHandler, 2localhost.org.apache.juli.AsyncFileHandler, 3manager.org.apache.juli.AsyncFileHandler, 4host-manager.org.apache.juli.AsyncFileHandler # 配置catalina日志轮转(每天一个文件,保留30天) 1catalina.org.apache.juli.AsyncFileHandler.level = FINE 1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs 1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina. 1catalina.org.apache.juli.AsyncFileHandler.maxDays = 30 1catalina.org.apache.juli.AsyncFileHandler.bufferSize = 16384

重启实例后,logs/下会出现catalina.2024-05-20.log、catalina.2024-05-19.log……自动清理旧日志。

6.3 平滑升级:Tomcat版本更新不中断jpress服务

当Tomcat发布新版本(如9.0.84),如何无缝升级?三步走:

  1. 停旧启新:先停jpress-prod,再解压新Tomcat到/opt/tomcat-new,然后用新bin/catalina.sh启动,指向旧CATALINA_BASE:
    sudo -u tomcat /opt/tomcat-new/bin/catalina.sh start -Dcatalina.base=/opt/tomcat-instances/jpress-prod
  2. 验证功能:访问http://ip:8080/,确认jpress一切正常。
  3. 切换软链接:sudo rm /opt/tomcat && sudo ln -s /opt/tomcat-new /opt/tomcat。

整个过程,jpress服务中断时间小于30秒。这就是CATALINA_HOME与CATALINA_BASE分离设计的最大红利。

6.4 安全加固:最小权限原则的落地实践

生产环境绝不能用root跑Tomcat。我的加固清单:

  • 用户隔离:为

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询