方法一:

查找tomcat进程并kill

ps -elf | grep ${ctompath} | grep -v grep | awk '{print $4}' | xargs kill -9

此处可写成脚本,可参考我之前的脚本 https://www.cnblogs.com/shenjianxin/p/9263765.html

方法二:

修改$TOMCAT_HOME/bin/catalina.sh文件,在PRGDIR下面一行添加CATALINA_PID参数行,修改完成后应该跟下面相同。

# Get standard environment variables PRGDIR=`dirname "$PRG"` CATALINA_PID=$PRGDIR/CATALINA_PID

也可以自定义pid路径,例如“CATALINA_PID=/var/run/tomcat.pid”

要杀死进程需要添加参数 -force        ./shutdown.sh -force 或者 ./catalina.sh stop -force

源码分析:(以下出处https://blog.csdn.net/hxyerui/article/details/52181884)

最近我们在使用Jenkins自动化部署项目时,在生产liunx环境下,使用脚本shutdown.sh停止tomcat服务,然后再start之后发现应用无法访问了,后台查看tomcat进程是发现有个2个tomcat进程,说明之前的shutdown并没有完全停掉tomcat进程。那怎么样tomcat使用shutdown之后立马关掉其进程呢? 经查资料发现在shutdown.sh脚本之后有条命令是这样的:

exec "$PRGDIR"/"$EXECUTABLE" stop "$@"

这个就是停止tomcat 服务的命令,我们只需要加一个  -force  就可以在shutdown时强制关闭tomcat进程

exec "$PRGDIR"/"$EXECUTABLE" stop -force "$@"

但光这样还是不行,再shutdown时报错:

Kill failed: $CATALINA_PID not set

查找失败原因:

  1. + FORCE=1
  2. + '[' '!' -z '' ']'
  3. + /usr/java/jdk1.6.0_38/bin/java -server -Xms2048m -Xmx2048m -Xmn768m -XX:PermSize=128m -XX:MaxPermSize=256m -XX:+UseParallelOldGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/xrltest1/tomcat/dumpfile/heap.bin -Xloggc:/home/xrltest1/tomcat/logs/gc.log -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/home/xrltest1/tomcat/endorsed -classpath /home/xrltest1/tomcat/bin/bootstrap.jar -Dcatalina.base=/home/xrltest1/tomcat -Dcatalina.home=/home/xrltest1/tomcat -Djava.io.tmpdir=/home/xrltest1/tomcat/temp org.apache.catalina.startup.Bootstrap stop
  4. 2015-3-21 11:59:53 org.apache.catalina.startup.Catalina stopServer
  5. 严重: Catalina.stop:
  6. java.net.ConnectException: Connection refused
  7. at java.net.PlainSocketImpl.socketConnect(Native Method)
  8. at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
  9. at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
  10. at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
  11. at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
  12. at java.net.Socket.connect(Socket.java:529)
  13. at java.net.Socket.connect(Socket.java:478)
  14. at java.net.Socket.<init>(Socket.java:375)
  15. at java.net.Socket.<init>(Socket.java:189)
  16. at org.apache.catalina.startup.Catalina.stopServer(Catalina.java:422)
  17. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  18. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  19. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  20. at java.lang.reflect.Method.invoke(Method.java:597)
  21. at org.apache.catalina.startup.Bootstrap.stopServer(Bootstrap.java:338)
  22. at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:416)
  23. + '[' '!' -z '' ']'
  24. + '[' 1 -eq 1 ']'
  25. + '[' -z '' ']'
  26. + echo 'Kill failed: $CATALINA_PID not set'
  27. Kill failed: $CATALINA_PID not set

从中可以看到,首先是执行java命令失败,没有停止tomcat,然后执行-force模块的命令,但是却没有找到$CATALINA_PID设定的进程号,我们先不去关注java执行stop命令为什么报错,而是看看为什么加了-force参数也不起作用了

为什么没有$CATALINA_PID?接下来就带大家一探究竟

首先,我们将涉及到$CATALINA_PID变量的代码全部提取出来:

第一处:

#以下这句判断设置的$CATALINA_PID变量如果不存在,则显示"Using CATALINA_PID:

  1. $CATALINA_PID",如果存在则不显示
  2. if [ ! -z "$CATALINA_PID" ]; then
  3. echo "Using CATALINA_PID: $CATALINA_PID"
  4. fi
  5. fi

#貌似只是判断$CATALINA_PID是否是空字符,其他什么都没有做

第二处:(涉及到start参数的模块内的$CATALINA_PID变量,只是提出来分析,其实不对stop模块有影响)

