Linux下Tomcat部署与调优实战:从JDK到systemd全解析

发布时间:2026/10/23 3:33:22
Linux下Tomcat部署与调优实战:从JDK到systemd全解析 把 Tomcat 部署在 Linux 上这件事说起来不算复杂但真正操作过的人都知道这里面藏着不少细节。最近我给公司内部一套模拟项目X配服务端环境又从头把 Tomcat 捋了一遍从下载到调优踩了几个坑也总结了一些规律。这篇文章就是基于这次实际部署过程整理出来的目标很明确帮你在 Linux 系统上快速、稳定地把 Tomcat 跑起来并且能应对后续运维中常见的问题。在 Java Web 服务端这个圈子里Tomcat 依然是使用最广泛的 Servlet 容器之一特别是传统单体应用和中小型内网系统用 Tomcat 部署是最直接、最省事的选择。很多新手容易上来就执行startup.sh看着进程起来了就觉得完事大吉结果内存爆了、端口冲突了、权限乱了问题层出不穷。我想和大家聊的是尽量避开这些“隐藏副本”的方式。1. 整体设计与思路拆解为什么这样装以及装之前要想清楚的事很多人在安装 Tomcat 之前根本没有想过“部署”这个动作包含哪些环节。这里我所谓的“部署”不只是把压缩包解压到/opt/tomcat下然后启动而是包括 JDK 环境选择、系统用户规划、目录权限控制、JVM 参数调优、启动守护方式等一系列动作。先说环境选择。Tomcat 本身是 Java 写的运行前必须有 JDK。这里要注意版本匹配关系Tomcat 9.x 对应 JDK 8 或 JDK 11Tomcat 10.x 开始默认走 Jakarta EE对应 JDK 11 及以上。我这次用的是 Tomcat 9.0.x JDK 11原因很简单项目X的技术栈要求 Java 11 的语法特性同时很多老库对 JDK 8 的支持更成熟但新老之间容易出兼容性矛盾。如果你拿不准直接遵循“选新不选旧但别追最新”的原则。然后是安装方式。Linux 上装 Tomcat 有三种常见路径yum/apt 装系统自带的安装包、直接用官方二进制 tar.gz 包解压、走 Docker 容器。我坦诚地说生产环境我推荐第二种“手动解压”方式。原因很实际系统包管理器yum、apt里的 Tomcat 版本通常滞后而且会强行依赖系统 Java升级路径不可控Docker 方式虽然隔离性好但你没搞清楚底层网络和卷挂载逻辑就上手排查故障时很容易把自己绕晕手动解压对目录结构完全可控修改配置、升级版本哪一步出了问题都能看到具体文件。本次部署我也采用了官方二进制包方式。下载时尽量从官网或者可靠的镜像站获取 tar.gz 包不要拿不明链接到处乱下安全上靠不住。在整个设计思路上还有一点容易被忽略Tomcat 跑的系统账号。很多人图省事直接 root 启动 Tomcat。如果你只在一个无关紧要的测试环境里折腾倒无所谓但在共享服务器或生产环境上用 root 跑 Tomcat 非常危险一旦 Web 应用有漏洞被利用攻击者拿到的直接就是系统最高权限。所以我在后面专门安排了“单独建一个系统用户给 Tomcat 跑”这个步骤这是隔离权限下移的标准做法。我们再把整体部署流程在脑子里过一遍下载 JDK 与 Tomcat、创建系统用户、解压配置、设置环境变量、用 systemd 管理服务生命周期、验证启动、最后把日志和内存策略调好。这整套链路下来不仅能保证 Tomcat 装得上更能保证它活得久、跑得稳。2. 核心细节解析与实操要点目录结构、环境变量和 JVM 参数之间的关系要玩转 Tomcat不能光会敲命令最好先看透它的“骨架”。Tomcat 解压后的根目录我们通常叫CATALINA_HOME。里面有bin、conf、lib、logs、temp、webapps、work这七个关键目录每一个都负责不同职责bin存放启动、关闭脚本比如startup.sh、shutdown.sh还有不同平台的/catalina处理脚本conf核心配置文件所在地这里的大头是server.xml、web.xml、context.xml和tomcat-users.xmllibTomcat 自身依赖的 Java 类库我们一般不动logs日志输出目录catalina.out是全量日志还有其他按天滚动的日志文件webapps存放 Web 应用目录或 war 包应用默认在这里被自动部署workJSP 编译后的临时 class 文件跑久了你可能会发现这里占用越来越大可定期清理。环境变量的认知也要突破“填一行 JAVA_HOME 就好”的直觉。Tomcat 启动时依赖两个核心变量JAVA_HOME指向 JDK 安装目录CATALINA_HOME指向 Tomcat 根目录。前者空缺的话Tomcat 连 JVM 都找不到会直接报 “Cannot find JAVA_HOME” 之类的错误。后者没设对脚本会找不到catalina.jar和配置文件。在/etc/profile.d/tomcat.sh之类的地方写入变量可以避免每次切换用户都要重新 export。有一个点我特别想说JVM 参数其实不该一股脑塞进JAVA_OPTS里。Tomcat 提供了两个变量JAVA_OPTS和CATALINA_OPTS。区别在于JAVA_OPTS在任意执行模式包括start、stop、version下都会被加载而CATALINA_OPTS只在启动 Tomcat 的主进程时生效。如果你要设置堆内存、GC 参数、远程调试端口建议放进CATALINA_OPTS避免在管理命令时也加载不必要的参数免得shutdown.sh因为内存参数过大而卡住。我这次部署的应用是个典型的数据处理服务Xmx 开到了 2G。这里想提醒一下并不是所有机器都能无脑开大堆。开发机只有 4G 内存时你给 Tomcat 分 3G操作系统自身和其他进程就容易申请不到内存进而触发 OOM Killer后果比 JVM 自己 OutOfMemoryError 更麻烦。我的经验公式是JVM 堆最大值不超过物理内存的 50%并且预留出足够空间给操作系统缓存和中间件。# 常规 JVM 参数 CATALINA_OPTS-server -Xms512M -Xmx2048M -XX:MetaspaceSize256M -XX:MaxMetaspaceSize512M上面这段是最基础也最稳妥的堆与元空间设置。-Xms和-Xmx分别是最小堆和最大堆设成一样有避免动态扩容带来的性能损耗但容易造成内存浪费如果你不是特别追求低延迟可以像我这里这样让 JVM 动态伸缩。元空间设置很重要很多人只关注堆却忽略了大量使用反射、动态代理的 Web 应用会吞噬元空间内存不设置上限的话有时候直接触发 操作系统级 的异常。另外 GC 参数如果是 JDK 11 默认 G1生产上一般不必改保持默认反而比乱调更稳定我在项目X里就没动它。再展开讲讲server.xml里的核心端口配置。默认配置有三个端口值得注意端口作用风险说明8005管理 Tomcat 的 SHUTDOWN 端口暴露到外部很危险默认是只能本机访问8080HTTP 访问入口业务端口对外防火墙需放行8443HTTPS 加密访问端口需要配置证书默认未启用我见过不少人把 8080 端口改掉却忘了同步 8005 端口在防火墙上的访问规则导致服务器上明明开着 Tomcat外部却访问不到。改端口时protocol属性和address也要留意address0.0.0.0表示监听所有网卡如果只服务本机可以改成127.0.0.1能减少暴露面。3. 实操过程与核心环节实现从下载到 systemd 守护一步步跟着做话说回来光讲理论没太多价值关键是动手。接下来我按自己的部署过程把每一步命令和注意事项写清楚。3.1 创建专用系统用户隔离运行权限我先新建了一个名为tomcat的系统用户指定其主目录为/opt/tomcat并且禁止其交互式登录因为 Tomcat 不需要一个 shell 来执行命令。执行下面命令时我习惯用/sbin/nologin而不是/bin/false两个都能禁止登录但前者的限制信息更明确。sudo groupadd tomcat sudo useradd -s /sbin/nologin -g tomcat -d /opt/tomcat tomcat这一步创建用户和组但还没有真正赋予/opt/tomcat目录权限等解压完再统一授权。需要特别叮嘱一句不要用 root 去启动 Tomcat也不要用 root 去跑应用内涉及文件读写的功能应用越权写出数据是越权问题的根源。3.2 下载并解压 JDK 与 TomcatJDK 安装方式有很多种解压方式是其中最直接的一种。我使用的是官方构建的 JDK 11 tar.gz 包放在/usr/local/java目录下解压然后通过软链接将路径固定这样以后升级 JDK 只需要改软链接指向sudo mkdir -p /usr/local/java sudo tar -zxvf jdk-11.0.21_linux-x64_bin.tar.gz -C /usr/local/java sudo ln -s /usr/local/java/jdk-11.0.21 /usr/local/java/latest接着下载 Tomcat。我这里用的是某个稳定版本的二进制包注意官方下载页的 tar.gz 是最干净的格式zip 包主要为 Windows 设计。sudo wget -P /tmp https://downloads.apache.org/tomcat/tomcat-9/v9.0.93/bin/apache-tomcat-9.0.93.tar.gz sudo mkdir -p /opt/tomcat sudo tar -zxvf /tmp/apache-tomcat-9.0.93.tar.gz -C /opt/tomcat --strip-components1这里要说明一个容易踩的坑从 Tomcat 官网下载页面直接右键复制链接时如果走了某些重定向和 CDN 链接wget可能会拿到一个 HTML 页面而不是真正的 tar.gz。所以下载完一定要用tar -tzf或者du -sh检查文件类型和大小我这次就遇到过文件只有几 KB 的情况白忙活几分钟。解压时使用--strip-components1是为了把apache-tomcat-9.0.93这一层目录剥掉使文件直接落在/opt/tomcat下为后续路径统一访问提供便利。3.3 配置系统环境变量JDK 和 Tomcat 的路径要写进全局环境变量否则重启后可能找不到命令。我在/etc/profile.d/tomcat.sh里写入了下面的内容export JAVA_HOME/usr/local/java/latest export CATALINA_HOME/opt/tomcat export PATH$PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin写完记得执行source /etc/profile.d/tomcat.sh让当前会话立即生效。有些教程会把这么一段塞进/etc/profile那里是登录 shell 才加载的配置放到/etc/profile.d下更加规范系统维护时也方便单独禁用或修改。然后授权给tomcat用户。这个步骤别马虎sudo chown -R tomcat:tomcat /opt/tomcat sudo chmod x /opt/tomcat/bin/*.sh如果不赋予可执行权限用startup.sh启动时会报 “Permission denied”。webapps目录如果存在旧页面而你想清理可以清空但目录本身要保留Tomcat 启动时若发现该目录缺失会自动重建但症状间会有警告信息提前排查浪费时间。3.4 用 systemd 接管 Tomcat 生命周期很多人的第一反应是直接跑/opt/tomcat/bin/startup.sh。说实话开发测试环境这么干没事但在需要长期稳定运行的环境里我更推荐用 systemd 来管理。好处很明显开机自启动、进程守护崩溃自动拉起、日志统一由 journald 接管管理命令也统一用 systemctl 风格不需要再记startup.sh/shutdown.sh那套。我在/etc/systemd/system/tomcat.service里写了如下配置[Unit] DescriptionApache Tomcat Web Application Container Afternetwork.target [Service] Typeforking Usertomcat Grouptomcat EnvironmentJAVA_HOME/usr/local/java/latest EnvironmentCATALINA_HOME/opt/tomcat EnvironmentCATALINA_BASE/opt/tomcat EnvironmentCATALINA_OPTS-Xms512M -Xmx2048M -XX:MetaspaceSize256M -XX:MaxMetaspaceSize512M ExecStart/opt/tomcat/bin/startup.sh ExecStop/opt/tomcat/bin/shutdown.sh ExecReload/opt/tomcat/bin/shutdown.sh Restarton-failure [Install] WantedBymulti-user.target这里Typeforking很关键因为startup.sh脚本本身会通过daemon方式把 Tomcat 主进程放到后台然后退出如果不声明 forkingsystemd 会误判服务启动失败。文件写好后执行sudo systemctl daemon-reload sudo systemctl enable tomcat sudo systemctl start tomcat sudo systemctl status tomcat --no-pager看到输出里出现active (running)并且 PID 正常才算真正启动成功。后续重启、停止都只用systemctl restart tomcat和systemctl stop tomcat一对命令就够了。3.5 验证访问与防火墙放行Tomcat 默认监听 8080 端口我在服务器上先本机验证一下curl -I http://127.0.0.1:8080正常情况下会返回HTTP/1.1 200的响应头。如果返回连接拒绝多半是进程没起来或者端口被防火墙挡了。本机通了之后再考虑外部访问的问题。如果用的是firewalld放行端口方式sudo firewall-cmd --permanent --add-port8080/tcp sudo firewall-cmd --reloadiptables裸用则是iptables -A INPUT -p tcp --dport 8080 -j ACCEPT。注意放行之前先想清楚这个 Tomcat 是纯内网服务还是对外开放不要一张口就把端口全放开。我就是因为一开始没评估好策略把 8080 直接暴露在公网 IP 上结果第二天就被扫描日志灌满后来老老实实加白名单。3.6 查看日志确认启动过程启动完成不意味着完全没问题。我最常用的命令是tail -f /opt/tomcat/logs/catalina.out启动日志里会依次显示 JVM 参数、Deploying web application、Server startup in [xxxx] milliseconds 等信息。Server startup出现才是真正的完成标志。如果你发现进程还在页面却打不开那就要回头看看日志别凭感觉重启。4. 常见问题与排查技巧实录端口占用、权限错误、内存溢出的现场还原部署过程中遇到问题太正常了我这次也踩了好几个老坑这里整理成速查表顺便把排查思路说透。4.1 端口被占用Tomcat 起不来现象是最典型的执行启动后catalina.out里出现java.net.BindException: Address already in use或者页面一直超时。排查时要分两步走先看端口被哪个进程占了netstat -plnt | grep 8080再看 CPU 占用率高的 java 进程ps -ef | grep java如果确实是被旧 Tomcat 实例占着往往是因为之前shutdown.sh没有干净退出这时两种办法用kill -9强制结束残留 PID或者干脆systemctl restart tomcat让 systemd 拉起一个新的干净进程。但要记住强制 kill 有风险Web 应用正在写的数据文件有损坏可能能优雅关闭就尽量优雅关闭。4.2 Tomcat 的 manager 页面提示 403 Access Denied安装完 Tomcat 后访问http://localhost:8080/manager/html大概率会得到“403 Access Denied”这是默认情况别慌不是故障是安全机制。默认只有本机回环地址能访问 manager而且还得在conf/tomcat-users.xml里配置用户角色。sudo vim /opt/tomcat/conf/tomcat-users.xml在tomcat-users节点下添加角色和用户role rolenamemanager-gui/ user usernameadmin passwordadmin123 rolesmanager-gui/改完需要重启 Tomcat 才能生效。这里有几个注意点密码不要用admin123这类弱口令尤其是在内外网可达的机器上分配角色时最小化授权只需要manager-gui就绝不把manager-script和manager-jmx一起给后者权限太大能被远程脚本滥用。4.3 内存溢出或系统资源不足应用跑几天后突然变卡日志里出现java.lang.OutOfMemoryError: Java heap space这一般说明-Xmx设置得不够或者应用本身有内存泄漏。排查逻辑是这样的先看存活进程和内存以下top -c -p $(pidof java)观察进程的 RES 和 CPU。再结合jstat看 JVM 内部jstat -gcutil $(pidof java) 1000 10如果老年代持续 100% 不下降并且堆空间已经到-Xmx基本可以确认堆设置不合理或应用代码有问题。临时最直接办法是调大CATALINA_OPTS里的-Xmx但更核心的是找到谁在吃内存。我之前在项目X里遇到过一个大坑应用使用 JDBC 连接池连接数设置过大而且没有回收导致内存被连接对象占满。后来把连接池上限调小并开启泄漏检测内存问题就解决了。4.4 JDK 版本不匹配导致启动失败Tomcat 启动时如果提示UnsupportedClassVersionError几乎可以断定是 JDK 版本的问题。比如 JDK 8 下编译的 class 遇到 JDK 11 有时没问题但反过来低版本 JDK 运行高版本编译的类就直接报错。这种情况下执行java -version确认全局 JDK 版本再确认JAVA_HOME是否真的指向这个版本。我自己曾经忽略过 shell 脚本里Environment配置项导致 systemd 里的JAVA_HOME被固定成了一个旧路径而终端里怎么echo $JAVA_HOME都是新路径排查了半小时才发现是服务启动环境跟交互 shell 环境并不共享。4.5 webapps 下 war 包反复重部署页面还是旧版本这个坑往往会骗到新手。Tomcat 默认监控 webapps 目录里的 war 包有新 war 包会自动解压部署。但如果旧目录还在而新 war 包版本号相同Tomcat 可能不会自动清掉旧配置和版本化的类导致你感觉自己在更新实际访问的还是旧应用。我现在的处理方式先停服务删除webapps下的应用目录和 war 包再把新 war 包拷进来然后启动。这种方式最保险能避免不少自动化带来的隐含状态。如果你不想停服可以另建appBase指向新目录但那是高级玩法了初学阶段老老实实停机更新更靠谱。5. 从能用到好用日志滚动、时区和监控这些事装完顺手就做Tomcat 跑起来只是第一步想让它长期稳定还得做几个“锦上添花”的动作这些动作很多教程不会主动提醒你但对后续运维体验影响巨大。5.1 日志滚动避免磁盘爆掉Tomcat 的logs目录如果不管理时间长了会堆出大量 GB 级日志把磁盘占满后应用会突然变得非常奇怪比如写文件失败、进程死锁。官方自带logrotate配置在 CentOS 的/etc/logrotate.d/tomcat里通常长这样/opt/tomcat/logs/*.out { daily rotate 30 copytruncate compress missingok }copytruncate是重点它先拷贝当前日志再截断原文件避免因为 Tomcat 还持有日志句柄而无法正常轮转。如果你懒得到处找配置文件也可以用 cron 做个脚本每周末把catalina.out按日期归档至少保证单文件不超过 1G。5.2 修改时区不然日志时间跟你“对不上号”Tomcat 默认取系统时区服务器时区若是 UTC日志里就是 UTC 时间看异常发生时间就得换算一次很痛苦。在catalina.sh里添加一行设置时区并不难CATALINA_OPTS$CATALINA_OPTS -Duser.timezoneAsia/Shanghai或者在 systemd service 的 Environment 里直接加TZAsia/Shanghai效果一样。这个操作虽然简单但真的能减少不少沟通成本我在排查项目X线上问题时发现应用日志和数据库日志相差 8 小时一度以为是慢查询问题最后定位到是时区导致的时间偏差。5.3 应用监控可以很轻量新装一个 Tomcat 就上全功能监控平台多少有点小题大做。我习惯先看两个基础指标进程存活和端口响应。# 每分钟检查处理器 curl -s http://127.0.0.1:8080/HealthCheck /dev/null || systemctl restart tomcat配合 systemd 的Restarton-failure再叠加一个简单的健康检查脚本就能覆盖大部分假死场景。如果追求更精细的数据再考虑接入 JMX 或定期采集 GC 日志一般到这一步Tomcat 部署和初始运维就已经相当扎实了。6. 最后的调侃与提醒这些操作细节都是我用时间换来的学 Tomcat 部署不难网上教程一抓一大把但真正动手时你才会发现细节都在你意想不到的地方。比如 Tomcat 的startup.sh是用sh解释执行的如果你的 Linux 环境里sh被替换成了不兼容bash的 shell启动时就会莫名报错再比如你放行防火墙后还是访问不了服务那要确认 SELinux 是否开着可以用getenforce查一下如果是Enforcing状态Tomcat 监听端口可能被 SELinux 拦在策略之外最简单先setenforce 0做个对比实验别一上来就改内核参数。个人体会最深的一点是部署过程一定要用 systemd 托管起来哪怕现在只是个人测试机也别嫌多写一个 service 文件费事。裸用startup.sh意味着你每次重启系统后都得手动敲命令而且进程一旦挂掉没有任何拉起策略这对生产环境是不可接受的。现阶段做 IT 运维规范化、自动化是最基本的素养用 systemd 管起来之后很多扩展和排查都会顺手很多。最后再分享一个小技巧Tomcat 部署完别着急把webapps/ROOT目录删掉去测试可以先放一个简单静态页面或者小 war 包验证链路再切正式应用这样能快速排除是 Tomcat 环境问题还是应用代码本身问题。服务器上的事很多时候像炒菜火候太猛会糊火候不够不熟你要做的就是按经验耐心调一遍不行多试几遍时间长了自然形成肌肉记忆。希望这篇复盘能帮你少走几步弯路让 Tomcat 在你手里真正跑得稳妥。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询