生产环境-linux-catalina.sh脚本停止不了服务分析解决

    在生产测试环境中,在使用脚本catalina.sh停止tomcat进程后失败,即时在catalina.sh脚本执行时加入-force参数也会失败,使用sh -x 分析catalina.sh脚本停止过程,将停止失败的地方抽取出来:

+ FORCE=1
+ ‘[‘ ‘!‘ -z ‘‘ ‘]‘
+ /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
2015-3-21 11:59:53 org.apache.catalina.startup.Catalina stopServer
严重: Catalina.stop: 
java.net.ConnectException: Connection refused
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
        at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
        at java.net.Socket.connect(Socket.java:529)
        at java.net.Socket.connect(Socket.java:478)
        at java.net.Socket.<init>(Socket.java:375)
        at java.net.Socket.<init>(Socket.java:189)
        at org.apache.catalina.startup.Catalina.stopServer(Catalina.java:422)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.catalina.startup.Bootstrap.stopServer(Bootstrap.java:338)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:416)
+ ‘[‘ ‘!‘ -z ‘‘ ‘]‘
+ ‘[‘ 1 -eq 1 ‘]‘
+ ‘[‘ -z ‘‘ ‘]‘
+ echo ‘Kill failed: $CATALINA_PID not set‘
Kill failed: $CATALINA_PID not set


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

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


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

第一处:

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

 $CATALINA_PID",如果存在则不显示
  if [ ! -z "$CATALINA_PID" ]; then
    echo "Using CATALINA_PID:    $CATALINA_PID"
  fi
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
  #但是[ ! -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脚本的代码前,加入以下语句:

CATALINA_PID=/home/xrltest1/tomcat/CATALINA_PID
echo 12031 > $CATALINA_PID

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


总结:

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

    我们可以看出,整个代码中,隐含的一个信息,$CATALINA_PID既要是一个文件还要写入tomcat项目的PID,那么catalina.sh在停止时,则会一路畅通...

    需要我们注意的是tomcat在启动时,同样的参数会启动多个实例,这个是我们不想看到了,所以tomcat启动、停止、重启还需要编写脚本,至于如何编写出满意的脚本,作者将在后面的文章中将作者在生产中使用的脚本举列给各位小伙伴分析下~




















本文出自 “运维路上” 博客,请务必保留此出处http://vekergu.blog.51cto.com/9966832/1623700

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。