#这个是start模块内的代码 "$_RUNJAVA" "$LOGGING_CONFIG" $JAVA_OPTS $CATALINA_OPTS \ -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \ -Dcatalina.base="$CATALINA_BASE" \ -Dcatalina.home="$CATALINA_HOME" \ -Djava.io.tmpdir="$CATALINA_TMPDIR" \ org.apache.catalina.startup.Bootstrap "$@" start \ >> "$CATALINA_OUT" 2>&1 & #从&可以看出启动的命令在后台启动 fi if [ ! -z "$CATALINA_PID" ]; then #判断CATALINA_PID如果不是空字符,则将Shell最后运行的后台Process的PID 传给$CATALINA_PID echo $! > "$CATALINA_PID" #在使用命令运行进程至后台时,可以使用$!抓取前面启动运行在后台进程的进程号 fi fi #上面语句是tomcat在启动时,会将$CATALINA_PID写入PID进程号

第三处:

#一下语句都出现在stop模块内 if [ ! -z "$CATALINA_PID" ]; then #$CATALINA_PID文件不是非空 if [ -f "$CATALINA_PID" ]; then if [ -s "$CATALINA_PID" ]; then kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #kill -0 pid 不发送任何信号,但是系统会进行错误检查。 if [ $? -gt 0 ]; then echo "PID file found but no matching process was found. 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

#如果发现$CATALINA_PID则发送一个模拟结束进程的型号,如果返回值为0,则正常,其他则异常,做退出操作

#从上面的sh -x输出的信息对应的是:'[' '!' -z '' ']' 可以看出$CATALINA_PID变量没有设定,所以这个判断直接就结束了,什么都没做

第四处:

#下面的代码紧接着stop的正常停止代码下 if [ ! -z "$CATALINA_PID" ]; then #如果$CATALINA_PID不为空 if [ -f "$CATALINA_PID" ]; then #而且还是普通文件 while [ $SLEEP -ge 0 ]; do #而且$SLEEP还大于0 kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #则测试下tomcat能不能被关闭 if [ $? -gt 0 ]; then #剩下的参数还有,则清空$CATALINA_PID rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then if [ -w "$CATALINA_PID" ]; then cat /dev/null > "$CATALINA_PID" else echo "Tomcat stopped but the PID file could not be removed or cleared." fi fi break fi if [ $SLEEP -gt 0 ]; then sleep 1 fi if [ $SLEEP -eq 0 ]; then if [ $FORCE -eq 0 ]; then echo "Tomcat did not stop in time. PID file was not removed." fi fi SLEEP=`expr $SLEEP - 1 ` done fi fi #上段语句主要是判断tomcat是否被关闭 #核心语句还是:kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #while语句做sleep使用,用于清空$CATALINA_PID #但是[ ! -z "$CATALINA_PID" ]导致这段语句什么都没做啊!!!!!

第五处:

#这段代码就是涉及-force的核心代码了 if [ $FORCE -eq 1 ]; then if [ -z "$CATALINA_PID" ]; then echo "Kill failed: \$CATALINA_PID not set" else if [ -f "$CATALINA_PID" ]; then PID=`cat "$CATALINA_PID"` echo "Killing Tomcat with the PID: $PID" kill -9 $PID #强制执行的核心命令 rm -f "$CATALINA_PID" >/dev/null 2>&1 if [ $? != 0 ]; then echo "Tomcat was killed but the PID file could not be removed." fi fi fi fi #从中就可以看出,sh -x输出的Kill failed: $CATALINA_PID not set是怎么来的

总结下,$CATALINA_PID在整个代码中的作用:

1.在tomcat启动时会写入$CATALINA_PID,但是假设我们的环境是多tomcat项目或$CATALINA_PID为空

2.stop代码中,检查$CATALINA_PID是否为空字符,是的话什么都不做

3.sstop代码中,检查$CATALINA_PID是否为空字符,是的话什么都不做

4.force代码中,检查$CATALINA_PID是否为空字符,是的话就报错

也就是说只要没有保存中这个项目的PID,那么正常stop停止不了,-force也是没有用的。

那么该如何解决呢?直接给$CATALINA_PID付PID的值,那么看结果:

+ FORCE=1 + '[' '!' -z 12031 ']' + '[' -f 12031 ']' + echo '$CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted.' $CATALINA_PID was set but the specified file does not exist. Is Tomcat running? Stop aborted.

涉及到的代码:

if [ -f "$CATALINA_PID" ]; then if [ -s "$CATALINA_PID" ]; then kill -0 `cat "$CATALINA_PID"` >/dev/null 2>&1 #kill -0 pid 不发送任何信号,但是系统会进行错误检查。 if [ $? -gt 0 ]; then echo "PID file found but no matching process was found. 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 #$CATALINA_PID不是个文件,所以不好意思,我退出了....

原来$CATALINA_PID还必须是个文件,那么我们可不可以建这么一个文件呢?

在catalina.sh脚本的代码前,加入以下语句:

######################################################################################### if [ -z "$CATALINA_PID" ]; then     CATALINA_PID=$PRGDIR/CATALINA_PID     cat $CATALINA_PID fi

######################################################################################

结果:tomcat停止执行成功,完成结束进程任务

