views:

580

answers:

1

Since I've struggled a lot with this problem, I am posting my solution. Disabling jmx in an activemq network of brokers removes race conditions about the registration of the jmx connector. When starting multiple activemq servers on the same machine:

Failed to start jmx connector: Cannot bind to URL [rmi://localhost:1099/jmxrmi]: javax.naming.NameAlreadyBoundException: jmxrmi [Root exception is java.rmi.AlreadyBoundException: jmxrmi]

Another problem with this is, that even if you don't cause a race condition, this exception can still occur. Even when starting one broker after another while waiting for them to initialize properly in between. If one process is run by root as the first instance and the other as a normal user, somehow the user process tries to register its own jmx connector, though there already is one.

Or another exception which happens when the broker that successfully registered the jmx connector goes down:

Failed to start jmx connector: Cannot bind to URL [rmi://localhost:1099/jmxrmi]: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: localhost; nested exception is: java.net.ConnectException: Connection refused]

Those exceptions cause the network of brokers to stop working, or to not work at all. The trick to disable jmx was, that jmx had to be disabled in the connectionfactory aswell. The documentation http://activemq.apache.org/jmx.html does not say that this is needed explicitly. So I had to struggle for 2 days until I found the solution:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.3.1.xsd"&gt;

<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
    <constructor-arg ref="connectionFactory" />
</bean>

<!-- Caching, sodass das jms template überhaupt nutzbar ist in sachen performance -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
    <constructor-arg ref="amqConnectionFactory" />
    <property name="exceptionListener" ref="jmsExceptionListener" />
    <property name="sessionCacheSize" value="1" />
</bean>

<!--
    Jeder Client verbindet sich mit seinem eigenen broker, broker sind untereinander vernetzt. Nur wenn hier
    nochmals jmx deaktiviert wird, bleibt es auch deaktiviert...
-->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="vm://broker:default?useJmx=false" />

<!--
    Broker suchen sich einen eigenen Port und sind gegenseitig verbunden, ergeben dadurch ein Grid. Dies zwar etwas
    langsamer, aber dafür ausfallsicherer. Siehe http://activemq.apache.org/networks-of-brokers.html
-->
<amq:broker useJmx="false" persistent="false">
    <!-- Wird benötigt um JMX endgültig zu deaktivieren -->
    <amq:managementContext>
        <amq:managementContext connectorHost="localhost" createConnector="false" />
    </amq:managementContext>
    <!-- Nun die normale Konfiguration für Network of Brokers -->
    <amq:networkConnectors>
        <amq:networkConnector networkTTL="1" duplex="true" dynamicOnly="true" uri="multicast://default" />
    </amq:networkConnectors>
    <amq:persistenceAdapter>
        <amq:memoryPersistenceAdapter />
    </amq:persistenceAdapter>
    <amq:transportConnectors>
        <amq:transportConnector uri="tcp://localhost:0" discoveryUri="multicast://default" />
    </amq:transportConnectors>
</amq:broker>

With this, there is no need to specify -Dcom.sun.management.jmxremote=false for the jvm. Which somehow also didn't work for me, because the connectionfactory started the jmx connector.

Edit:

Tonys answer brought me to rethinking the configuration and I found a simplified version which works aswell.

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.3.2.xsd"&gt;

<!-- Caching, sodass das jms template überhaupt nutzbar ist in sachen performance -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
    <constructor-arg ref="amqConnectionFactory" />
    <property name="exceptionListener" ref="jmsExceptionListener" />
    <property name="sessionCacheSize" value="1" />
</bean>

<!--
    Jeder Client verbindet sich mit seinem eigenen broker, broker sind untereinander vernetzt. Nur wenn hier nochmals jmx
    deaktiviert wird, bleibt es auch deaktiviert...
-->
<amq:connectionFactory id="amqConnectionFactory" brokerURL="vm://default?broker.persistent=false" />

<!--
    Broker suchen sich einen eigenen Port und sind gegenseitig verbunden, ergeben dadurch ein Grid. Dies zwar etwas
    langsamer, aber dafür ausfallsicherer. Siehe http://activemq.apache.org/networks-of-brokers.html
-->
<amq:broker useJmx="false" persistent="false">
    <amq:networkConnectors>
        <amq:networkConnector networkTTL="1" conduitSubscriptions="true" duplex="true" dynamicOnly="true"
            uri="multicast://default" />
    </amq:networkConnectors>
    <amq:persistenceAdapter>
        <amq:memoryPersistenceAdapter />
    </amq:persistenceAdapter>
    <amq:transportConnectors>
        <amq:transportConnector uri="tcp://localhost:0" discoveryUri="multicast://default" />
    </amq:transportConnectors>
</amq:broker>

A: 

This is really great! When I deploy my application on my customer's server, NameAlreadyBoundException occurred. I hope disable JMX will solve this problem. One thing I don't quite understand is since you defined brokerURL using VM transport, why transportConnector using tcp transport ?

ZZcat
a network of brokers is build of vm instances that connect to their own broker, thats why the vm connection is done to the broker.the brokers between themselves have to establish tcp connections, so they can build a network and relay the messages that they receive via their own vm transport.
subes
I've noticed that the amqConnectionFactory creates its own broker. you can fix that by specifying <amq:connectionFactory id="amqConnectionFactory" brokerURL="vm://default" /> instead of the old one. I'ma update the post i made aswell.
subes