Skip to content
Laurent Bovet edited this page May 9, 2015 · 3 revisions

Principle

We reuse the standard remoting capability of JMX. Each node will export its mbean server with a RMI connector.

Each node has a JMiniX console configured with a composite server connection provider managed by a ClusterManager.

This manager is based on JGroups, a solid multicast-based clustering toolkit to discover and maintain the list of running nodes and reflect the state of the cluster in the console.

Thus, all running nodes serve the console and all nodes appear in the server list. As JMiniX is RESTfully stateless, there is no session issue.

Configuration

We provide here an example of Spring configuration although Spring is not necessary to JMiniX and its clustering support. If you don't use Spring, just deduce the structure from the examples and use the RMI and JMX support included in the JDK directly instead of the convenience tools provided by Spring.

RMI Registry

To export your mbean server, you will need a RMI registry. Application Servers generally provide their own.

With spring, you can create or reuse a registry with:

    <bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
        <property name="port" value="1099" />
    </bean>

Cluster Manager

This is the server connection provider that will contain one entry per node.

    <bean id="serverConnectionProvider" class="org.jminix.server.ConfigurableServerConnectionProvider"/> 

The cluster manager is an active component keeping the server connections up-to-date according to the state of the cluster.

    <bean id="clusterManager" class="org.jminix.server.cluster.RmiClusterManager" 
        init-method="start" destroy-method="close" depends-on="registry">
        <property name="provider" ref="serverConnectionProvider"/>
        <property name="clusterName" value="jminix-test"/>
        <property name="credentialsHolder" ref="jmxAuthenticator"/>     
    </bean>

clusterName identifies your JGroups cluster uniquely.

Exporting the MBean Server with RMI

The following configuration creates a RMI connector for the local mbean server. The service URL that will be multicasted to other nodes is maintained in the cluster manager. By default, it locates the mbean server automatically, but you can inject your own in the property server.

    <bean class="org.springframework.jmx.support.ConnectorServerFactoryBean">
        <property name="objectName" value="connector:name=rmi" />
        <property name="serviceUrl">
            <util:property-path path="clusterManager.localUrl"/>
        </property> 
        <property name="environment">
            <map>
                <entry key="jmx.remote.authenticator" value-ref="jmxAuthenticator"/>
                <entry key="jmx.remote.jndi.rebind" value="true"/>
            </map>
        </property>     
    </bean>

Security

You don't want anyone in the network to have access to the exported mbean servers and JGroups cluster. Both are protected with these credentials.

        <bean id="jmxAuthenticator" class="org.jminix.server.SimpleJMXAuthenticator">
            <property name="username" value="jminix"/>
            <property name="password" value="Hi238SDA.252"/>
        </bean>

For more security, choose your own credentials :)

Multiple Nodes on the same Host

By default, the node name is the host name. If you want to run multiple nodes on the same machine, you will need to set the property nodeName of the cluster manager.

For testing purpose, in order to avoid a different configuration file per node, one can use the following configuration to use a unique ID generated by the JVM:

    <bean id="clusterManager" class="org.jminix.server.RmiClusterManager" 
        init-method="start" destroy-method="close" depends-on="registry">
        <property name="nodeName" ref="vmid-string"/>
        <property name="provider" ref="serverConnectionProvider"/>
        <property name="urlPattern" value="service:jmx:rmi://{0}/jndi/rmi://{0}:{1,number,#}/rmi{2}"/>
        <property name="clusterName" value="rmi-client-test"/>
    </bean>

    <bean id="vmid-string" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetClass" value="java.lang.Math"/>
        <property name="targetMethod" value="abs"/> 
        <property name="arguments">
        <list>
            <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
                <property name="targetObject">
                    <bean id="vmid" class="java.rmi.dgc.VMID"/>
                </property>
                <property name="targetMethod" value="hashCode"/>
            </bean>
        </list>
        </property>
    </bean>

Full Configuration Example

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
           
	<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
		<property name="port" value="1099" />
	</bean>

	<bean id="serverConnectionProvider" class="org.jminix.server.ConfigurableServerConnectionProvider"/> 
	
	<bean id="jmxAuthenticator" class="org.jminix.server.SimpleJMXAuthenticator">
		<property name="username" value="it"/>
		<property name="password" value="pw"/>
	</bean>
	
	<bean id="clusterManager" class="org.jminix.server.cluster.RmiClusterManager" 
		init-method="start" destroy-method="close" depends-on="registry">
		<property name="provider" ref="serverConnectionProvider"/>
		<property name="clusterName" value="jminix-test"/>
		<property name="credentialsHolder" ref="jmxAuthenticator"/>		
	</bean>

	<bean class="org.springframework.jmx.support.ConnectorServerFactoryBean">
		<property name="objectName" value="connector:name=rmi" />
		<property name="serviceUrl">
			<util:property-path path="clusterManager.localUrl"/>
		</property>	
		<property name="environment">
			<map>
				<entry key="jmx.remote.authenticator" value-ref="jmxAuthenticator"/>
				<entry key="jmx.remote.jndi.rebind" value="true"/>
			</map>
		</property>		
	</bean>
	
	<!-- Configuration example allowing several nodes on the same host -->
	<!-- 
	
	<bean id="clusterManager" class="org.jminix.server.RmiClusterManager" 
		init-method="start" destroy-method="close" depends-on="registry">
		<property name="nodeName" ref="vmid-string"/>
		<property name="provider" ref="serverConnectionProvider"/>
		<property name="urlPattern" value="service:jmx:rmi://{0}/jndi/rmi://{0}:{1,number,#}/rmi{2}"/>
		<property name="clusterName" value="rmi-client-test"/>
	</bean>

	<bean id="vmid-string" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
		<property name="targetClass" value="java.lang.Math"/>
		<property name="targetMethod" value="abs"/>	
		<property name="arguments">
		<list>
			<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
				<property name="targetObject">
					<bean id="vmid" class="java.rmi.dgc.VMID"/>
				</property>
				<property name="targetMethod" value="hashCode"/>
			</bean>
		</list>
		</property>
	</bean>

	<bean class="org.springframework.jmx.support.ConnectorServerFactoryBean"
		depends-on="registry">
		<property name="objectName" value="connector:name=rmi" />
		<property name="serviceUrl"
			ref="serviceUrl" />
		<property name="environment">
			<map>
				<entry key="jmx.remote.jndi.rebind" value="true"/>
			</map>
		</property>	
	</bean>

	<bean id="serviceUrl" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
		<property name="targetObject">
			<bean class="java.lang.String">
				<constructor-arg value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/rmi"/>
			</bean>
		</property>
		<property name="targetMethod" value="concat"/>
		<property name="arguments">
			<list>
				<ref bean="vmid-string"/>
			</list>
		</property>
	</bean>
	-->

	<bean id="log4jHierarchyMBean" class="org.apache.log4j.jmx.HierarchyDynamicMBean" />

	<bean class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
				<entry key="log4j:hierarchy=default" value-ref="log4jHierarchyMBean"/>
				<entry key="ch.post.it.common.jmx:name=MyBean">
					<bean class="ch.post.it.common.jmx.server.MyBean"/>
				</entry>
			</map>
		</property>
	</bean>
</beans>