总结:

在我看到的很到部署tomcat的文章中,还没发现有关于设置$CATALINA_PID文件路径的提示(也许是我看到的少),但是此处我要建议小伙伴们,在写tomcat启动、停止、重启的脚本的时候,一定要注意这个变量。

tomcat 在liunx中shutdown后进程仍然存在的两种实用解决办法的更多相关文章

  1. Oracle 11g 数据库 shutdown 后立即执行 startup mount 报错的解决办法

    最新文章:Virson's Blog 今天在配置Goldengate时Capture进程提示未开启归档日志,然后立即用sys用户登录orcl数据库,然后执行了“shutdown immediate”命 ...

  2. wamp中修改后mysq数据库l闪退无法登陆解决办法

    WampServer安装后密码是空的,   修改一般有三种方式:   一是通过phpMyAdmin直接修改:   二是使用WAMP的MySql控制台修改.     三是重置密码    第一种:   1 ...

  3. 关于csrss.exe和winlogon.exe进程多、占用CPU高的解决办法,有人在暴力破解

    关于csrss.exe和winlogon.exe进程多.占用CPU高的解决办法 最近VPS的CPU一直处在100%左右,后台管理上去经常打不开,后来发现上远程都要好半天才反映过来,看到任务管理器有多个 ...

  4. Linux进程分配内存的两种方式--brk() 和mmap()

    如何查看进程发生缺页中断的次数? 用ps -o majflt,minflt -C program命令查看. majflt代表major fault,中文名叫大错误,minflt代表minor faul ...

  5. 内存分配的原理__进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)

    如何查看进程发生缺页中断的次数? 用ps -o majflt,minflt -C program命令查看. majflt代表major fault,中文名叫大错误,minflt代表minor faul ...

  6. Android中EditText显示明文与密文的两种方式

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 记录输入框显示.隐藏密码的简单布局以及实现方式. 效果图    代码分析 方式一 /**方式一:*/ private void sh ...

  7. linux尝试登录失败后锁定用户账户的两种方法

    linux尝试登录失败后锁定用户账户的两种方法 更新时间:2017年06月23日 08:44:31   作者:Carey    我要评论   这篇文章主要给大家分享了linux尝试登录失败后锁定用户账 ...

  8. combogrid翻页后保持显示内容为配置的textField解决办法

    easyui的combogrid当配置pagination为true进行分页时,当datagrid加载其他数据页,和上一次选中的valueField不匹配时,会导致combogrid直接显示value ...

  9. Windows Server 2008 R2中IIS7.5配置完网站权限不足问题的解决办法:

    Windows Server 2008 R2中IIS7.5配置完网站权限不足问题的解决办法:常见问题:HTTP 错误 500.0 - Internal Server Error无法显示页面,因为发生内 ...

随机推荐

  1. n=n+1 放在print(s)的上面的影响 (2) n=n=+1在前面,则不满足前面<100条件时候,才跳出while的循环,这时候while循环结束, 到了外面的下一步-->print()

    1+2+3+....+100=     ? n=1 s = 0 while n < =100: s = s+n n= n+1 # n=n+1    在print(s)上面的情况 print(s)

  2. Basestation函数解析(二)

    ---恢复内容开始--- 这部分从Basestation的RecvDataThread开始,流程为 RecvDataThread->RecvData->Decoder->PostDa ...

  3. Java 输入输出流总结

    1. 运用BufferedInputStream 读取文件流和BufferedOutputStream写文件流: protected static void writeFile2(String inp ...

  4. MEMCACHE与REDIS

    千万数据量的高并发,容灾. Redis 基于单线程, 持久性 多数据类型 内存中只存KEY Redis支持数据的备份,即master-slave模式的数据备份. Redis与Memcached的区别 ...

  5. JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释 (生动形象)

    [转自]:https://blog.csdn.net/sd4015700/article/details/50109939 jvm区域总体分两类,heap区和非heap区.heap区又分:Eden S ...

  6. two sum[easy]

    Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...

  7. Java泛型学习二

    通配符的使用 上一篇中知道,Box<Number>和Box<Integer>实际上都是Box类型,现在需要继续探讨一个问题,那么在逻辑上,类似于Box<Number> ...

  8. CentOS部署Kubernetes1.13集群-1(使用kubeadm安装K8S)

    参考:https://www.kubernetes.org.cn/4956.html 1.准备 说明:准备工作需要在集群所有的主机上执行 1.1系统配置 在安装之前,需要先做如下准备.三台CentOS ...

  9. 初识Qt文字绘制

    1.新建一个Qt Gui应用,项目名称为myDraw,基类选择为QMainWindow,类名设置为MainWindow. 2.在mainwindow.h头文件中添加void paintEvent(QP ...

  10. PAT乙级1030

    1030 完美数列 (25 分)   给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 M≤mp,则称这个数列是完美数列. 现在给定参数 p 和一些正整数,请你从中选择 ...