控制 MDB 中的并发和消耗

Controlling concurrency and consumption in MDB

是否有任何标准方法可以控制 MDB 中的并发和消耗?我能找到的每个建议似乎都是特定于应用程序服务器或资源适配器的(例如 maxSession @ActivationConfigProperty)。

问题™

我们在双节点 JBoss 设置 (EAP 6.3) 上 运行 一些相对繁重的分析作业,并希望并行作业并对并发作业的数量施加上限所以我们不会淹没数据库服务器。作业从 Web 前端开始,只要有空闲的处理槽就应该开始——没有优先级或顺序限制。我们使用消息队列(IBM WMQ,因为政治原因)将“开始分析”消息分发到节点。

当前进度

根据各种建议进行大量调整后,结果证明是 Non-Working Resource-Adapter-Specific Cargo-Cult Misinformation™ :),我 认为 问题已解决通过为 MDB 定义 EJB 池。这确实解决了并发问题,但不幸的是,一个没有空闲 MDB 的节点似乎仍在拉取队列中的消息——这可能导致一个节点未得到充分利用,而另一个节点满载积压。

如果我对 IBM documentation 的理解正确,这种行为应该可以通过 readAheadAllowed 配置选项来控制,但这似乎根本不会影响我的结果。

那么,有没有:

或者,我可能会重新设计架构以使用主题队列,并让每个节点尝试一些类似于 UPDATE Projects SET Status='inprogress' WHERE Id=42 AND Status='inqueue'; 的事情 - 但如果没有必要,我宁愿不去那里,主要是因为更改队列所需的更改请求:)

MQ,实际上是 JMS,被设计和优化为尽可能快地在管道中获取消息。 queue 管理器跟踪每条消息的状态,但并发要求将要求 QMgr 跟踪相互关联的消息状态。 MQ 不会那样做。

在调整 Activation Spec 连接池和事务范围内有一些粒度,但这些都是为了影响服务器的动态行为而不是精确指定。

跨多个消息管理应用程序状态正是 IBM Integration Broker 等 ESB 产品的设计目的。 MQ 是一种仅查看消息 headers 以执行路由和交付的传输,而 ESB 则查看消息关系和内容。除非 JMS 规范定义了并发管理 API,否则 MQ 负责传输而 ESB 负责处理的这种责任划分不太可能改变。

无论是在 ESB 还是 JEE 代码中实现,您所描述的都是 Message Dispatcher Pattern from the Enterprise Integration Patterns 书, 消息传递世界中权威的体系结构参考之一。有几种写法,这取决于对检测的偏好。

标记化

  1. 应用程序实例执行 GET 等待令牌 queue 和同步点。
  2. 收到令牌消息后,应用程序 PUT 将相同的消息返回令牌 queue,再次在同步点下。
  3. 该应用在同步点下的应用程序 queue 上执行 GET 等待。
  4. 收到应用程序消息后,应用程序会对其进行处理,然后根据需要执行 COMMITROLLBACK

应用程序实例在处理应用程序消息之前竞争令牌消息。结果是应用程序消息通常在它们到达时处理得很快,但在负载下最大并发数等于令牌消息的数量。

通常令牌消息是信息性的,例如包含一个随着每次迭代递增的计数器,并且可能包含最后一个写入令牌消息的应用程序的实例信息。这提供了一些关于正在发生的事情的诊断洞察力。在某些情况下,监控应用程序还会侦听令牌 queue 以对该信息进行采样并写入仪表板。在这种情况下,额外的令牌消息将添加到 queue 以说明监控应用程序的 activity。

独立调度程序

  1. 调度程序应用程序在通告目的地 queue 上侦听消息,并在 ACK queue 上侦听确认消息。
  2. 计数器将未完成的消息与调度程序应用程序配置中设置的 {max outstanding message limit} 进行比较。
  3. 如果未完成的消息 < 限制,消息将移至应用程序的输入 queue 并且未完成的消息计数器递增。
  4. 当业务应用程序 GET 发送消息时,它还会将消息发送到调度程序 ACK queue,这两个操作都在同步点下。
  5. 当业务应用程序发出 COMMIT 时,调度程序收到 ACK 并递减未完成消息计数器。

调度程序应用程序可以请求发送消息确认,但这些消息并不总是与业务应用程序成功处理交易相关。如果业务应用程序明确地将 ACK 消息放入与使用的业务消息相同的工作单元中,则结果是坚如磐石的。

我最终使用了我的“或者我可以 [...]”方法 - 将 "start-analysis" 更改为广播消息,并使用SQL 语句中的状态子句。

这是一个简单的解决方案,不会增加很多额外的复杂性,而且在实践中证明效果很好 - 它已经 运行 投入生产大约一年了。