【问题标题】:Tomcat shutdown leading to data loss from executor service?Tomcat关闭导致执行程序服务数据丢失?
【发布时间】:2019-06-26 12:33:12
【问题描述】:

我有几个 Kafka 消费者从 Kafka 集群中提取消息,然后他们将这些消息放入执行器服务中进行处理。消息本身的处理是耗时的。当我尝试关闭应用程序时——即关闭 Tomcat,我注意到执行程序服务将继续工作,但速度要慢得多,并且出现一些套接字超时异常。这意味着我可能要等待很长时间才能完成 Tomcat 关闭过程,但它只是继续运行。如果我手动杀死 Tomcat 线程,那么我会丢失很多消息。我有办法解决这个问题吗?非常感谢!

【问题讨论】:

  • 在关闭事件的上下文监听器中关闭执行器服务。
  • 在您的应用程序成功处理消息之前,您的 Kafka 消费者可能正在确认已收到消息。确保在关闭时停止您的 Kafka 消费者并处理所有待处理的消息;或者,在处理消息之前不要知道消息(请参阅 kafka 指南..)
  • 感谢您的回答!是的,我昨晚多想了一些,相信消费者一定还在忙着从软管里喝水。由于消费者获取消息的速度比执行者处理消息的速度要快,因此Tomcat必须一直等待......所以我们可以先尝试关闭消费者,然后一旦确认关闭,我们就可以关闭Tomcat。使用 Spring Boot,我刚刚开始寻找停止监听器的方法。可能是这样的:stackoverflow.com/questions/47062346/….

标签: java tomcat executorservice shutdown


【解决方案1】:

线程池继续存在

执行器的线程池可能会在其父应用程序结束后继续运行。因此,您应该在退出应用程序时始终优雅地关闭执行程序。

ServletContextListener

对于基于Java Servlet 技术的网络应用程序,Servlet spec 定义了一个用于启动和退出网络应用程序的挂钩。

那个钩子是ServletContextListener 接口。该接口需要一对方法,一个由 Servlet 容器在处理 Web 应用程序的第一个传入请求之前调用,另一个在发出最后一个响应后调用。规范要求每个 Servlet 容器(例如 Tomcat)在适当的时间调用这些方法。

在这两种方法中,您可以实例化您的执行器服务,然后将其关闭。

您通过编写一个类来实现接口。您还必须将该类标记到容器中。标记它的最简单方法是使用 @WebListener 注释。

这已经在 Stack Overflow 上讨论过很多次了。所以search for more info 和例子。

JSR 236:JavaTM EE 的并发实用程序

如果使用成熟的Jakarta EE(以前的Java EE)实现(Glassfish、Payara、JBoss 等)而不是单纯的 Servlet 容器(Tomcat、Jetty 等),这项工作会容易得多。这样的服务器将提供JSR 236 的实现来自动处理执行程序的生命周期。所以你不需要实现ServletContextListener

这也已在 Stack Overflow 上多次解决。所以搜索更多信息。

【讨论】:

  • 非常感谢您的帮助!只要有任务要处理,线程池就一直存在吗?在我的负载测试中,看起来父应用程序没有关闭,这很好;否则,如果父应用程序中提供的那些资源不再可用,我可能会看到大量异常。我正在考虑先发送一个信号来停止消费者(休息调用,或者可能是数据库中的配置值更改),然后关闭 Tomcat。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 1970-01-01
  • 1970-01-01
  • 2011-11-11
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
相关资源
最近更新 更多