代码之家  ›  专栏  ›  技术社区  ›  Thomas Schütt

如何在docker容器中优雅地关闭tomcat中的服务器?

  •  1
  • Thomas Schütt  · 技术社区  · 6 年前

    到目前为止我发现:

    • “docker stop”发送一个SIGTERM到容器中的进程ID 1。
    • 容器中的进程ID 1是运行tomcat的java进程。*)
    • 即使在处理reguest的过程中,Servlet也会在2秒后被杀死(!!)

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

    我发现了关于tomcat在默认情况下执行gracefull shutdown的语句( 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有可能正确地结束其正在进行的请求的唯一方法是更改 “解锁”( https://tomcat.apache.org/tomcat-7.0-doc/config/context.html ).

    但是,我没有在tomcat配置文件中找到正确的位置来定义非默认unloadDelay。在这种情况下,我主要关心的是jersey servlet(org.glassfish.jersey.servlet.ServletContainer)。

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

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

    2 回复  |  直到 6 年前
        1
  •  2
  •   Thomas Schütt    6 年前

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

    它在linux下为我工作

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

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

        2
  •  0
  •   davidxxx    6 年前

    您可以公开REST API来正常地停止服务器。

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