2

My acitvemq server always print error below :

2014-07-12 16:14:27,820 | ERROR | Could not accept connection : 
org.apache.activemq.transport.tcp.ExceededMaximumConnectionsException:
Exceeded the maximum number of allowed client connections.
See the 'maximumConnections' property on the TCP transport configuration URI 
in the ActiveMQ configuration file (e.g., activemq.xml) 
| org.apache.activemq.broker.TransportConnector 
| ActiveMQ Transport Server Thread Handler:
 tcp://0.0.0.0:61616?maximumConnections=1000&wireformat.maxFrameSize=104857600

When I restart the server it will be ok. But after a few days the error come out again. I don't why the connections always increase to 1000.

My server config:

<!-- activeMQ -->
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL" value="${jms.brokerURL}"></property>
</bean>

<!-- Spring Caching  -->
<bean id="cachingConnectionFactory"
    class="org.springframework.jms.connection.CachingConnectionFactory">
    <property name="targetConnectionFactory" ref="jmsConnectionFactory" />
    <property name="sessionCacheSize" value="10" />
</bean>

<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="cachingConnectionFactory" />
    <property name="explicitQosEnabled" value="true" />
    <property name="priority" value="4" />
</bean>

<bean id="scoreQueue" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="SCORE" />
</bean>

<bean id="scoreMessage" class="com.tt.score.mq.server.ScoreMessage"></bean>

<bean id="scoreListener"
    class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref="jmsConnectionFactory"></property>
    <property name="destination" ref="scoreQueue"></property>
    <property name="messageListener" ref="scoreMessage"></property>
    <property name="concurrentConsumers" value="10" />
    <property name="maxConcurrentConsumers" value="100" />
    <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE" />
</bean>

My client config xml:

<!-- Spring Caching -->
<bean id="cachingConnectionFactory"
    class="org.springframework.jms.connection.CachingConnectionFactory">
    <property name="targetConnectionFactory" ref="jmsConnectionFactory" />
    <property name="sessionCacheSize" value="10" />
</bean>

<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="cachingConnectionFactory" />
    <property name="explicitQosEnabled" value="true" />
    <property name="priority" value="4" />
</bean>

<bean id="messageProducer" class="com.tt.score.mq.client.MessageProducer">
    <property name="jmsTemplate" ref="jmsTemplate" />
    <property name="scoreQueue" ref="scoreQueue" />
</bean>

<bean id="scoreQueue" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="SCORE" />
</bean>

Other info:

  • acitvemq server : 5.8.0
  • client acitvemq : 5.4.2
  • spring : 3.0.7
  • spring-jms : 3.0.7

We use transactionManager so the DefaultMessageListenerContainer's cachelevel will be set to none.

---update add dao config----------------------------------

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"><value>${jdbc.driverClass}</value></property>
        <property name="username"><value>${jdbc.user}</value></property>
        <property name="url"><value>${jdbc.jdbcUrl}</value></property>
        <property name="password">
            <bean class="com.tongbanjie.commons.util.EncryptDBPasswordFactory">
                <property name="password" value="${jdbc.password}" />
            </bean>
        </property>
        <property name="maxActive"><value>${jdbc.maxActive}</value></property>
        <property name="initialSize"><value>${jdbc.initialSize}</value></property>
        <property name="maxWait"><value>60000</value></property>
        <property name="maxIdle"><value>${jdbc.maxIdle}</value></property>
        <property name="minIdle"><value>5</value></property>
        <property name="removeAbandoned"><value>true</value></property>
        <property name="removeAbandonedTimeout"><value>180</value></property>
        <property name="timeBetweenEvictionRunsMillis"><value>60000</value></property>
        <property name="minEvictableIdleTimeMillis"><value>1800000</value></property>
        <property name="defaultAutoCommit" value="false" />
        <property name="connectionProperties">
            <value>bigStringTryClob=true;clientEncoding=UTF-8;defaultRowPrefetch=50;serverEncoding=ISO-8859-1</value>
        </property>
    </bean>

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />


    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource">
            <ref bean="dataSource"/>
        </property>
    </bean>

    <!-- myBatis -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:META-INF/mybatis/score-configuration.xml" />
        <property name="mapperLocations" value="classpath*:META-INF/mybatis/mapper/*.xml" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="commonSqlSessionDao" abstract="true">
        <property name="sqlSessionFactory">
            <ref bean="sqlSessionFactory" />
        </property>
    </bean>

-----post the code that we how to use the template now

the jmsTemplate wrapped in a class

public class MessageProducer {

    private JmsTemplate   jmsTemplate;
    private ActiveMQQueue scoreQueue;

    public void sendScoreQueue(Map<String, String> userMap) {
        sendMessage(this.scoreQueue, userMap);
    }

    private void sendMessage(Destination destination, final Map<String, String> map) {
        this.jmsTemplate.send(destination, new MessageCreator() {

            public Message createMessage(Session session) throws JMSException {
                MapMessage message = session.createMapMessage();
                for (String key : map.keySet()) {
                    message.setStringProperty(key, (String) map.get(key));
                }
                return message;
            }
        });
    }
}

And we use a thead to send call the MessageProducer class's sendScoreQueue method. As follows:

 //the code is old and ugly.that is the original position we call the mq.
 ThreadUtils.execute(new Thread(new SendMsgThread(dycc, ScoreMQSendType.SEND_TYPE_SCORE)));

///

public class ThreadUtils {

