跳到主要内容

设置监听关闭端口优雅关闭tomcat

2023-06-28

阅读 ranger 代码内置 web server的部分, 启动webserver的时候设置了两个port, 并且标记其中一个为shutdownPort, 觉得有点奇怪.

咨询了chatgpt, 原来tomcat还支持优雅关闭, 提前设置好监听关闭命令的端口, 约定好监听命令, 然后就可以通过发送命令到指定端口优雅关闭了.


package org.apache.ranger.server.tomcat;

public class EmbeddedServer {

public static int DEFAULT_SHUTDOWN_PORT = 6185;
public static String DEFAULT_SHUTDOWN_COMMAND = "SHUTDOWN";

public void start() {

final Tomcat server = new Tomcat();
String servername = EmbeddedServerUtil.getConfig("servername");
String hostName = EmbeddedServerUtil.getConfig("ranger.service.host");
int serverPort = EmbeddedServerUtil.getIntConfig("ranger.service.http.port", 6181);
int shutdownPort = EmbeddedServerUtil.getIntConfig("ranger.service.shutdown.port", DEFAULT_SHUTDOWN_PORT);
String shutdownCommand = EmbeddedServerUtil.getConfig("ranger.service.shutdown.command", DEFAULT_SHUTDOWN_COMMAND);

server.setHostname(hostName);
server.setPort(serverPort);
server.getServer().setPort(shutdownPort);
server.getServer().setShutdown(shutdownCommand);

...
}
}

picture 1

picture 2

ranger里同时提供了用于优雅关闭tomcat的代码, 看起来就是启动一个socket连接到tomcat的shutdownPort, 然后发送shutdown命令即可.

发送命令到端口, 竟然是用print方法.


package org.apache.ranger.server.tomcat;

import java.io.PrintWriter;
import java.net.Socket;

public class StopEmbeddedServer extends EmbeddedServer {

private static final String SHUTDOWN_HOSTNAME = "localhost";

public static void main(String[] args) {
new StopEmbeddedServer(args).stop();
}

public StopEmbeddedServer(String[] args) {
super(args);
}

public void stop() {

try {

int shutdownPort = EmbeddedServerUtil.getIntConfig("ranger.service.shutdown.port", DEFAULT_SHUTDOWN_PORT );
String shutdownCommand = EmbeddedServerUtil.getConfig("ranger.service.shutdown.command", DEFAULT_SHUTDOWN_COMMAND );

Socket sock = new Socket(SHUTDOWN_HOSTNAME,shutdownPort);

PrintWriter out = new PrintWriter(sock.getOutputStream(), true);

out.println(shutdownCommand);

out.flush();

out.close();
}
catch(Throwable t) {
System.err.println("Server could not be shutdown due to exception:" + t);
System.exit(1);
}
}

关闭命令脚本, 异步执行的java命令就是 org.apache.ranger.server.tomcat.StopEmbeddedServer


# /root/projects/ranger/embeddedwebserver/scripts/ranger-admin-services.sh

stop(){
WAIT_TIME_FOR_SHUTDOWN=2
NR_ITER_FOR_SHUTDOWN_CHECK=15
if [ -f "$pidf" ] ; then
pid=`cat $pidf` > /dev/null 2>&1
echo "Getting pid from $pidf .."
else
pid=`ps -ef | grep java | grep -- '-Dproc_rangeradmin' | grep -v grep | awk '{ print $2 }'`
if [ "$pid" != "" ];then
echo "pid file($pidf) not present, taking pid from \'ps\' command.."
else
echo "Apache Ranger Admin Service is not running"
return
fi
fi

echo "Found Apache Ranger Admin Service with pid $pid, Stopping it..."
nohup java ${JAVA_OPTS} -Duser=${USER} -Dhostname=${HOSTNAME} -Dlogdir=${RANGER_ADMIN_LOG_DIR} -Dcatalina.base=${XAPOLICYMGR_EWS_DIR} -cp "${XAPOLICYMGR_EWS_DIR}/webapp/WEB-INF/classes/conf:${XAPOLICYMGR_EWS_DIR}/lib/*:${RANGER_JAAS_LIB_DIR}/*:${RANGER_JAAS_CONF_DIR}:${RANGER_HADOOP_CONF_DIR}/*:$CLASSPATH" org.apache.ranger.server.tomcat.StopEmbeddedServer > ${RANGER_ADMIN_LOG_DIR}/catalina.out 2>&1
for ((i=0; i<$NR_ITER_FOR_SHUTDOWN_CHECK; i++))
do
sleep $WAIT_TIME_FOR_SHUTDOWN
if ps -p $pid > /dev/null ; then
echo "Shutdown in progress. Will check after $WAIT_TIME_FOR_SHUTDOWN secs again.."
continue;
else
break;
fi
done
# if process is still around, use kill -9
if ps -p $pid > /dev/null ; then
echo "Initial kill failed, getting serious now..."
kill -9 $pid
fi
sleep 1 #give kill -9 sometime to "kill"
if ps -p $pid > /dev/null ; then
echo "Wow, even kill -9 failed, giving up! Sorry.."
exit 1

else
rm -rf $pidf
echo "Apache Ranger Admin Service with pid ${pid} has been stopped."
fi

}