答疑:tomcat关闭脚本怎么确保不误杀其他进程

Q: tomcat的关闭过程是怎么触发的?是通过系统信号吗?如果存在多个tomcat进程,关闭时怎么保证不会误杀?

A: 这个过程可以跟踪一下关闭时的脚本就知道了。

$ bash -x ./catalina.sh stop
...
eval '"/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home/bin/java"'
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Dlog4j.defaultInitOverride=true
-Dorg.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE=true
-Dorg.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0=true '
-Djava.endorsed.dirs="/data/server/tomcat/endorsed"'
-classpath '"/data/server/tomcat/bin/bootstrap.jar:/data/server/tomcat/bin/tomcat-juli.jar"' '
-Dcatalina.base="/data/server/tomcat"' '
-Dcatalina.home="/data/server/tomcat"' '
-Djava.io.tmpdir="/data/server/tomcat/temp"'
org.apache.catalina.startup.Bootstrap stop

可见是新启了一个java进程,调用org.apache.catalina.startup.Bootstrapmain方法,传入的stop参数。

跟踪一下这个新的java进程执行过程,堆栈大致如下:

at java.net.Socket.(Socket.java:208)
at org.apache.catalina.startup.Catalina.stopServer(Catalina.java:477)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.catalina.startup.Bootstrap.stopServer(Bootstrap.java:371)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:452)

Bootstrapmain方法里的,对stop参数会执行stopServer的操作:

...
else if (command.equals("stop")) {
    daemon.stopServer(args);
}

stopServer是通过反射调用的Catalina.stopServer,它通过解析当前CATALINA_HOME/conf/server.xml从中得到正在运行的tomcat实例的关闭端口(server port, 默认是8005)和关闭指令(默认是SHUTDOWN),然后通过socket连接到这个目标端口上,发送关闭指令。如果我们直接telnet到目标端口,然后输入指令也是一样的:

所以通过默认脚本关闭tomcat,并不关心tomcat进程pid,而是socket通讯的方式。如果存在多个tomcat实例,每个tomcat的server port都是不同的。

如果不通过8005端口的方式,而是系统信号的方式,tomcat则是通过了ShutdownHook来确保在进程退出前关闭服务的。这时如果有多个tomcat进程实例,就需要明确进程pid了,一些改进的脚本会在启动时把进程pid记录在某个文件来以便后续使用。

发表评论

电子邮件地址不会被公开。 必填项已用*标注