zoukankan      html  css  js  c++  java
  • Tomcat意外宕机分析

      之前在网上看过一篇文章,是讲Tomcat进程意外退出的,我看完感觉好奇,自己也测试了下,果然是有这种问题,所以自己也借此总结一下。

      先简单说下测试过程,先创建一个web服务启动 test.sh,内容如下:

    #!/bin/bash
    cd /usr/software/tomcat/apache-tomcat-7.0.81/bin/
    ./catalina.sh start
    tail -f /usr/software/tomcat/apache-tomcat-7.0.81/logs/catalina.out

      然后启动该脚本,服务起来了,可以正常访问。

      tomcat启动之后,当前shell进程并没有退出,而是挂住在tail进程,往终端输出日志内容。这种情况下:

      1)、如果我先直接关掉ssh窗口后,Java进程会退出,服务不可用。

      2)、而我如果先 用ctrl-c终止test.sh进程,然后再关闭ssh终端的话,这时Java进程不会退出。服务没有受到影响,仍然可用。

      3)、下面我又把最后tail这一行去掉,发现直接关掉ssh终端窗口,Java进程也不会退出,服务不受影响。

    #!/bin/bash
    cd /usr/software/tomcat/apache-tomcat-7.0.81/bin/
    ./catalina.sh start

      4)、最后我再次恢复tail这一行,然后在开头再加上 set -m, 直接关掉ssh窗口Java进程同样也不会退出,服务同样也不受影响。

    #!/bin/bash
    set -m
    cd /usr/software/tomcat/apache-tomcat-7.0.81/bin/
    ./catalina.sh start
    tail -f /usr/software/tomcat/apache-tomcat-7.0.81/logs/catalina.out

      到这里是不是有点晕了,不急,待我慢慢道出原因来。

      这是一个有趣的现象,catalina.sh start方式启动的tomcat会把java进程挂到init(进程id为1)的父进程下,已经与当前test.sh进程脱离了父子关系,也与ssh进程没有关系,为什么关闭ssh终端窗口会导致java进程退出?

      经过测试,有发现:

      a) 用 ctrl-c 终止当前test.sh进程时,系统events进程向 java 和 tail 两个进程发送了SIGINT 信号

      b) 关闭ssh终端窗口时,sshd向下游进程发送SIGHUP, java进程也会收到。

      后来通过google后了解到: shell在非交互模式下对后台进程处理SIGINT信号时设置的是IGNORE

      交互模式与非交互模式对作业控制(job control)默认方式不同:

      I)在交互模式下,因为作业控制的需要shell不会对后台进程处理SIGINT信号设置为忽略。因此这样的话,父进程会把收到的键盘事件比如ctrl-c之类的SIGINT传播给进程组中的每个成员(假设后台进程也是父进程组的成员),那么终端随意ctrl-c就可能导致所有的后台进程退出,显然这样是不合理的。因此,在交互模式下的后台进程会设置一个自己的进程组ID。

      II)而非交互模式下,通常是不需要作业控制的,所以作业控制在非交互模式下默认也是关闭的(当然也可以在脚本里通过选项set -m打开作业控制选项)。不开启作业控制的话,脚本里的后台进程可以通过设置忽略SIGINT信号来避免父进程对组中成员的传播,因为对它来说这个信号已经没有意义。

      在非交互模式下,shell对java进程设置了SIGINTSIGQUIT信号设置了忽略,但并没有对SIGHUP信号设为忽略,回头看上面说的,直接关闭ssh终端窗口时,sshd向下游进程发送SIGHUP, java进程也会收到。

      再看一下当时的进程层级:

      |-sshd(1622)-+-sshd(11681)---sshd(11699)---bash(11700)---test.sh(13285)---tail(13299)

      

      sshd把SIGHUP传递给bash进程后,bash会把SIGHUP传递给它的子进程,并且对于其子进程test.sh,bash还会对test.sh的进程组里的成员都传播一遍SIGHUP。因为java后台进程从父进程catalina.sh(又是从其父进程test.sh)继承的pgid,所以java进程仍属于test.sh进程组里的成员,收到SIGHUP后退出。

      如果我们在test.sh里设置开启作业控制的话,就不会让java进程退出了

    #!/bin/bash
    set -m
    cd /usr/software/tomcat/apache-tomcat-7.0.81/bin/
    ./catalina.sh start
    tail -f /usr/software/tomcat/apache-tomcat-7.0.81/logs/catalina.out

      此时java后台进程继承父进程catalina.sh的pgid,而catalina.sh不再使用test.sh的进程组,而是自己的pid作为pgid,catalina.sh进程在执行完退出后,java进程挂到了init下,java与test.sh进程就完全脱离关系了,bash也不会再向它发送信号。

      

      注: 如果把tail 打印的这一行去掉,为什么Java进程也不会退出,我猜原因应该是,如果没有tail的话, Java进程就不是他们的子进程了,自然怎么操作都不会受影响。

  • 相关阅读:
    Docker初识
    57、android 应用内全局通知的实现方法
    56、使用android studio(v1.3.*)修改包名 (rename package name)
    55、android app借助友盟实现微信授权登录
    54、edittext输入类型限制为ip,inputType应该如何设置
    53、listview、expandableListview如何选中时保持高亮?
    52、sb犯的错误
    51、如何提取android代码中的字符串为系统资源文件 (I18N)
    50、转自知乎上android开发相见恨晚的接口
    49、android studio 使用技巧记录
  • 原文地址:https://www.cnblogs.com/xiexin2015/p/9032510.html
Copyright © 2011-2022 走看看