EJBException:无法获取池信号量

问题描述 投票:0回答:2

我偶尔会在几个不同的消息驱动 bean 中遇到以下 EJB 异常:

javax.ejb.EJBException: Failed to acquire the pool semaphore, strictTimeout=10000

此行为与特定数据库出现问题的情况密切相关,从而增加了 MDB 的 onMessage 函数所花费的时间。消息由 ActiveMQ 代理(版本 5.4.2)传递。 MDB 上的预取为 2000(20 个会话 x 每个会话 100 条消息)。

我的问题是一个一般性问题。这里究竟发生了什么?我知道如果 Bean 池中没有实例来处理消息,则已传递到运行 MDB 的服务器的消息将在 10 秒后超时,但是该消息最初是如何传递到服务器的呢?到目前为止,我的假设是 MDB 仅当不再有任何消息需要处理时才向代理请求一定数量的消息。他们只是在服务器端“桶”中等待太久了吗?

还有其他人遇到过这种情况吗?关于调整预取/信号量超时的建议?

编辑:忘了提及我正在使用 JBoss AS 5.1.0

java jakarta-ee jboss ejb-3.0
2个回答
12
投票

经过一些研究,我找到了对此 EJBException 的令人满意的解释。

MessageDrivenBeans 有一个实例池。当一批 JMS 消息以预取的数量传递到 MDB 时,每个消息都会从该池中分配一个实例,并通过

onMessage
函数传递到该实例。

关于池如何工作的一些信息:在 JBoss 5.1.0 中,池 bean(例如 MDB 和 SessionBean)默认通过 JBoss AOP 配置,特别是部署目录中标题为“ejb3-interceptors-aop.xml”的文件。该文件为任何与其域匹配的类创建拦截器绑定和默认注释。对于消息驱动 Bean 域,除其他事项外,还有

org.jboss.ejb3.annotation.Pool
注释:

<annotation expr="class(*) AND !class(@org.jboss.ejb3.annotation.Pool)">
     @org.jboss.ejb3.annotation.Pool (value="StrictMaxPool", maxSize=15, timeout=10000)
</annotation>

该注释的参数描述于here

问题就在这里。如果消息预取超过此池的 maxSize(对于高吞吐量消息传递应用程序通常会如此),您必然会有等待 MDB 实例的消息。 如果从消息传递到调用 onMessage 的时间超过任何消息的池超时,则会抛出 EJBException。 对于消息分发的前几次迭代,这可能不是问题,但如果预取较大且时间较长平均 onMessage 时间,接近队列末尾的消息将开始失败。

一些快速代数表明,粗略地说,当

timeout < (prefetch x onMessageTime) / maxSize

这假设消息是即时分发的,并且每个 onMessage 花费相同的时间,但应该可以让您粗略估计您是否超出范围。

这个问题的解决方案比较主观。简单地增加超时是一个天真的选择,因为它会掩盖消息位于应用程序服务器而不是队列上的事实。鉴于 onMessage 时间在某种程度上是固定的,如果资源允许,减少预取很可能是一个不错的选择,增加池大小也是一个不错的选择。在调整此过程中,除了大幅减少预取和增加 maxSize 之外,我还减少了超时,以使消息在队列中保留更长时间,同时保持 onMessage 时间高于正常时间时的警报指示器。


0
投票

jpredham 所说的是正确的。另请检查是否

“strictMaximumSize”设置为 true

这可能会导致 https://issues.jboss.org/browse/JBAS-1599

© www.soinside.com 2019 - 2024. All rights reserved.