如何在 docker 容器中优雅地关闭 tomcat 中的 servelts?
How to gracefully shutdown servelts in tomcat in docker container?
到目前为止我发现了什么:
- “docker 停止”向容器中的进程 ID 1 发送 SIGTERM。
- 容器中进程ID 1为java进程运行ning tomcat.*)
- 是的,tomcat 本身会正常关闭,但 servlet 不会这样做。
- Servlet 在 2 秒后被杀死,即使它们正在处理请求(!!)
*) 旁注:
虽然我们的容器入口点是 [ "/opt/tomcat/bin/catalina.sh", "运行" ],但是
在 catalina.sh 中,java 进程是通过 bash buildin "exec" 命令启动的,
因此 java 进程 替换 shell 进程并因此成为新的进程 ID 1。
(我可以通过 exec 进入 运行ning 容器并在其中执行“ps aux”来验证这一点。)
顺便说一句,我正在使用 tomcat 7.0.88.
我找到了关于 tomcat 默认情况下正常关闭的声明(http://tomcat.10.x6.nabble.com/Graceful-Shutdown-td5020523.html - “任何正在进行的连接都将完成”),但我只能看到从docker 到 java 进程几乎不会停止正在执行的请求。
我写了一个小的 rest servlet 来测试这个行为:
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.Status;
@Path("/")
public class SlowServerRes
{
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("test1")
public Response test1(@QueryParam("sleep") final int sleepDurationSec)
{
long received = System.currentTimeMillis();
System.out.println("+++++++++++++++++++++ received request at " + received);
for (int i=1; i <= sleepDurationSec; i++) {
System.out.println(" ++++ Sleeping for 1 sec ("+i+")");
try { Thread.sleep(1000); }
catch (InterruptedException e) {
System.out.println(" Sleep was interrupted at second " + i + " ... ignoring/continue sleeping.");
}
}
long finished = System.currentTimeMillis();
String result = "received: " + received + " finished: " + finished;
System.out.println("+++++++++++++++++++++ " + result);
Response response = Response.status(Status.OK).entity(result).build();
return response;
}
}
经过深入的谷歌搜索,我终于看到了这个帖子:
http://grokbase.com/t/tomcat/users/113nayv5kx/tomcat-6-graceful-shutdown
因此,给予 tomcat 的宽限期不会传播为 servlet 的宽限期。
我想知道天气这很有意义,但看起来这是事实。
因此,让 servlet 有可能正确结束其正在进行的请求的唯一方法是更改
“unloadDelay”(https://tomcat.apache.org/tomcat-7.0-doc/config/context.html)。
但是,我没有在 tomcat 配置文件中找到正确的位置来定义非默认的 unloadDelay。如果这很重要,我主要关心的是球衣 servlets (org.glassfish.jersey.servlet.ServletContainer)。
或者也许还有其他可能性,我现在还没有看到?
(我将 kubernetes 添加到标签列表中,因为这可能是一个主要问题,尤其是对于 Kubernetes,因为它经常重新定位 (docker stop->SIGTERM) 容器,只是为了保持负载平衡。 )
您可以公开 REST API 以优雅地停止服务器。
1) 实施并使用一个 javax 过滤器,该过滤器将正在进行的 HTTP 请求保持在自己的状态。
2) 当停止事件发生时,当前 tomcat 实例不必再为新客户端请求提供服务。所以要确保新的请求不能被重定向到这个实例。
3) 当停止事件发生时(第二件事),启动一个等待所有请求被处理的线程。发送所有响应后,请求 tomcat 实例关闭:the command String shutdown may be a way。
现在我在这里找到了答案:
它在 linux 和
下对我有用
<Context path="/myapp" unloadDelay="10000"/>
但只有大写字母 "C"ontext.
到目前为止我发现了什么:
- “docker 停止”向容器中的进程 ID 1 发送 SIGTERM。
- 容器中进程ID 1为java进程运行ning tomcat.*)
- 是的,tomcat 本身会正常关闭,但 servlet 不会这样做。
- Servlet 在 2 秒后被杀死,即使它们正在处理请求(!!)
*) 旁注: 虽然我们的容器入口点是 [ "/opt/tomcat/bin/catalina.sh", "运行" ],但是 在 catalina.sh 中,java 进程是通过 bash buildin "exec" 命令启动的, 因此 java 进程 替换 shell 进程并因此成为新的进程 ID 1。 (我可以通过 exec 进入 运行ning 容器并在其中执行“ps aux”来验证这一点。) 顺便说一句,我正在使用 tomcat 7.0.88.
我找到了关于 tomcat 默认情况下正常关闭的声明(http://tomcat.10.x6.nabble.com/Graceful-Shutdown-td5020523.html - “任何正在进行的连接都将完成”),但我只能看到从docker 到 java 进程几乎不会停止正在执行的请求。
我写了一个小的 rest servlet 来测试这个行为:
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.Status;
@Path("/")
public class SlowServerRes
{
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("test1")
public Response test1(@QueryParam("sleep") final int sleepDurationSec)
{
long received = System.currentTimeMillis();
System.out.println("+++++++++++++++++++++ received request at " + received);
for (int i=1; i <= sleepDurationSec; i++) {
System.out.println(" ++++ Sleeping for 1 sec ("+i+")");
try { Thread.sleep(1000); }
catch (InterruptedException e) {
System.out.println(" Sleep was interrupted at second " + i + " ... ignoring/continue sleeping.");
}
}
long finished = System.currentTimeMillis();
String result = "received: " + received + " finished: " + finished;
System.out.println("+++++++++++++++++++++ " + result);
Response response = Response.status(Status.OK).entity(result).build();
return response;
}
}
经过深入的谷歌搜索,我终于看到了这个帖子: http://grokbase.com/t/tomcat/users/113nayv5kx/tomcat-6-graceful-shutdown
因此,给予 tomcat 的宽限期不会传播为 servlet 的宽限期。 我想知道天气这很有意义,但看起来这是事实。 因此,让 servlet 有可能正确结束其正在进行的请求的唯一方法是更改 “unloadDelay”(https://tomcat.apache.org/tomcat-7.0-doc/config/context.html)。
但是,我没有在 tomcat 配置文件中找到正确的位置来定义非默认的 unloadDelay。如果这很重要,我主要关心的是球衣 servlets (org.glassfish.jersey.servlet.ServletContainer)。
或者也许还有其他可能性,我现在还没有看到?
(我将 kubernetes 添加到标签列表中,因为这可能是一个主要问题,尤其是对于 Kubernetes,因为它经常重新定位 (docker stop->SIGTERM) 容器,只是为了保持负载平衡。 )
您可以公开 REST API 以优雅地停止服务器。
1) 实施并使用一个 javax 过滤器,该过滤器将正在进行的 HTTP 请求保持在自己的状态。
2) 当停止事件发生时,当前 tomcat 实例不必再为新客户端请求提供服务。所以要确保新的请求不能被重定向到这个实例。
3) 当停止事件发生时(第二件事),启动一个等待所有请求被处理的线程。发送所有响应后,请求 tomcat 实例关闭:the command String shutdown may be a way。
现在我在这里找到了答案:
它在 linux 和
下对我有用<Context path="/myapp" unloadDelay="10000"/>
但只有大写字母 "C"ontext.