    protected static ThreadPoolExecutor executor = null;
    public static Properties            Props    = null;

    public static void execute(Thread thread) {
        executor.execute(thread);
    }

  static {
        if (executor == null) 
            Integer corePoolSize = 5;
            Integer maximumPoolSize = 10;
            Integer keepAliveTime = 3000;
            executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MINUTES,
                                              new LinkedBlockingQueue());
    }
}

public class SendMsgThread implements Runnable {

    private Log                    log      = LogFactory.getLog(SendMsgThread.class);

    private Map<String, String>    map;
    private String                 type;

    private static MessageProducer producer = null;

    public SendMsgThread(Map<String, String> map, String type){
        this.type = type;
        this.map = map;
    }

    public void run() {
        try {
            if(type.equals(ScoreMQSendType.SEND_TYPE_SCORE) || type.equals(ScoreMQSendType.SEND_TYPE_REGISTER)) {
                producer.sendMessage(map);
            }
        } catch (Exception e) {
            this.log.error("sendMsgThread sendScoreQueue error.", e);
        }
    }

 static {
        if (producer == null) producer = 
(MessageProducer )SpringContextHolder.getBean(MessageProducer .class);
    }
}
FishGel
  • 1,100
  • 2
  • 16
  • 27
  • You say this: "We use transactionManager so the DefaultMessageListenerContainer's cachelevel will be set to none". Your tx manager is not a JmsTransactionManager and DMLC doesn't have its property transactionManager set. – Andrei Stefan Aug 04 '14 at 10:08
  • Are you using `jmsConnectionFactory` somewhere else in your app? Also, how do you use the `jmsTemplate`, can you post some code? – Andrei Stefan Aug 04 '14 at 22:03
  • @AndreiStefan i post the code that how we use the jmsTempate. And we only use jmsConnectionFactory in mq. – FishGel Aug 05 '14 at 01:11
  • What is the source code of `MessageSender` from `SendMsgThread`, because I see is not the same with `MessageProducer`? – Andrei Stefan Aug 05 '14 at 05:46
  • @AndreiStefan Sorry, the svn trunk code was using MessageProducer from SendMsgThread. MessageSender is a new class.We just use it test now. – FishGel Aug 05 '14 at 06:21
  • How do initialize `MessageProducer` in `SendMsgThread`? I see it's set to `null` initially, but afterwards? – Andrei Stefan Aug 05 '14 at 06:43
  • @AndreiStefan use spring to initialize MessageProducer .Please take a look at client config xml. And get the bean by a util class. eg:applicationContext.getBean(MessageProducer.class) – FishGel Aug 05 '14 at 07:00
  • I'm trying to test your scenario, so if you can provide the exact code you are using, it's better than me assuming you are using the code in this way or another. I see the MessageProducer in xml config and I see it has a `jmsTemplate`. I was asking how do you initialize `MessageProducer` in `SendMsgThread`? Show me the code that does this. – Andrei Stefan Aug 05 '14 at 07:04
  • I've tested this but I cannot make it fail. Basically, the client uses just one connection to the broker (thanks to `CachingConnectionFactory`), no matter how many Threads are used to send the messages. My client is a simple `public static void main()` class. I only get this exception if I start that many clients so that each uses one connection and the number of connections is exhausted. – Andrei Stefan Aug 05 '14 at 08:09
  • What kind of application is your client app? (web-app, standalone, batch processing etc) – Andrei Stefan Aug 05 '14 at 08:10
  • @AndreiStefan it is web-app – FishGel Aug 05 '14 at 10:52
  • Then there might be something leaking connections. As I said, I tested your code with ActiveMQ and the Spring versions you mentioned and I don't see this issue. Maybe you are using this bean - `jmsConnectionFactory` (the uncached connection factory) - somewhere else in other classes? Used with `CachingConnectionFactory` there shouldn't be any problems. – Andrei Stefan Aug 05 '14 at 11:50
  • @AndreiStefan So do you know how to see the leaking connections? Any tool or monitor or command ? – FishGel Aug 06 '14 at 03:08
  • ActiveMQ has its own web interface to access and check connections, queues, topics etc, but I don't think you can tell what's with each connection. Usually, the web interface can be accessed at this link: [http://localhost:8161/](http://localhost:8161/). You can, also, enable DEBUG logging in your app (DEBUG logging enablement depends on your logging mechanism) and check the logs for connections created messages. This is not a well defined procedure, it all depends on the characteristics of each application. – Andrei Stefan Aug 06 '14 at 05:28
  • Any luck with the logs? – Andrei Stefan Aug 06 '14 at 22:06
  • Can you share those logs somehow? I can take a look. – Andrei Stefan Aug 07 '14 at 11:24
  • I changed it to CachingConnectionFactory. @AndreiStefan – FishGel Aug 08 '14 at 08:45

2 Answers2

1

For this scenario you should use PooledConnectionFactory instead of cachingConnectionFactory. More information can be found here.The difference between them can be found here

Community
  • 1
  • 1
Sachin Janani
  • 1,310
  • 1
  • 17
  • 33
0

I had the same problem recurring with same error, and the solution was obtained as a result of trial and error, use jms call to concurrent consumers max to 101, instead of 100, and see if results repeat, adding more to the value results the code executed further on debugger, you will reach a value when code works , Also the solution appears to be using a connection pool factory.

Try this, hope it works, rest my implementation is same as yours in bean file

Pavan Kate
  • 84
  • 1
  • 8