2

私の環境はGlassfish 3.1.2 b23で、JDK 1.7.0_45を搭載したWindows Server 2008上で組み込みモードのOpenMQがバンドルされています(FWIWも同じ結果でLOCALモードを試しました)。

非常に単純な JMS コンポーネントを含むアプリケーションがあります。JMS コンポーネントは、キューに送信され、MDB によって消費されるメッセージを生成するステートレス セッション Bean で構成されます。JMS 接続プールとキューは、Glassfish 管理 UI を使用して作成された管理オブジェクトです。

問題は、メッセージを通常どおりに作成して消費した後、次のエラーが表示されることです。

com.sun.messaging.jms.JMSException: MQRA:DCF:allocation failure:createConnection:Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
    at com.sun.messaging.jms.ra.DirectConnectionFactory._allocateConnection(DirectConnectionFactory.java:548)
    at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:265)
    at com.sun.messaging.jms.ra.DirectConnectionFactory.createConnection(DirectConnectionFactory.java:244)
    at 
    [SNIP]
Caused by: javax.resource.spi.ResourceAllocationException: Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
    at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:307)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:236)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:160)
    at com.sun.messaging.jms.ra.DirectConnectionFactory._allocateConnection(DirectConnectionFactory.java:543)
    ... 99 more
Caused by: com.sun.appserv.connectors.internal.api.PoolingException: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
    at com.sun.enterprise.resource.pool.ConnectionPool.getResource(ConnectionPool.java:418)
    at com.sun.enterprise.resource.pool.PoolManagerImpl.getResourceFromPool(PoolManagerImpl.java:245)
    at com.sun.enterprise.resource.pool.PoolManagerImpl.getResource(PoolManagerImpl.java:170)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.getResource(ConnectionManagerImpl.java:332)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:301)
    ... 103 more 

これは@Asynchronous、ステートレス EJB のメソッドによって開始された自動化されたプロセスが項目のリストをリッピングし、項目ごとにコード パスを呼び出し、それが最終的にこのメッセージ生成に影響を与える場合に発生するようです。一度に 1 つのメッセージしか生成しないわずかに異なるコード パスからメッセージ生成が呼び出される場合、この問題は見られません。

メッセージはミリ秒かかります。生産し、ミリ秒。消費する。接続の最大待機時間は 1 分です。また、最大。同時にメッセージを生成できるスレッドの数は、JMS 接続ファクトリに関連付けられた接続の最大数より (約 2 倍) 少なくなります。

セッションが非 jms-transactional で AUTO-ACK であるプロデューサーは、どのくらいの速さで連続してコールできますか? Producer.send(..) が返されるとすぐに、jms 接続が返されて次のプロデューサで使用できるようになるか、次の .send 呼び出しのために接続が解放されるまでに非常にわずかな遅延時間があると想定します()?

コンシューマーは MDB であり、プロデューサーが使用しているのと同じプールからの JMS 接続も使用していると想定しています (それが唯一の JMS 接続プールであるため)。以下の imqcmd の出力は、アクティブなコンシューマが 1 つあることを示していますが、MDB がプールされているため、コンシューマ側も X # (MDB インスタンスの数) の接続を使用している可能性があることを意味します。プールされた MDB インスタンス?

MDB の例外処理にも興味があります。このパターンは、JavaEE6 サンプルおよび catches/logs Throwable から取得されました。Throwable で mdc.setRollback への呼び出しがないと、JMS 接続がリークしますか?

この問題のデバッグでは、imqcmdコマンドを使用しています。具体的には:

imqcmd query dst -tq -n MyQueue -u admin

---------------------------------------
Destination Name       Destination Type
---------------------------------------
MyQueue    Queue

On the broker specified by:
-------------------------
Host         Primary Port
-------------------------
localhost    7676

Destination Name                      MyQueue
Destination Type                      Queue
Destination State                     RUNNING
Created Administratively              false

Current Number of Messages
    Actual                            0
    Remote                            0
    Held in Transaction               0
Current Message Bytes
    Actual                            0
    Remote                            0
    Held in Transaction               8928
Current Number of Producers           0
Current Number of Active Consumers    1
Current Number of Backup Consumers    0

Max Number of Messages                100000
Max Total Message Bytes               10737418240
Max Bytes per Message                 10485760
Max Number of Producers               100
Max Number of Active Consumers        unlimited (-1)
Max Number of Backup Consumers        0

Limit Behavior                        REJECT_NEWEST
Consumer Flow Limit                   1000
Is Local Destination                  false
Local Delivery is Preferred           false
Use Dead Message Queue                true
XML schema validation enabled         false
XML schema URI List                   -
Reload XML schema on failure          false

Successfully queried the destination. 

プロデューサ: ADetailBean.java

@Stateless
public class ADetailBean.java {

  private transient static final Logger log = Logger.getLogger(ADetailBean.java);

  @Resource(mappedName = "jms/MyConnectionFactory")
  private ConnectionFactory jmsConnectionFactory;

  @Resource(mappedName = "jms/myApp/MyQueue")
  private javax.jms.Queue myQueue;

