【问题标题】:JMS connection with queue createConnection fails after some requests一些请求后,与队列 createConnection 的 JMS 连接失败
【发布时间】:2014-04-04 21:11:36
【问题描述】:

我有一个无状态的 ejb,我与 jms 队列建立连接并向它发送消息。
我这样做的部分代码:

@Resource(mappedName = "jms/abcd")
private ConnectionFactory abcd;
@Resource(mappedName = "jms/xyz")
private Queue xyz;
 @Override
    public void saveCounter(String protocolName, String serialNumber, String counterName,CounterAction action)
    {
        Connection connection = null;
        Session session=null;
        try
        {
            connection = abcd.createConnection();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer producer = session.createProducer(xyz);

            Message message = session.createMessage();
            message.setStringProperty("serialNumber", serialNumber);
            producer.send(message);
        }
        catch (Exception e)
        {
            logger.error("Sending message to queue", e);
        }
        finally
        {
            try
            {
                if(session!=null){
                    session.close();    
                }
                if (connection != null)
                {
                    connection.close();
                }
            }
            catch (JMSException e)
            {
                logger.warn(e);
            }
        }

    }

我正在使用 MDB。消费代码如图:

 @MessageDriven(name = "XXMessageDrivenBean", activationConfig = {
 @ActivationConfigProperty(propertyName = "destinationType",
 propertyValue = "javax.jms.Queue") }, mappedName = "jms/xyz")

 public class CounterMessageDrivenBean {

 ...

     @Override
     public void onMessage(Message message){

        System.out.println("got message: " + message);
            log.debug("got message: " + message);

     }

     .....
 }

我通过对这个 ejb 进行依赖注入并调用它的方法来使用来自其他 ejb 的这个 ejb 的功能。它适用于某些请求

但是当我尝试对我的代码进行负载测试时,在像数千次这样的请求之后,代码的 crateConnection 部分开始失败并出现异常:

Thread 64518 "httpWorkerThread-38080-1": (state = BLOCKED)
    at com.sun.enterprise.resource.AbstractResourcePool.getResourceFromPool(AbstractResourcePool.java:788)
    at com.sun.enterprise.resource.AbstractResourcePool.getUnenlistedResource(AbstractResourcePool.java:682)
    at com.sun.enterprise.resource.AbstractResourcePool.internalGetResource(AbstractResourcePool.java:624)
    at com.sun.enterprise.resource.AbstractResourcePool.getResource(AbstractResourcePool.java:470)
    at com.sun.enterprise.resource.PoolManagerImpl.getResourceFromPool(PoolManagerImpl.java:248)
    at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:176)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:323)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:245)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:175)
    at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:168)
    at com.sun.messaging.jms.ra.ConnectionFactoryAdapter._allocateConnection(ConnectionFactoryAdapter.java:179)
    at com.sun.messaging.jms.ra.ConnectionFactoryAdapter.createConnection(ConnectionFactoryAdapter.java:166)
    at com.sun.messaging.jms.ra.ConnectionFactoryAdapter.createConnection(ConnectionFactoryAdapter.java:148)

在上面显示的代码中:saveCounter:createConnection

请帮助我理解为什么我的代码开始失败。 我是 glassfish 应用服务器。

提前致谢

【问题讨论】:

  • 在对代码进行更多调试后,我发现在创建会话时内存不足。我认为生产者无法与经纪人建立联系。

标签: glassfish jms ejb-3.0


【解决方案1】:

喜满洲,

首先想到的是为什么要使用无状态 ejb 而不是 MDB。

您的代码的负面影响是您正在处理 JMS 连接的打开和关闭。

如果您使用的是 MDB,则 JMS 连接处理由 MDB 本身处理。 另外,您将获得一个打开的 JMS 连接池,可以轻松地对其进行调整。 因此,您不应遇到与您报告的相同的问题。

【讨论】:

  • 您好,我正在使用 mbd,我在我的问题中添加了消费者代码。从那会更清楚
【解决方案2】:

您也可以尝试关闭 MessageProducer 对象。您的代码看起来非常适合关闭会话和连接,但您实际上并没有关闭生产者。 MessageProducer javadoc 建议调用 close()。您可以在producer.send(message); 之后立即拨打producer.close();

另外,关于 finally 块的小建议 - 如果 session.close() 抛出异常,您将无法关闭连接。您也可以尝试将该调用包装在 try/catch 块中:

 finally
    {
        try
        {
            if(session!=null){
               try {
                  session.close();    
                } catch(JMSException e) { }
            }
            if (connection != null)
            {
                connection.close();
            }
        }
        catch (JMSException e)
        {
            logger.warn(e);
        }
    }

希望这会有所帮助!

【讨论】:

  • 您好,当您关闭会话时,生产者和消费者会自动关闭。所以不需要单独关闭生产者。关闭会话就足够了。 docs.oracle.com/javaee/1.4/api/javax/jms/Session.html#close()
  • 这就是规范所说的,然后您需要查看所提供的 JMS 的实际实现代码,以查看他们的实现是否在他们的 Session.close() 方法中实际处理了这种情况。
【解决方案3】:

我每天使用非常相似的代码来处理 200,000-300,000 trx 并且没有遇到任何问题。我在这里分享代码: ...

Connection connection;
Session session = null;
MessageProducer messageProducer;
try {
    connection = connectionFactory.createConnection();

    session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    messageProducer = session.createProducer(queue);
    TextMessage message = session.createTextMessage();

    for (String msgKey : messages.keySet()) {

        message.setText(messages.get(msgKey));
        // logger.debug("Sending message to Queue: "
        // + message.getText());
        messageProducer.send(message);
    }
} catch (JMSException e) {
    logger.info("Error " + e);
    e.printStackTrace();
}

...

我可以从您的代码中看到的唯一区别是我在 try 块之外声明 MessageProducer。试试看有没有区别。

【讨论】:

  • 嗨,我的操作速度是每小时缺 1 次(意味着每天缺 24 次),我认为使用 openMQ 的 jms 无法支持这么多负载
  • 很高兴知道。我使用过 WebSphere 和 WebLogic,从未遇到过负载问题。
【解决方案4】:

我发现关闭连接也会关闭会话和生产者。所以不存在开放资源相关的问题。

我发现的问题是,我们在 jms 上施加了过多的负载,就像每小时缺少 1 个一样。所以 jms 服务无法处理这么大的负载。

【讨论】:

    猜你喜欢
    • 2017-11-07
    • 1970-01-01
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多