防止消息驱动 Bean 消耗消息[或]处理 Java EE 中的数据库连接失败

发布于 2025-01-06 02:25:12 字数 1336 浏览 4 评论 0原文

场景

我们将 Java EE 应用程序作为传统的面向数据库的应用程序和实时 Java SE 应用程序之间的一个层来提供,该应用程序管理物理设备以阻止或授予访问权限(例如电子门)。

Java EE 应用程序对于客户来说是本地的。他管理本地网络中的应用程序服务器。

Java SE 所做的一切都基于其内部内存。该内存由 Java EE 应用程序通过 JMS 消息更新。

Java EE 应用程序从 Java SE 应用程序接收消息,这些消息是关键任务,它们不能丢失。

一旦 Java EE 收到这些消息,它就会将其保存到数据库中。

我们的大部分客户都拥有一台数据库计算机(非集群、非 HA 等)。

我们的应用程序应该优雅地处理数据库连接失败,而且确实如此。但这正在成为我们设计的真正负担。

每个新线程(MDB、EJB Timer 或 WebService)都通过调用临时 Singleton 中的数据库检查(不是 @Singleton,因为我们使用的是 EJB 3.0) 。如果数据库连接关闭,单例​​会锁定(因此所有其他线程将等待直到锁定被释放),停止所有计时器的运行,并继续每五秒尝试一次数据库连接。如果在此过程中传递 JMS 消息,MDB 将持有 Singleton 的锁,因此该消息不会被消耗或丢失。

一旦数据库连接恢复,锁就会被释放,并且计时器会再次启动。 MDB 可以自由地继续处理它们的消息。

解决方案的架构如下所示[抱歉,mspaint 绘图不佳]:

Solution's Architecture

为什么?

我们之所以采用这种基于锁的方法,是因为在我们所做的每次测试中,抛出异常或回滚 MDB 上的事务都会导致消息立即重新传递。重新投递计数的汇总速度非常快,并且消息最终进入死消息队列 (DMQ)。

我们需要在数据库连接建立后立即处理此消息,因此不能将其重定向到 DMQ。

梦想

我们梦想一个世界,在数据库连接建立之前可以停止消费消息或处理任何其他请求。

一旦我们检测到数据库故障,整个应用程序就会关闭并专注于一件小事:了解数据库何时备份。一旦我们获得了这些信息,我们就可以让整个应用程序再次运行。

问题

是否可以对 Java EE 容器进行更多控制?就像随意停止或启动带注释的 MDB 一样。

或者,是否有可能以更优雅的方式防止数据库故障? (考虑到 JMS 消息是关键任务。)

Scenario

We deliver a Java EE application as a layer between a legacy database-oriented application and a real-time Java SE application that manages physical devices to block or to grant access (like eletronic doors).

The Java EE application is local to the customer. He manages the application server in his local network.

Everything the Java SE do is based on it's internal memory. This memory is updated by the Java EE application thru JMS Messages.

The Java EE application receives messages from the Java SE applications, these messages are mission-critical, i.e. they can not be lost.

Once the Java EE receives these messages it persists it to the database.

The major slice of our customers have a single database machine (not clustered, not HA, etc.).

Our application should handle database connection failures gracefully, and it does. But this is becoming a really burden to our design.

Every new thread (MDB, EJB Timer or WebService) starts by invoking a database check in an ad-hoc Singleton (i.e. not a @Singleton as we are using EJB 3.0). If database connection is down, the Singleton locks up (so all other threads waits until the lock is released), stops all timers running, and keep trying a database connection every five seconds. If a JMS message is delivered during this process, the MDB will be held to the Singleton's lock, so the message will not be consumed nor lost.

Once the database connection is back up, the lock is released and the timers are started again. The MDBs are free to continue processing their messages.

The architecture of the solutions looks like that [sorry for the poor mspaint drawing]:

Solution's Architecture

Why?

We are doing this lock-based approach because on every tests we did, throwing an exception or rolling back the transaction at the MDB causes the message to be redelivered immediately. The redelivery count sums up really quick and the message ends up in the dead-message queue (DMQ).

We need this message to be processed as soon as the database connection is up, so it can not be redirected to the DMQ.

Dream

We dream a world where it is possible to stop consuming messages or processing any other requests until the database connection is up.

Once we detect the database failure, the entire application shutdown and focus in one little thing: to get to know when the database is back up. Once we have this information, we get the entire application to work again.

Question

Is it possible to have more control over the Java EE container? Like stopping or starting an annotated MDB at will.

Or, is it possible to be database-failure-proof in a more elegant way? (Considering the JMS Messages are mission-critical.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

宫墨修音 2025-01-13 02:25:12

您的数据库通常会停机多长时间?

不能在 MDB 内部使用某种信号系统吗?同步某个外部对象,并且仅在该对象允许您这样做时才处理当前消息?

我能想到的最简单的例子是监视器,您的 MDB 可以根据它进行同步。监视器监视数据库,并在失去与数据库联系的能力时立即将 PERMIT_PROCESSING 设置为 false。

但它并不优雅。

How long is your database typically down?

Can you not use some sort of signalling system inside the MDB? Synchronize on some external object, and only process the current message if that object clears you to do so?

The simplest example I can think of for this is a Monitor, against which your MDBs synchronize. The Monitor monitors the Database, and sets PERMIT_PROCESSING false as soon as it loses the ability to contact the database.

It's not elegant though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文