  @PersistenceContext(unitName = "MyPC")
  private EntityManager entityManager;

  @EJB
  AnotherBean anotherBean;

  public void createAMessage(@NotNull AFile file, AnAction action) {
    ACollection aCol = aCollectionBean.findReqColForTaskColId(file.getCollectionId());
    if (aCol != null) {
        ADetail aDetail = new ADetail(file.getFileNumber(), file.getCollectionId(), file.getMd5(), reqCol.getCollectionId(), action);
        entityManager.persist(aDetail);
       Connection jmsConnection = null;
        try {
            jmsConnection = jmsConnectionFactory.createConnection();
            Session session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer producer = session.createProducer(myQueue);
            AMessage aMessage = new AMessage(file.getName());
            ObjectMessage myMessage = session.createObjectMessage(aMessage);
            producer.send(myMessage);
        } catch (JMSException e) {
            log.error("Error sending message for file number: " +
                    file.getFileNumber() + ", md5: " + file.getMd5() +
                    ", action: " + action + " : " + e.getMessage(), e);
        } finally {
            if (jmsConnection != null) {
                try {
                    jmsConnection.close();
                } catch (Exception ex) {
                    log.warn("Unable to close JMS connection: " + ex.getMessage());
                }
            }
        }
    }

//Other methods in this EJB

}

MDB: MyMessageListener.java

@MessageDriven(mappedName = "jms/myApp/MyQueue", activationConfig = {
        @ActivationConfigProperty(propertyName = "acknowledgeMode",
                propertyValue = "Auto-acknowledge"),
        @ActivationConfigProperty(propertyName = "destinationType",
                propertyValue = "javax.jms.Queue"),
        @ActivationConfigProperty(propertyName = "subscriptionDurability",
                propertyValue = "Durable"),
        @ActivationConfigProperty(propertyName = "clientId",
                propertyValue = "myClient"),
        @ActivationConfigProperty(propertyName = "subscriptionName",
                propertyValue = "mySub")
})
public class MyMessageListener implements MessageListener {

    private static final Logger log = Logger.getLogger(MyMessageListener.class);

    @Resource
    private MessageDrivenContext mdc;

    @PersistenceContext(unitName = "MyPC")
    private EntityManager entityManager;

    @EJB
    ADetailManager aDetailManager;

    @EJB
    ADetailBean aDetailBean;

    @EJB
    AFileBean aFileBean;

    @Override
    public void onMessage(Message message) {
        log.debug("MESSAGE received from the MyQueue queue");
        try {
            if (message instanceof ObjectMessage) {
                if (((ObjectMessage) message).getObject() != null &&
                        ((ObjectMessage) message).getObject() instanceof ACalcMessage) {
                    ACalcMessage msg = (ACalcMessage) ((ObjectMessage) message).getObject();
                    log.debug("MESSAGE BEAN: Received aCalc msg for name: " + msg.getName());
                    //Wait for opportunity to process dupe recalculation for name
                    try {
                        while (!aDetailManager.obtainNameLock(msg.getName())) {
                            log.debug("Waiting to obtain name lock for name: " + msg.getName());
                            Thread.sleep(1000);
                        }

                          aDetail aDetail = aDetailBean.findNext(msg.getName());

                          //Do some processing including JPA queries and entity merges

                          entityManager.remove(aDetail);
                        }
                    } finally {
                        aDetailManager.releaseNameLock(msg.getName());
                    }

                }
            }
        } catch (JMSException e) {
            log.error("Error processing message: " + e.getMessage());
            mdc.setRollbackOnly();
        } catch (Throwable te) {
            log.error("Error processing message: ", te);
        }
    }
}

MyConnectionFactory 管理対象オブジェクトの設定

Pool Name: jms/MyConnectionFactory
JNDI Name: jms/MyConnectionFactory
Resource Type: javax.jms.ConnectionFactory
Status: [X] Enabled

Initial Minimum Pool Size: 8
Maximum Pool Size: 64
Pool Resize Quantity: 2
Idle Timeout: 300 seconds
Max Wait Time: 60000 Milliseconds
Transaction Support: EMPTY  (I assume this means the default level, which is XA?)
Connection Validation: [X] Required 

No Additional Properties

接続プールの詳細タブで:

Validate At Most Once: 0 Seconds
Leak Timeout: 0 Seconds
Leak Reclaim: [ ]
Creation Retry Attempts: 0
Retry Interval: 10 Seconds
Pooling: [X] Enabled
Lazy Association: [ ] Enabled
Lazy Connection Enlistment: [ ] Enabled
Associate with Thread: [ ] Enabled
Match Connections: [X] Enabled
Max Connection Usage: 0

Queue 管理対象オブジェクトの設定は次のようになります。

JNDI Name: jms/myApp/MyQueue
Resource Adapter: jmsra
Resource Type: javax.jms.Queue
Class Name: com.sun.messaging.Queue
Status: [X] Enabled

Additional Properties:
Name   |  Value
----     -------
Name      MyQueue
4

0 に答える 0