【问题标题】:How to gracefully shutdown servelts in tomcat in docker container?如何在docker容器中优雅地关闭tomcat中的servlts?
【发布时间】:2019-01-11 11:57:06
【问题描述】:

到目前为止我发现了什么:

  • “docker stop”向容器中的进程 ID 1 发送 SIGTERM。
  • 容器中的进程ID 1是运行tomcat的java进程。*)
  • 是的,tomcat 本身会正常关闭,但 servlet 不会这样做。
  • Servlet 在 2 秒后被杀死,即使它们正在处理请求 (!!)

*) 旁注: 虽然我们的容器入口点是 [ "/opt/tomcat/bin/catalina.sh", "run" ],但是 在 catalina.sh 中,java 进程是通过 bash 内置“exec”命令启动的, 因此 java 进程替换 shell 进程并因此成为新的进程 id 1。 (我可以通过执行到正在运行的容器中来验证这一点,并在其中执行“ps aux”。) 顺便说一句,我使用的是 tomcat 7.0.88。

我发现关于 tomcat 默认情况下执行正常关闭的语句(http://tomcat.10.x6.nabble.com/Graceful-Shutdown-td5020523.html - “任何正在进行的连接都将完成”),但我只能看到从 docker 发送到 java 进程的 SIGTERM 几乎不会导致停止正在执行的请求。

我写了一个小的 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。如果这很重要,我主要关心的是 jersey servlet (org.glassfish.jersey.servlet.ServletContainer)。

或者也许还有其他的可能性,我现在还没有看到?

(我将 kubernetes 添加到标签列表中,因为这可能是 Kubernetes 的主要问题,因为它经常重新定位(docker stop->SIGTERM)容器,只是为了保持负载平衡。)

【问题讨论】:

    标签: java docker tomcat kubernetes shutdown


    【解决方案1】:

    现在我在这里找到了答案:https://stackoverflow.com/a/11154770/2081279

    它在 linux 下对我有用

    <Context path="/myapp" unloadDelay="10000"/> 
    

    但只有大写字母“C”上下文。

    【讨论】:

      【解决方案2】:

      您可以公开一个 REST API 以优雅地停止服务器。

      1) 实现并使用 javax 过滤器,该过滤器将正在进行的 HTTP 请求保持在自己的状态。
      2) 随着停止事件的发生,当前的 tomcat 实例不再需要为任何新的客户端请求提供服务。因此,请确保新请求无法重定向到此实例。
      3)当停止事件发生时(第二件事),启动一个等待所有请求都被服务的线程。发送完所有响应后,请求关闭 tomcat 实例:the command String shutdown may be a way

      【讨论】:

      • 是的,我能做到。但我还必须确保原始的 SIGTERM 不会到达 tomcat,而只有我自己的逻辑。毕竟,我会重新实现一些应该是服务器功能的东西。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-06
      • 2016-05-10
      • 2022-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-02
      相关资源
      最近更新 更多