我偶尔会在几个不同的消息驱动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
答案 0 :(得分:10)
在做了一些研究之后,我发现了一个令人满意的解释,这个EJBException。
MessageDrivenBeans有一个实例池。当一批JMS消息以预取的数量传递到MDB时,每个消息都会从该池中分配一个实例,并通过onMessage
函数传递给该实例。
关于池如何工作的一点:在JBoss 5.1.0中,默认情况下通过JBoss AOP配置诸如MDB和SessionBeans之类的池,特别是部署目录中标题为“ejb3-interceptors-aop.xml”的文件。此文件为与其域匹配的任何类创建拦截器绑定和默认注释。对于Message Driven 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时间高于正常时保持警报指示。
答案 1 :(得分:0)