当前位置: 首页 > 知识库问答 >
问题:

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

裘丰
2023-03-14

到目前为止,我发现:

  • docker停止向容器中的进程ID 1发送SIGTERM。
  • 容器中的进程ID 1是运行tomcat的java进程。*)
  • 是的,tomcat本身会优雅地关闭,但servlet不会这样做。
  • Servlet在2秒后被杀死,即使他们正在处理一个再访客(!!)

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

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

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

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

(我将kubernetes添加到标记列表中,因为这可能是kubernetes特别关注的问题,因为它会重新定位(docker stop)-

共有2个答案

满玉泽
2023-03-14

您可以公开一个RESTAPI来正常停止服务器。

1)实现并使用一个javax过滤器,它将正在进行的HTTP请求保持在自己的状态。
2)当停止事件发生时,当前tomcat实例不必为任何更长的新客户端请求提供服务。因此,请确保新请求不能重定向到此实例。
3)当停止事件发生时(第二件事),启动一个等待所有请求被服务的线程。当所有响应都已发送时,请请求tomcat实例关闭:命令String关闭可能是一种方法。

华季萌
2023-03-14

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

它在linux下对我起作用

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

但仅限于大写字母“C”的上下文。

 类似资料:
  • 在我的webapp中,我创建了一个使用具有固定大小线程池的的服务。我在整个应用程序生命周期中重用相同的。 All在Tomcat中运行,在关闭时出现以下错误: 我确实意识到在关闭tomcat之前需要关闭ExecutorService。Soms所以线程已经谈到了这一点,但我找不到一个干净的方法来处理这一点。 我是否应该使用,就像@tim-bender建议的那样,在优雅地关闭线程和执行器?还是应该使用C

  • 在这种情况下,优雅地关闭WebSocket的正确方法是什么?

  • 我们如何优雅地关闭守护进程线程[ActiveMQ会话:ID:PC-63704-1472105244157-1:1:1]? spring-boot activeMQ设置如下所示 对于发送消息,我们只是简单地autowired JmsTemplate并发送消息出去: 对于接收(监听)消息,我们使用Spring DefaultMessageListenerContainer(DMLC) 我们还有其他的设

  • 我有一个应用程序运行在嵌入式jetty服务器上。现在我想将服务器作为服务启动/停止。我使用一个脚本来启动服务器。

  • 优雅关闭,包括两部分,一个是 RPC 框架作为客户端,一个是 RPC 框架作为服务端。 作为服务端 作为服务端的时候,RPC 框架在关闭时,不应该直接暴力关闭。在 RPC 框架中 com.alipay.sofa.rpc.context.RpcRuntimeContext 在静态初始化块中,添加了一个 ShutdownHook // 增加jvm关闭事件 if (RpcConf

  • 本文向大家介绍docker容器如何优雅的终止详解,包括了docker容器如何优雅的终止详解的使用技巧和注意事项,需要的朋友参考一下 前言 在Docker大行其道的今天,我们能够非常方便的使用容器打包我们的应用程序,并且将它在我们的服务器上部署并运行起来。但是,谈论到如何停掉运行中的docker容器并正确的终止其中的程序,这就成为一个非常值得讨论的话题了。 事实上,在我们日常的项目当中,这是我们经常