深入分析:为什么 catalina.sh stop 10
无效?揭示 Tomcat 脚本中的问题
前言
在接触 Tomcat 过程中,发现 catalina.sh --help 中明明写着可以延迟关闭,但我加了10秒也没有生效,如果只是用catalina.sh stop 官方说明也会延迟五秒关闭,但事实就是无论这两种哪个,都不会延迟关闭,要算的话大概只有1秒。
系统版本
# 操作系统:CentOS 7
# Tomcat :9.0.96
# JDK :8
# Tomcat 版本
[root@centos7 tomcat]#catalina.sh version
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/default/jre
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Using CATALINA_PID: /usr/local/tomcat/temp/tomcat.pid
Server version: Apache Tomcat/9.0.96
Server built: Oct 3 2024 19:44:30 UTC
Server number: 9.0.96.0
OS Name: Linux
OS Version: 3.10.0-1160.102.1.el7.x86_64
Architecture: amd64
JVM Version: 1.8.0_431-b10
JVM Vendor: Oracle Corporation
[root@centos7 tomcat]#
# jdk 版本
[root@centos7 tomcat]#java -version
java version "1.8.0_431"
Java(TM) SE Runtime Environment (build 1.8.0_431-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.431-b10, mixed mode)
[root@centos7 tomcat]#
二进制安装 Tomcat
# 官网和镜像网站下载:
[root@centos7 ~]#wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.96/bin/apache-tomcat-9.0.96.tar.gz
[root@centos7 ~]#tar xf apache-tomcat-9.0.96.tar.gz -C /usr/local/
[root@centos7 ~]#cd /usr/local/
[root@centos7 local]#ln -s apache-tomcat-9.0.96/ tomcat
[root@centos7 local]#ls tomcat -dl
lrwxrwxrwx 1 root root 21 Oct 18 13:49 tomcat -> apache-tomcat-9.0.96/
[root@centos7 local]#
# 指定 PATH 变量
[root@centos7 local]#echo 'PATH=$PATH:/usr/local/tomcat/bin' > /etc/profile.d/tomcat.sh
[root@centos7 local]#source /etc/profile.d/tomcat.sh
[root@centos7 local]#echo $PATH
/usr/java/default/bin:/apps/httpd/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/tomcat/bin
# 查看当前变量设置和命令用法
[root@centos7 local]#catalina.sh
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/default
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Usage: catalina.sh ( commands ... )
commands:
debug Start Catalina in a debugger #运行 Tomcat 并附加调试器(用于开发时调试 Tomcat)。
debug -security Debug Catalina with a security manager #在启用了安全管理器的情况下以调试模式启动 Tomcat。
jpda start Start Catalina under JPDA debugger #使用 Java Platform Debugger Architecture (JPDA) 调试器启动 Tomcat(常用于远程调试)。
run Start Catalina in the current window #直接在当前终端窗口中启动 Tomcat(没有后台运行,会一直占用该窗口)。
run -security Start in the current window with security manager #在当前终端窗口中并启用安全管理器的情况下启动 Tomcat。
start Start Catalina in a separate window #启动 Tomcat 并让其在后台运行(常用的启动方式,不会占用当前终端)。
start -security Start in a separate window with security manager #在后台启动 Tomcat,并启用安全管理器。
stop Stop Catalina, waiting up to 5 seconds for the process to end #停止 Tomcat,默认等待 5 秒钟让进程正常退出。
stop n Stop Catalina, waiting up to n seconds for the process to end #停止 Tomcat,等待 n 秒钟以允许进程正常退出。
stop -force Stop Catalina, wait up to 5 seconds and then use kill -KILL if still running #停止 Tomcat,等待最多 5 秒后,如果进程仍未退出,则强制使用 kill -KILL 杀掉进程。
stop n -force Stop Catalina, wait up to n seconds and then use kill -KILL if still running #停止 Tomcat,等待 n 秒钟后,如果进程仍未退出,则使用 kill -KILL 强制杀掉进程。
configtest Run a basic syntax check on server.xml - check exit code for result #运行基本的 server.xml 配置文件语法检查(可以用于检查配置是否正确)。
version What version of tomcat are you running? #显示当前 Tomcat 的版本信息。
Note: Waiting for the process to end and use of the -force option require that $CATALINA_PID is defined #使用 `stop` 命令时,如果需要强制停止,必须确保已经定义了 `CATALINA_PID` 变量,它表示 Tomcat 运行时存储其进程 ID 的文件路径。
配置 CATALINA_PID 变量
CATALINA_PID
是一个环境变量,用于指定 Tomcat 运行时保存其进程 ID(PID)的文件路径。这个 PID 文件的作用是记录 Tomcat 进程的 PID,方便在启动、停止或重启时进行进程管理。可选项:默认情况下,Tomcat 不需要
CATALINA_PID
变量即可正常启动和停止。推荐定义:如果您希望更方便地管理 Tomcat 进程,特别是在编写启动和停止脚本时,建议定义
CATALINA_PID
。如果是使用 service 文件来管理,那这个就不需要定义。如果要使用 catalina.sh stop 必须先配置 CATALINA_PID,因为脚本中是通过
CATALINA_PID
来记录 Tomcat 的运行的pid,然后通过读取这个文件拿到进程编号,来kii掉。
# 配置 CATALINA_PID 变量,可以在环境变量配置文件或启动脚本中定义 CATALINA_PID
[root@centos7 temp]#vim /usr/local/tomcat/bin/catalina.sh
export CATALINA_PID=/usr/local/tomcat/temp/tomcat.pid
# 或者在环境变量配置文件中定义
[root@centos7 temp]#vim /etc/profile.d/tomcat.sh
export CATALINA_PID=/usr/local/tomcat/temp/tomcat.pid
# 启动 Tomcat 多了一行信息:Using CATALINA_PID: /usr/local/tomcat/temp/tomcat.pid
[root@centos7 temp]#startup.sh
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/default
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Using CATALINA_PID: /usr/local/tomcat/temp/tomcat.pid #多出的信息
Tomcat started.
# 测试两次延迟关闭 Tomcat,但总是立马就退出了
[root@centos7 tomcat]#catalina.sh stop
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr/java/default/jre
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Using CATALINA_PID: /usr/local/tomcat/temp/tomcat.pid
Tomcat stopped.
[root@centos7 tomcat]#catalina.sh stop 10
修改官方自带的 catalina.sh 脚本
通读了一遍catalina.sh脚本,发现原来是官方自带的脚本中有点小问题,所以导致 catalina.sh stop n 这个命令无效。
elif [ "$1" = "stop" ] ; then
shift
SLEEP=5
if [ ! -z "$1" ]; then
echo $1 | grep "[^0-9]" >/dev/null 2>&1
if [ $? -gt 0 ]; then
SLEEP=$1
shift
fi
fi
FORCE=0
if [ "$1" = "-force" ]; then
shift
FORCE=1
fi
if [ ! -z "$CATALINA_PID" ]; then
if [ -f "$CATALINA_PID" ]; then
if [ -s "$CATALINA_PID" ]; then
kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1
if [ $? -gt 0 ]; then
echo "PID file found but either no matching process was found or the current user does not have permission to stop the process. Stop aborted."
exit 1
fi
else
echo "PID file is empty and has been ignored."
fi
else
echo "\$CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted."
exit 1
fi
fi
eval "\"$_RUNJAVA\"" $LOGGING_MANAGER "$JAVA_OPTS" \
-D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
-classpath "\"$CLASSPATH\"" \
-Dcatalina.base="\"$CATALINA_BASE\"" \
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \
org.apache.catalina.startup.Bootstrap "$@" stop
# stop failed. Shutdown port disabled? Try a normal kill.
if [ $? != 0 ]; then
if [ ! -z "$CATALINA_PID" ]; then
echo "The stop command failed. Attempting to signal the process to stop through OS signal."
kill -15 `cat "$CATALINA_PID"` >/dev/null 2>&1
fi
fi
if [ ! -z "$CATALINA_PID" ]; then
if [ -f "$CATALINA_PID" ]; then
while [ $SLEEP -ge 0 ]; do
kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1
if [ $? -gt 0 ]; then
rm -f "$CATALINA_PID" >/dev/null 2>&1
if [ $? != 0 ]; then
if [ -w "$CATALINA_PID" ]; then
cat /dev/null > "$CATALINA_PID"
# If Tomcat has stopped don't try and force a stop with an empty PID file
FORCE=0
else
echo "The PID file could not be removed or cleared."
fi
fi
echo "Tomcat stopped."
break
fi
if [ $SLEEP -gt 0 ]; then
sleep 1 # 官方脚本中这里默认写的就是1,无论前面的变量到底赋值是多少,这里都定义的是1。
fi
# 在文件第592行
vim +592 catalina.sh
sleep 1
# 修改成
sleep $SLEEP
配合 CATALINA_PID 之Tomcat的启停脚本
#! /bin/bash
#-----------------------------------------------------
#Author: XingYuyu
#Date: 2024-10-18
#Blog: http://8.141.4.74
#Filename: start_tomcat.sh
#Description: [Enter Description Here]
#-----------------------------------------------------
# 定义变量
TOMCAT_HOME=/usr/local/tomcat
PID_FILE=${TOMCAT_HOME}/temp/tomcat.pid
start() {
if [ -f "$PID_FILE" ] && [ -s "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p $PID > /dev/null 2>&1; then
echo "Tomcat 已经在运行,进程号:$PID"
exit 1
else
echo "发现过期的 PID 文件,删除..."
rm -f "$PID_FILE"
fi
fi
echo "启动 Tomcat..."
$TOMCAT_HOME/bin/startup.sh
}
stop() {
if [ -f "$PID_FILE" ] && [ -s "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p $PID > /dev/null 2>&1; then
echo "停止 Tomcat,进程号:$PID"
kill $PID
sleep 5
if ps -p $PID > /dev/null 2>&1; then
echo "进程未停止,强制杀死..."
kill -9 $PID
fi
rm -f "$PID_FILE"
else
echo "PID 文件存在,但进程 $PID 不存在,删除 PID 文件..."
rm -f "$PID_FILE"
fi
else
echo "Tomcat 未运行,未找到 PID 文件。"
fi
}
status() {
if [ -f "$PID_FILE" ] && [ -s "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p $PID > /dev/null 2>&1; then
echo "Tomcat 正在运行,进程号:$PID"
else
echo "PID 文件存在,但进程 $PID 不存在。"
fi
else
echo "Tomcat 未运行。"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo "使用方法:$0 {start|stop|restart|status}"
exit 1
;;
esac