Tag: Coherence

ActiveCache and Coherence*Web

Coherence*Web is an HTTP session management module dedicated to managing session state in clustered environments. Built on top of Coherence, Coherence*Web: brings Coherence data grid’s data scalability, availability, reliability, and performance to in-memory session management and storage; allows storage of session data outside of the Java EE application server, freeing application server heap space and enabling server restarts without session data loss; enables session sharing and management across different Web applications, domains and application servers. More information can be found in the post Setting-up a WebLogic Cluster that uses Coherence.

ActiveCache is employed by applications running on WebLogic Server and provides replicated and distributed caching services that make an application’s data available to servers in a Coherence data cluster. ActiveCache provides direct access by applications to data caches, either through resource injection or component-based JNDI lookup, and lets us display, monitor, create, and configure Coherence clusters using the WebLogic Server Administration Console and WLST.

So far the commercial side of this post. Now let us first set-up an application that puts some data into the HttpSession. To this end we will use the following servlet

package userinterface.servlets;

import model.entities.Klant;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Random;

public class TestServlet extends HttpServlet {

    private Random generator;

    @Override
    public void init() throws ServletException {
        generator = (Random)getServletContext().getAttribute("generator");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession(false);

        // generate a random client
        Klant klant = createKlant();

        // insert a client
        session.setAttribute(klant.getKlantnummer().toString(), klant);
        if (generator.nextDouble() < 0.001) {
            // remove a client
            session.removeAttribute(generateKlantNummer().toString());
        } else {
            // find a client by ID
            session.getAttribute(generateKlantNummer().toString());
        }

        PrintWriter writer = response.getWriter();
        Enumeration<String> clientids = session.getAttributeNames();
        while (clientids.hasMoreElements()) {
            writer.println(session.getAttribute(clientids.nextElement()));
        }
        writer.flush();
        writer.close();
    }

    private Klant createKlant() {
        int klantnummer = generateKlantNummer();

        Klant klant = new Klant();
        klant.setKlantnummer(klantnummer);
        klant.setNaam("Middleware" + klantnummer);
        klant.setAdres("Magic");
        klant.setStad("Pune");
        klant.setProvincie("IN");
        klant.setPostcode("1234AB");
        klant.setGebied(1);
        klant.setTelefoonnummer("123-4567");
        klant.setReputatieNummer(1);
        klant.setKredietlimiet(Math.rint(generator.nextDouble() * 5000.0));
        klant.setCommentaar(Long.toString(Math.abs(generator.nextLong()), 36));

        return klant;
    }

    private Integer generateKlantNummer() {
        return generator.nextInt(10000);
    }
}

and the following web configuration

<web-app ...>
    <listener>
        <listener-class>userinterface.listeners.ContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>userinterface.servlets.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/test</url-pattern>
    </servlet-mapping>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>All</web-resource-name>
            <url-pattern>/test</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>MANAGER</role-name>
            <role-name>EMPLOYEE</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.jsp</form-login-page>
            <form-error-page>/login.jsp</form-error-page>
        </form-login-config>
    </login-config>
    <security-role>
        <role-name>MANAGER</role-name>
    </security-role>
    <security-role>
        <role-name>EMPLOYEE</role-name>
    </security-role>
</web-app>

which secures the servlet URL (and enables us to set-up a session). Refer to the posts WebLogic 12c in Action and Deploy WebLogic12c to Multiple Machines for more information (and WLST scripts) on setting-up a WebLogic cluster. To deploy the application, we create the following directory structure

/testactivecache
	/app
		TestActiveCache.war
	/plan
		Plan.xml
		/WEB-INF
			weblogic.xml

Here weblogic.xml has the following contents

<weblogic-web-app ...>
	<security-role-assignment>
		<role-name>EMPLOYEE</role-name>
		<principal-name>employees</principal-name>
	</security-role-assignment>
	<security-role-assignment>
		<role-name>MANAGER</role-name>
		<principal-name>managers</principal-name>
	</security-role-assignment>
	<session-descriptor>
		<persistent-store-type>replicated_if_clustered</persistent-store-type>
	</session-descriptor>
</weblogic-web-app>

in which we map the EMPLOYEE and MANAGER roles (defined in the application) to groups (employees and managers) created in the WebLogic console. We set the persistent-store-type to replicated_if_clustered, i.e., if the Web application is deployed on a clustered server, the in-effect persistent-store-type will be replicated.

Let us test the session fail-over. We start with two servers in the cluster and issue requests as two different users. By using the cluster, monitoring environment in the WebLogic Admin console, we can see that cluster-server1 is the holder of the primary sessions and cluster-server2 holds the secundairy sessions

Next, we shutdown cluster-server1

Issue some requests (and notice that the session has failed-over to cluster-server2) and we can continue working as if nothing has happened. Bring up cluster-server1 again

Now cluster-server2 is the holder of the primary sessions and cluster-server1 holds the secundairy sessions. Note that the secundairy sessions are present after the user has issued some requests, i.e., the session is replicated when setAttribute has been called on HttpSession. In the application server logging the following is observed

# SHUTDOWN CLUSTER-SERVER1
####<Mar 7, 2013 12:59:37 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server1> <[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'> <weblogic> <> <94ba3ca995633592:-60f7582f:13d44ab2061:-8000-0000000000000401> <1362657577726> <BEA-000103> <Disconnecting from cluster loadtest-cluster> 

####<Mar 7, 2013 12:59:37 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server2> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657577103> <BEA-000144> <Managed Server cluster-server1 has been suspended or shut down.> 

# START CLUSTER_SERVER1
####<Mar 7, 2013 1:04:21 PM CET> <Notice> <Cluster> <middleware-magic.com> <cluster-server1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657861115> <BEA-000197> <Listening for announcements from cluster using unicast cluster messaging> 

####<Mar 7, 2013 1:04:21 PM CET> <Notice> <Cluster> <middleware-magic.com> <cluster-server1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657861125> <BEA-000133> <Waiting to synchronize with other running members of loadtest-cluster.> 

####<Mar 7, 2013 1:04:29 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server1> <weblogic.cluster.MessageReceiver> <<WLS Kernel>> <> <> <1362657869754> <BEA-003107> <Lost 2 unicast message(s).> 

####<Mar 7, 2013 1:04:29 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server1> <[STANDBY] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657869781> <BEA-000111> <Adding cluster-server2 with ID -5268211843454898694S:middleware-magic.com:[9002,9002,-1,-1,-1,-1,-1]:base_domain:cluster-server2 to cluster: loadtest-cluster view.> 

####<Mar 7, 2013 1:04:29 PM CET> <Notice> <Cluster> <middleware-magic.com> <cluster-server1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657869787> <BEA-000142> <Trying to download cluster JNDI tree from server cluster-server2.> 

####<Mar 7, 2013 1:04:29 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server1> <[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657869806> <BEA-000128> <Updating -5268211843454898694S:middleware-magic.com:[9002,9002,-1,-1,-1,-1,-1]:base_domain:cluster-server2 in the cluster.> 

####<Mar 7, 2013 1:04:29 PM CET> <Notice> <Cluster> <middleware-magic.com> <cluster-server1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657869936> <BEA-000164> <Synchronized cluster JNDI tree from server cluster-server2.> 

####<Mar 7, 2013 1:04:30 PM CET> <Notice> <Cluster> <middleware-magic.com> <cluster-server1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657870214> <BEA-000162> <Starting "async" replication service with remote cluster address "null">

####<Mar 7, 2013 1:04:30 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server2> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657870415> <BEA-000111> <Adding cluster-server1 with ID 7719031716195535281S:middleware-magic.com:[9001,9001,-1,-1,-1,-1,-1]:base_domain:cluster-server1 to cluster: loadtest-cluster view.> 

####<Mar 7, 2013 1:04:31 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server2> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657871227> <BEA-000128> <Updating 7719031716195535281S:middleware-magic.com:[9001,9001,-1,-1,-1,-1,-1]:base_domain:cluster-server1 in the cluster.> 

####<Mar 7, 2013 1:04:31 PM CET> <Info> <Cluster> <middleware-magic.com> <cluster-server1> <[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1362657871758> <BEA-000128> <Updating -5268211843454898694S:middleware-magic.com:[9002,9002,-1,-1,-1,-1,-1]:base_domain:cluster-server2 in the cluster.>

Now let us configure the application such that it will use Coherence*Web to store the session information (such that the session data will be off loaded to separate JVMs and not interfere with the application). We start with configuring a Coherence Cluster by using the WebLogic Admin console. The Coherence Cluster has the following configuration

<!-- snippet from config.xml -->
<coherence-cluster-system-resource>
	<name>coherence-session-cluster</name>
    <target>loadtest-cluster</target>
    <descriptor-file-name>coherence/coherence-session-cluster/coherence-session-cluster-coherence.xml</descriptor-file-name>
</coherence-cluster-system-resource>

<!-- coherence-session-cluster-coherence.xml -->
<weblogic-coherence ...>
	<name>coherence-session-cluster</name>
	<coherence-cluster-params>
		<unicast-listen-address>localhost</unicast-listen-address>
		<unicast-listen-port>8088</unicast-listen-port>
		<unicast-port-auto-adjust>true</unicast-port-auto-adjust>
		<multicast-listen-address>231.1.1.1</multicast-listen-address>
		<multicast-listen-port>7777</multicast-listen-port>
		<coherence-cluster-well-known-addresses>
			<coherence-cluster-well-known-address>
				<name>middleware-magic</name>
				<listen-address>middleware-magic.com</listen-address>
				<listen-port>8088</listen-port>
			</coherence-cluster-well-known-address>
		</coherence-cluster-well-known-addresses>
	</coherence-cluster-params>
</weblogic-coherence>

Note that when a well-known-address has been confgured, the multicast settings are not used. Next, we need to configure a Coherence Server. The Coherence Server has the following configuration

<coherence-server>
    <name>coherence-session-server</name>
    <machine>machine1</machine>
    <coherence-cluster-system-resource>coherence-session-cluster</coherence-cluster-system-resource>
    <unicast-listen-address>localhost</unicast-listen-address>
    <unicast-listen-port>8088</unicast-listen-port>
    <unicast-port-auto-adjust>true</unicast-port-auto-adjust>
    <coherence-server-start>
		<java-vendor>Oracle</java-vendor>
		<java-home>/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0</java-home>
		<class-path>/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules.coherence.server_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence-web.jar</class-path>
		<arguments>-jrockit -Xms512m -Xmx512m -Xns128m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -Dtangosol.coherence.cacheconfig=session-cache-config.xml -Dtangosol.coherence.session.localstorage=true -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true</arguments>
    </coherence-server-start>
</coherence-server>

Note the class path entries. The first is logical, the second is needed such that the Coherence Server can be started using the node manager, the third is needed as it contains the Coherence cache conifguration file (in this case session-cache-config.xml). In the JVM arguments we set the system property tangosol.coherence.cacheconfig to session-cache-config.xml. This tells Coherence which cache configuration to use. We also set the system property tangosol.coherence.session.localstorage to true, as within the cache configuration the storage is turned off

...
<distributed-scheme>
	<scheme-name>session-base</scheme-name>
	<service-name>DistributedSessions</service-name>
	<thread-count>0</thread-count>
	<lease-granularity>member</lease-granularity>
	<local-storage system-property="tangosol.coherence.session.localstorage">false</local-storage>
	<partition-count>257</partition-count>
	<backup-count>1</backup-count>
	<backup-storage>
		<type>on-heap</type>
	</backup-storage>
	<request-timeout>30s</request-timeout>
	<backing-map-scheme>
		<local-scheme>
			<scheme-ref>unlimited-local</scheme-ref>
		</local-scheme>
	</backing-map-scheme>
	<autostart>true</autostart>
</distributed-scheme>
...

Next we deploy the following shared libraries

<library>
    <name>coherence-web-spi#1.0.0.0@1.0.0.0</name>
    <target>loadtest-cluster</target>
    <module-type>war</module-type>
    <source-path>/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence-web-spi.war</source-path>
    <security-dd-model>DDOnly</security-dd-model>
</library>
<library>
    <name>coherence#3.7.1.1@3.7.1.1</name>
    <target>loadtest-cluster</target>
    <module-type xsi:nil="true"></module-type>
    <source-path>/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar</source-path>
    <security-dd-model>DDOnly</security-dd-model>
</library>
<library>
    <name>active-cache#1.0@1.0</name>
    <target>loadtest-cluster</target>
    <module-type xsi:nil="true"></module-type>
    <source-path>/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/common/deployable-libraries/active-cache-1.0.jar</source-path>
    <security-dd-model>DDOnly</security-dd-model>
    <staging-mode>nostage</staging-mode>
</library>

Note that for the ActiveCache library we have chosen nostage as the staging mode, i.e., in the WebLogic Admin console on the deployment settings page, choose the ‘I will make the deployment accessible from the following location’. The reason for this, is that the jar file only contains a MANIFEST.MF with the following class path setting

Class-Path: ../../../modules/features/weblogic.server.modules.coherence.integration_12.1.1.0.jar

The weblogic.server.modules.coherence.integration_12.1.1.0.jar file in its MANIFEST.MF refers to

Class-Path: ../com.oracle.core.coherence.integration_2.0.0.0.jar

If we would choose a staging method the references would break, and ActiveCache will not work. To let the application refer to the deployed ActiveCache and Coherence libraries, we add the following to the MANIFEST.MF file

Extension-List: ActiveCache Coherence
ActiveCache-Extension-Name: active-cache
ActiveCache-Specification-Version: 1.0
ActiveCache-Implementation-Version: 1.0
Coherence-Extension-Name: coherence
Coherence-Specification-Version: 3.7.1.1
Coherence-Implementation-Version: 3.7.1.1

We also included a tangosol-coherence-override.xml file in the WEB-INF/classes directory of the application, with the following contents

<coherence ...>
    <cluster-config>
        <member-identity>
            <cluster-name system-property="tangosol.coherence.cluster">coherence-session-cluster</cluster-name>
        </member-identity>
        <unicast-listener>
            <well-known-addresses>
                <socket-address id="1">
                    <address>middleware-magic.com</address>
                    <port>8088</port>
                </socket-address>
            </well-known-addresses>
        </unicast-listener>
    </cluster-config>
</coherence>

Here, we configure the cluster-name, such that the application will only join the cluster with name coherence-session-cluster, which we also used in the configuration of the Coherence Cluster in the WebLogic Admin console. We also have configured a well-known-address. By default, Coherence uses a multicast protocol to discover other nodes when forming a cluster. If multicast networking is undesirable, or unavailable in the environment, the Well Known Addresses feature may be used to eliminate the need for multicast traffic. When in use the cluster is configured with a relatively small list of nodes which are allowed to start the cluster, and which are likely to remain available over the cluster lifetime. There is no requirement for all WKA nodes to be simultaneously active at any point in time. This list is used by all other nodes to find their way into the cluster without the use of multicast, thus at least one node that is configured as a well-known node must be running for other nodes to be able to join.

To deploy the application we again use the following structure

/testactivecache
	/app
		TestActiveCache.war
	/plan
		Plan.xml
		/WEB-INF
			weblogic.xml

in which weblogic.xml has the following contents

<weblogic-web-app ...>
	<security-role-assignment>
		<role-name>EMPLOYEE</role-name>
		<principal-name>employees</principal-name>
	</security-role-assignment>
	<security-role-assignment>
		<role-name>MANAGER</role-name>
		<principal-name>managers</principal-name>
	</security-role-assignment>
	<library-ref>
		<library-name>coherence-web-spi</library-name>
		<specification-version>1.0.0.0</specification-version>
		<implementation-version>1.0.0.0</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
	<coherence-cluster-ref>
		<coherence-cluster-name>coherence-session-cluster</coherence-cluster-name>
	</coherence-cluster-ref>
</weblogic-web-app>

Here we refer to the Coherence*Web shared library, such that it will be merged on runtime with our application, as it contains, next to the necessary jars, an important configuration in its web.xml

<context-param>
	<param-name>coherence-web-sessions-enabled</param-name>
    <param-value>true</param-value>
</context-param>

which enables Coherence web sessions for the application. To test the set-up, deploy the application, issue some requests as different users

shutdown a server (in this case cluster-server2)

As we have turned on the MBean management in Coherence (-Dtangosol.coherence.management=all) we can use an MBean browser to see what is going on

What is fun is that it is even possible to shut down all the WebLogic servers in the cluster and still be able to retrieve the session

<Mar 7, 2013 2:08:57 PM> <INFO> <NodeManager> <Starting Coherence server with command line: /home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0/bin/java -Dtangosol.coherence.member=coherence-session-server -Dtangosol.coherence.wka=middleware-magic.com -Dtangosol.coherence.wka.port=8088 -Dtangosol.coherence.clusterport=7777 -Dtangosol.coherence.clusteraddress=231.1.1.1 -Dtangosol.coherence.localport=8088 -Dtangosol.coherence.localhost=localhost -Dtangosol.coherence.cluster=coherence-session-cluster -Djava.class.path=/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules.coherence.server_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence-web.jar -jrockit -Xms512m -Xmx512m -Xns128m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -Dtangosol.coherence.cacheconfig=session-cache-config.xml -Dtangosol.coherence.session.localstorage=true -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true -Dweblogic.RootDirectory=/home/weblogic/weblogic12.1.1/configuration/domains/base_domain weblogic.nodemanager.server.provider.WeblogicCacheServer >
<Mar 7, 2013 2:08:57 PM> <INFO> <NodeManager> <Working directory is '/home/weblogic/weblogic12.1.1/configuration/domains/base_domain'>
<Mar 7, 2013 2:08:57 PM> <INFO> <NodeManager> <Server output log file is '/home/weblogic/weblogic12.1.1/configuration/domains/base_domain/servers_coherence/coherence-session-server/logs/coherence-session-server.out'>
2013-03-07 14:08:58.464/1.196 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence.xml"
2013-03-07 14:08:58.489/1.221 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational overrides from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2013-03-07 14:08:58.489/1.221 Oracle Coherence 3.7.1.1 <D5> (thread=Main Thread, member=n/a): Optional configuration override "/tangosol-coherence-override.xml" is not specified
2013-03-07 14:08:58.494/1.226 Oracle Coherence 3.7.1.1 <D5> (thread=Main Thread, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.1 Build 28901
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2013-03-07 14:08:59.345/2.077 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded Reporter configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/reports/report-group.xml"
2013-03-07 14:09:00.016/2.748 Oracle Coherence GE 3.7.1.1 <D4> (thread=Main Thread, member=n/a): TCMP bound to /192.168.1.150:8088 using SystemSocketProvider
2013-03-07 14:09:03.440/6.172 Oracle Coherence GE 3.7.1.1 <Info> (thread=Cluster, member=n/a): Created a new cluster "coherence-session-cluster" with Member(Id=1, Timestamp=2013-03-07 14:09:00.083, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8431,member:coherence-session-server, Role=WeblogicWeblogicCacheServer, Edition=Grid Edition, Mode=Development, CpuCount=4, SocketCount=1) UID=0xC0A801960000013D44F80E33FE391F98
2013-03-07 14:09:03.477/6.209 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Started cluster Name=coherence-session-cluster

WellKnownAddressList(Size=1,
  WKA{Address=192.168.1.150, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2013-03-07 14:09:00.083, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8431,member:coherence-session-server, Role=WeblogicWeblogicCacheServer)
  OldestMember=Member(Id=1, Timestamp=2013-03-07 14:09:00.083, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8431,member:coherence-session-server, Role=WeblogicWeblogicCacheServer)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2013-03-07 14:09:00.083, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8431,member:coherence-session-server, Role=WeblogicWeblogicCacheServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2013-03-07 14:09:03.445|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2013-03-07 14:09:03.596/6.328 Oracle Coherence GE 3.7.1.1 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2013-03-07 14:09:03.682/6.414 Oracle Coherence GE 3.7.1.1 <D5> (thread=ReplicatedCache:ReplicatedSessionsMisc, member=1): Service ReplicatedSessionsMisc joined the cluster with senior service member 1
2013-03-07 14:09:03.872/6.604 Oracle Coherence GE 3.7.1.1 <D5> (thread=DistributedCache:DistributedSessions, member=1): Service DistributedSessions joined the cluster with senior service member 1
2013-03-07 14:09:03.914/6.646 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=1):
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7.1, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  ReplicatedCache{Name=ReplicatedSessionsMisc, State=(SERVICE_STARTED), Id=2, Version=3.0, OldestMemberId=1}
  PartitionedCache{Name=DistributedSessions, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
  )

Started DefaultCacheServer...

2013-03-07 14:10:48.607/111.339 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-03-07 14:10:48.395, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8311, Role=WeblogicServer) joined Cluster with senior member 1
2013-03-07 14:10:48.856/111.589 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2013-03-07 14:10:48.903/111.635 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2013-03-07 14:10:48.702, Address=192.168.1.150:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:8308, Role=WeblogicServer) joined Cluster with senior member 1
2013-03-07 14:10:49.360/112.092 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 3 joined Service Management with senior member 1
2013-03-07 14:10:56.837/119.569 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 3 joined Service DistributedSessions with senior member 1
2013-03-07 14:10:56.858/119.590 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service DistributedSessions with senior member 1
# MBEAN BROWSER IS STARTED
[INFO ][mgmnt  ] Local JMX connector started
# CLUSTER-SERVER 2 IS SHUTDOWN
2013-03-07 14:23:26.704/869.436 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 3 left service Management with senior member 1
2013-03-07 14:23:26.710/869.442 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 3 left service DistributedSessions with senior member 1
2013-03-07 14:23:26.731/869.463 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=3, Timestamp=2013-03-07 14:10:48.702, Address=192.168.1.150:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:8308, Role=WeblogicServer) due to a peer departure; removing the member.
2013-03-07 14:23:26.733/869.465 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2013-03-07 14:23:26.733, Address=192.168.1.150:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:8308, Role=WeblogicServer) left Cluster with senior member 1
# CLUSTER-SERVER 2 IS STARTED AGAIN
2013-03-07 14:43:17.466/2060.198 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2013-03-07 14:43:17.261, Address=192.168.1.150:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:9145, Role=WeblogicServer) joined Cluster with senior member 1
2013-03-07 14:43:17.908/2060.640 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 4 joined Service Management with senior member 1
2013-03-07 14:43:20.149/2062.881 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 4 joined Service DistributedSessions with senior member 1
# CLUSTER-SERVER 1 AND CLUSTER-SERVER 2 ARE SHUTDOWN
2013-03-07 14:46:16.667/2239.399 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2013-03-07 14:46:16.672/2239.404 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 4 left service Management with senior member 1
2013-03-07 14:46:16.680/2239.412 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 left service DistributedSessions with senior member 1
2013-03-07 14:46:16.687/2239.419 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 4 left service DistributedSessions with senior member 1
2013-03-07 14:46:16.711/2239.443 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=4, Timestamp=2013-03-07 14:43:17.261, Address=192.168.1.150:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:9145, Role=WeblogicServer) due to a peer departure; removing the member.
2013-03-07 14:46:16.711/2239.443 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2013-03-07 14:46:16.711, Address=192.168.1.150:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:9145, Role=WeblogicServer) left Cluster with senior member 1
2013-03-07 14:46:16.712/2239.444 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): TcpRing connection to Member(Id=2, Timestamp=2013-03-07 14:10:48.395, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8311, Role=WeblogicServer) refused (Connection refused); removing the member.
2013-03-07 14:46:16.712/2239.444 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-03-07 14:46:16.712, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8311, Role=WeblogicServer) left Cluster with senior member 1
# CLUSTER-SERVER 1 AND CLUSTER-SERVER 2 ARE STARTED AGAIN
2013-03-07 14:48:12.673/2355.405 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2013-03-07 14:48:12.472, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:9402, Role=WeblogicServer) joined Cluster with senior member 1
2013-03-07 14:48:13.124/2355.856 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 3 joined Service Management with senior member 1
2013-03-07 14:48:15.067/2357.799 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=5, Timestamp=2013-03-07 14:48:14.866, Address=192.168.1.150:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:9411, Role=WeblogicServer) joined Cluster with senior member 1
2013-03-07 14:48:15.482/2358.214 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 5 joined Service Management with senior member 1
2013-03-07 14:48:15.594/2358.326 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 3 joined Service DistributedSessions with senior member 1
2013-03-07 14:48:17.851/2360.583 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 5 joined Service DistributedSessions with senior member 1

When cluster-server1 and cluster-server2 are up again, we can access the application with the session still available. Not very useful, as the application cannot be reached when all the servers that it runs on are down, but good to know that Coherence holds on to the data as long as the data does not expire. Very powerful stuff!

References

[1] Coherence Documentation.
[2] User’s Guide for Coherence*Web.
[3] Using ActiveCache.


WebLogic, Coherence and the G1 Collector

With JRockit not seeing a JDK7 version, we might want to change a current WebLogic environment to use Oracle JDK. Let us use the Garbage-First (G1) Collector, which is fully supported in Oracle JDK 7 update 4 and later releases.

When using the G1 collector, the heap is partitioned into a set of equal-sized heap regions, each a contiguous range of virtual memory. Certain region sets are assigned the same roles (eden, survivor, old) as in the older collectors, but there is not a fixed size for them. This provides greater flexibility in memory usage. When performing garbage collections, G1 operates in a manner similar to the CMS collector. G1 performs a concurrent global marking phase to determine the liveness of objects throughout the heap. After the mark phase completes, G1 knows which regions are mostly empty. It collects in these regions first, which usually yields a large amount of free space. This is why this method of garbage collection is called Garbage-First. As the name suggests, G1 concentrates its collection and compaction activity on the areas of the heap that are likely to be full of reclaimable objects, that is, garbage. G1 uses a pause prediction model to meet a user-defined pause time target and selects the number of regions to collect based on the specified pause time target.

The regions identified by G1 as ripe for reclamation are garbage collected using evacuation. G1 copies objects from one or more regions of the heap to a single region on the heap, and in the process both compacts and frees up memory. This evacuation is performed in parallel on multi-processors, to decrease pause times and increase throughput. Thus, with each garbage collection, G1 continuously works to reduce fragmentation, working within the user defined pause times. This is beyond the capability of both the previous methods. CMS (Concurrent Mark Sweep ) garbage collector does not do compaction. ParallelOld garbage collection performs only whole-heap compaction, which results in considerable pause times.

It is important to note that G1 is not a real-time collector. It meets the set pause time target with high probability but not absolute certainty. Based on data from previous collections, G1 does an estimate of how many regions can be collected within the user specified target time. Thus, the collector has a reasonably accurate model of the cost of collecting the regions, and it uses this model to determine which and how many regions to collect while staying within the pause time target.

To change a WebLogic installation to use another JDK, we can adjust the setDomainEnv file as follows (i.e., add SUN_JAVA_HOME, JAVA_VENDOR and USER_MEM_ARGS), for example,

#!/bin/sh

...

WL_HOME="/home/weblogic/weblogic12.1.1/installation/wlserver_12.1"
export WL_HOME

BEA_JAVA_HOME="/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0"
export BEA_JAVA_HOME

SUN_JAVA_HOME="/home/weblogic/jdk1.7.0_11"
export SUN_JAVA_HOME

JAVA_VENDOR="Sun"
export JAVA_VENDOR

if [ "${JAVA_VENDOR}" = "Oracle" ] ; then
	JAVA_HOME="${BEA_JAVA_HOME}"
	export JAVA_HOME
else
	if [ "${JAVA_VENDOR}" = "Sun" ] ; then
		JAVA_HOME="${SUN_JAVA_HOME}"
		export JAVA_HOME
	else
		JAVA_VENDOR="Oracle"
		export JAVA_VENDOR
		JAVA_HOME="/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0"
		export JAVA_HOME
	fi
fi

...

if [ "${SERVER_NAME}" = "" ] ; then
	SERVER_NAME="AdminServer"
	export SERVER_NAME
fi

if [ "${SERVER_NAME}" = "AdminServer" ] ; then
	if [ "${JAVA_VENDOR}" = "Sun" ] ; then
		# Memory arguments for JDK
		USER_MEM_ARGS="-server -Xms512m -Xmx512m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=80 -XX:G1HeapRegionSize=2048k -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"
		export USER_MEM_ARGS
	fi

	if [ "${JAVA_VENDOR}" = "Oracle" ] ; then
		# JMX configuration for JRockit
		JMX_OPTIONS="-Djava.rmi.server.hostname=192.168.1.150 -Xmanagement:ssl=false,authenticate=false,port=7091,autodiscovery=true"
		export JMX_OPTIONS
		# Memory arguments for JRockit
		USER_MEM_ARGS="-jrockit -Xms512m -Xmx512m -Xns128m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -XX:+UseCallProfiling -XX:+UseLargePagesForHeap ${JMX_OPTIONS}"
		export USER_MEM_ARGS
	fi
fi

To prevent the following error

Exception in thread "[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'"
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'"
Exception in thread "Timer-1"
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Timer-1"
***************************************************************************
The WebLogic Server encountered a critical failure
Reason: PermGen space
***************************************************************************
<Jan 30, 2013 4:24:14 PM CET> <Notice> <WebLogicServer> <BEA-000365> <Server state changed to FORCE_SHUTTING_DOWN.>
Exception in thread "main"
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"

set the perm size, to values that are large enough (in the example 256Mb was enough in order to start WebLogic, these values might change when we are dealing with large deployments). When we want to use the node manager to start and stop servers we have to adjust the nodemanager.properties and set the JAVA_HOME variables accordingly, for example,

...
javaHome=/home/weblogic/jdk1.7.0_11
...
JavaHome=/home/weblogic/jdk1.7.0_11/jre
...
StartScriptEnabled=true
...

To set up an environment that has an application that uses Coherence deployed on WebLogic, we create a WebLogic managed server that has the following settings

<server>
	<name>security-server</name>
    <ssl>
		<enabled>false</enabled>
    </ssl>
    <machine>machine1</machine>
    <listen-port>8001</listen-port>
    <cluster xsi:nil="true"></cluster>
    <web-server>
		<web-server-log>
			<number-of-files-limited>false</number-of-files-limited>
		</web-server-log>
    </web-server>
    <listen-address>middleware-magic.com</listen-address>
    <server-start>
		<java-vendor>Sun</java-vendor>
		<java-home>/home/weblogic/jdk1.7.0_11</java-home>
		<arguments>-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=80 -XX:G1HeapRegionSize=2048k -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages -Dtangosol.coherence.mode=prod -Dtangosol.coherence.distributed.localstorage=false</arguments>
    </server-start>
</server>

and a Coherence cache server that has the following settings

<coherence-server>
    <name>coherence-server1</name>
    <machine>machine1</machine>
    <coherence-cluster-system-resource xsi:nil="true"></coherence-cluster-system-resource>
    <unicast-listen-address>localhost</unicast-listen-address>
    <unicast-listen-port>8088</unicast-listen-port>
    <unicast-port-auto-adjust>true</unicast-port-auto-adjust>
    <coherence-server-start>
		<java-vendor>Sun</java-vendor>
		<java-home>/home/weblogic/jdk1.7.0_11</java-home>
		<class-path>/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules.coherence.server_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar</class-path>
		<arguments>-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=80 -XX:G1HeapRegionSize=2048k -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages -Dtangosol.coherence.mode=prod -Dtangosol.coherence.cacheconfig=security-cache-config.xml -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true</arguments>
    </coherence-server-start>
</coherence-server>
  • -server – select the JIT compiler.
  • -Xms – initial heap size.
  • -Xmx – maximum heap size.
  • -XX:PermSize and -XX:MaxPermSize – size of the permanent generation.
  • -XX:NewRatio=N – sets the young generation to heap size / (1 + N).
  • -XX:SurvivorRatio – ratio of eden/survivor space size.
  • -XX:MaxTenuringThreshold – sets the maximum tenuring threshold for use in adaptive GC sizing (above we assume that objects that are not collected in the eden space are objects related to the Coherence cache, and are tenured to the old space as these objects will live for a long time).
  • -XX:+UseG1GC – select the G1 collector.
  • -XX:MaxGCPauseMillis – sets the maximum pause time goal.
  • -XX:InitiatingHeapOccupancyPercent – percentage of the (entire) heap occupancy to start a concurrent GC cycle. It is used by the G1 collector to trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations.
  • -XX:G1HeapRegionSize – sets the size of the uniformly sized regions. We set this equal to the large page size.
  • -XX:+UseTLAB – enables thread-local object allocation. More information on thread local allocation can be found in the ‘Compaction and Thread Local Area’ section of the Tune the JVM that runs Coherence post.
  • -XX:LargePageSizeInBytes – sets the large page size used for the Java heap. We set this equal to the operating system parameter: Hugepagesize, which in our case is 2048kB
  • -XX:+UseLargePages – use large page memory. The steps involved on how to configure large pages in the operating system can be found in the ‘Call profiling and large pages’ section of the Tune the JVM that runs Coherence post.

Testing

To test the Coherence part of the set-up we will perform a load test, by using the following scripts

#!/bin/sh

# coherence options
#JMX_OPTIONS="-Dcom.sun.management.jmxremote.port=7091 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"
#JMX_OPTIONS="-Djava.rmi.server.hostname=192.168.1.150 -Xmanagement:ssl=false,authenticate=false,port=7091,autodiscovery=true"
COHERENCE_MANAGEMENT_OPTIONS="-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true"
COHERENCE_OPTIONS="-Dtangosol.coherence.mode=prod -Dtangosol.coherence.cacheconfig=security-cache-config.xml ${COHERENCE_MANAGEMENT_OPTIONS} ${JMX_OPTIONS}"
export COHERENCE_OPTIONS

JHICCUP_HOME="/home/weblogic/temp/jHiccup"
export JHICCUP_HOME

JAVA_HOME="/home/weblogic/jdk1.7.0_11"
#JAVA_HOME="/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0"
export JAVA_HOME

MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=80 -XX:G1HeapRegionSize=2048k -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"
#MEM_ARGS="-jrockit -Xms1024m -Xmx1024m -Xgc:pausetime -XpauseTarget=200m -XX:+UseCallProfiling -XX:+UseLargePagesForHeap"
export MEM_ARGS

CLASSPATH="/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar"
export CLASSPATH

# start the test
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} com.tangosol.net.DefaultCacheServer
#$JHICCUP_HOME/jHiccup ${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} com.tangosol.net.DefaultCacheServer

and

#!/bin/sh
# coherence options
COHERENCE_MANAGEMENT_OPTIONS="-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true"
COHERENCE_OPTIONS="-Dtangosol.coherence.mode=prod -Dtangosol.coherence.cacheconfig=security-cache-config.xml -Dtangosol.coherence.distributed.localstorage=false"
export COHERENCE_OPTIONS

#MEASUREMENT_OPTIONS="-verbosegc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -Xloggc:/home/weblogic/temp/gc.out"
#export MEASUREMENT_OPTIONS

JHICCUP_HOME="/home/weblogic/temp/jHiccup"
export JHICCUP_HOME

JAVA_HOME="/home/weblogic/jdk1.7.0_11"
#JAVA_HOME="/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0"
export JAVA_HOME

MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=80 -XX:G1HeapRegionSize=2048k -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"
#MEM_ARGS="-jrockit -Xms1024m -Xmx1024m -Xgc:pausetime -XpauseTarget=200m -XX:+UseCallProfiling -XX:+UseLargePagesForHeap"
export MEM_ARGS

CLASSPATH="/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar"
export CLASSPATH

# start the test
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} ${MEASUREMENT_OPTIONS} model.test.Test
#$JHICCUP_HOME/jHiccup ${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} ${MEASUREMENT_OPTIONS} model.test.Test

The first script runs a cache server, the second a cache client (which inserts, updates, deletes and obtains data from the cache)

[weblogic@middleware-magic temp]$ ./default-cache-server.sh
2013-02-08 13:18:23.816/0.518 Oracle Coherence 3.7.1.1 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence.xml"
2013-02-08 13:18:23.911/0.613 Oracle Coherence 3.7.1.1 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence-override-prod.xml"
2013-02-08 13:18:24.003/0.705 Oracle Coherence 3.7.1.1 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/tangosol-coherence-override.xml"
2013-02-08 13:18:24.010/0.712 Oracle Coherence 3.7.1.1 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.1 Build 28901
 Grid Edition: Production mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2013-02-08 13:18:24.434/1.136 Oracle Coherence GE 3.7.1.1 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/security-cache-config.xml"
2013-02-08 13:18:24.569/1.271 Oracle Coherence GE 3.7.1.1 <Info> (thread=main, member=n/a): Loaded Reporter configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/reports/report-group.xml"
2013-02-08 13:18:25.047/1.749 Oracle Coherence GE 3.7.1.1 <D4> (thread=main, member=n/a): TCMP bound to /192.168.1.150:8088 using SystemSocketProvider
2013-02-08 13:18:55.444/32.146 Oracle Coherence GE 3.7.1.1 <Info> (thread=Cluster, member=n/a): Created a new cluster "SecurityCoherenceCluster" with Member(Id=1, Timestamp=2013-02-08 13:18:25.091, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8514, Role=CoherenceServer, Edition=Grid Edition, Mode=Production, CpuCount=4, SocketCount=1) UID=0xC0A801960000013CB9BE0AC3FE391F98
2013-02-08 13:18:55.459/32.161 Oracle Coherence GE 3.7.1.1 <Info> (thread=main, member=n/a): Started cluster Name=SecurityCoherenceCluster

WellKnownAddressList(Size=1,
  WKA{Address=192.168.1.150, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2013-02-08 13:18:25.091, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8514, Role=CoherenceServer)
  OldestMember=Member(Id=1, Timestamp=2013-02-08 13:18:25.091, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8514, Role=CoherenceServer)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2013-02-08 13:18:25.091, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8514, Role=CoherenceServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2013-02-08 13:18:55.444|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2013-02-08 13:18:55.530/32.232 Oracle Coherence GE 3.7.1.1 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2013-02-08 13:18:55.759/32.461 Oracle Coherence GE 3.7.1.1 <Info> (thread=DistributedCache, member=1): Loaded POF configuration from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/security-pof-config.xml"
2013-02-08 13:18:55.788/32.490 Oracle Coherence GE 3.7.1.1 <Info> (thread=DistributedCache, member=1): Loaded included POF configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/coherence-pof-config.xml"
2013-02-08 13:18:55.850/32.552 Oracle Coherence GE 3.7.1.1 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
2013-02-08 13:18:55.881/32.583 Oracle Coherence GE 3.7.1.1 <Info> (thread=main, member=1):
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7.1, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  PartitionedCache{Name=DistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
  )

Started DefaultCacheServer...

2013-02-08 13:19:19.525/56.227 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest) joined Cluster with senior member 1
2013-02-08 13:19:19.612/56.314 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2013-02-08 13:19:20.038/56.740 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service DistributedCache with senior member 1
2013-02-08 13:20:56.110/152.812 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1125 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 75 packets rescheduled, PauseRate=0.0116, Threshold=4096
2013-02-08 13:20:58.125/154.827 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1154 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 45 packets rescheduled, PauseRate=0.0231, Threshold=3892
2013-02-08 13:27:11.534/528.236 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1784 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 1605 packets rescheduled, PauseRate=0.014, Threshold=3882
2013-02-08 13:27:12.915/529.617 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1166 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 215 packets rescheduled, PauseRate=0.0164, Threshold=3688
2013-02-08 13:27:47.460/564.162 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 3083 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 45 packets rescheduled, PauseRate=0.0214, Threshold=4096
2013-02-08 13:29:33.054/669.756 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1457 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4118 packets rescheduled, PauseRate=0.0207, Threshold=4096
2013-02-08 13:29:58.610/695.312 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1099 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 1244 packets rescheduled, PauseRate=0.0219, Threshold=3505
2013-02-08 13:32:54.405/871.107 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 3079 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 261 packets rescheduled, PauseRate=0.0226, Threshold=2713
2013-02-08 13:39:45.109/1281.811 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1001 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4116 packets rescheduled, PauseRate=0.0172, Threshold=4096
2013-02-08 13:41:05.814/1362.516 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 2553 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 3918 packets rescheduled, PauseRate=0.0185, Threshold=4096
2013-02-08 13:41:07.168/1363.870 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1146 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 2920 packets rescheduled, PauseRate=0.0194, Threshold=4086
2013-02-08 13:41:20.716/1377.418 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 2990 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 111 packets rescheduled, PauseRate=0.0214, Threshold=3505
2013-02-08 13:41:58.747/1415.449 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 3029 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4126 packets rescheduled, PauseRate=0.0231, Threshold=4096
2013-02-08 13:42:00.268/1416.970 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1284 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4117 packets rescheduled, PauseRate=0.024, Threshold=4096
2013-02-08 13:47:57.581/1774.283 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 3942 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 106 packets rescheduled, PauseRate=0.0215, Threshold=3854
2013-02-08 13:49:12.154/1848.856 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 2733 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 148 packets rescheduled, PauseRate=0.0223, Threshold=3505
2013-02-08 13:50:15.032/1911.734 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 3392 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 190 packets rescheduled, PauseRate=0.0235, Threshold=4096
2013-02-08 13:51:00.063/1956.765 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 2918 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4052 packets rescheduled, PauseRate=0.0247, Threshold=4023
2013-02-08 13:51:01.733/1958.435 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1457 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 3890 packets rescheduled, PauseRate=0.0255, Threshold=4096
2013-02-08 13:52:41.079/2057.781 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 2750 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 3726 packets rescheduled, PauseRate=0.0261, Threshold=3698
2013-02-08 14:08:09.516/2986.218 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1063 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 1753 packets rescheduled, PauseRate=0.0229, Threshold=4086
2013-02-08 14:10:04.268/3100.970 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1131 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4106 packets rescheduled, PauseRate=0.0227, Threshold=4086
2013-02-08 14:10:13.452/3110.154 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1010 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4115 packets rescheduled, PauseRate=0.023, Threshold=4096
2013-02-08 14:10:14.833/3111.535 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1139 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4106 packets rescheduled, PauseRate=0.0233, Threshold=4086
2013-02-08 14:10:31.388/3128.090 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1010 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 2878 packets rescheduled, PauseRate=0.0235, Threshold=2858
2013-02-08 14:10:32.819/3129.521 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1206 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 2872 packets rescheduled, PauseRate=0.0239, Threshold=2851
2013-02-08 14:10:43.136/3139.838 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1135 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 163 packets rescheduled, PauseRate=0.0245, Threshold=3283
2013-02-08 14:11:36.859/3193.561 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 4313 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 177 packets rescheduled, PauseRate=0.0254, Threshold=4096
2013-02-08 14:27:48.746/4165.448 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 2824 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4115 packets rescheduled, PauseRate=0.0223, Threshold=4086
2013-02-08 14:27:50.454/4167.156 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1490 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4098 packets rescheduled, PauseRate=0.0227, Threshold=4076
2013-02-08 14:28:39.448/4216.150 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 3848 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 86 packets rescheduled, PauseRate=0.0233, Threshold=4096
2013-02-08 14:29:44.679/4281.381 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 4360 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 199 packets rescheduled, PauseRate=0.0242, Threshold=4096
2013-02-08 14:30:35.106/4331.808 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 3074 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 4126 packets rescheduled, PauseRate=0.0247, Threshold=4096
2013-02-08 14:30:36.794/4333.496 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 1455 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 3904 packets rescheduled, PauseRate=0.0251, Threshold=3882
2013-02-08 14:31:46.922/4403.624 Oracle Coherence GE 3.7.1.1 <Warning> (thread=PacketPublisher, member=1): Experienced a 4512 ms communication delay (probable remote GC) with Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest); 142 packets rescheduled, PauseRate=0.0257, Threshold=4086
2013-02-08 14:32:32.260/4448.962 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2013-02-08 13:19:19.335, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest) due to a peer departure; removing the member.
2013-02-08 14:32:32.260/4448.962 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2013-02-08 14:32:32.260/4448.962 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 left service DistributedCache with senior member 1
2013-02-08 14:32:32.260/4448.962 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-08 14:32:32.26, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8610, Role=ModelTestTest) left Cluster with senior member 1

What is worrying are the ‘Experienced a ….ms communication delay’ messages that appear frequently, and also the reason behind it (i.e., probable remote GC). To see what is happening on the operating system (RAM and CPU) we can use vmstat and mpstat

[weblogic@middleware-magic ~]$ vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 4374164 162896 695112    0    0    14   146  443  602 28  3 68  1  0
[weblogic@middleware-magic ~]$ mpstat -P ALL
Linux 2.6.32-279.22.1.el6.x86_64 (middleware-magic.com) 	02/08/2013 	_x86_64_	(4 CPU)

02:33:15 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
02:33:15 PM  all   28.09    0.29    2.44    0.83    0.01    0.12    0.00    0.00   68.23
02:33:15 PM    0   27.13    0.42    2.53    0.81    0.00    0.12    0.00    0.00   68.98
02:33:15 PM    1   29.86    0.30    2.33    0.81    0.00    0.11    0.00    0.00   66.57
02:33:15 PM    2   27.70    0.21    2.55    0.91    0.00    0.13    0.00    0.00   68.49
02:33:15 PM    3   27.66    0.23    2.35    0.77    0.01    0.12    0.00    0.00   68.87

Now let us see if the communication is really some problem that involves garbage collection (stop-the-world) times. We run the test again, now with JRockit (and also set a pausetime goal of 200msec, just as was done with the G1 collector). The following shows the output of the cache server

[weblogic@middleware-magic temp]$ ./default-cache-server.sh
2013-02-08 11:24:19.549/2.676 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence.xml"
2013-02-08 11:24:19.577/2.704 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational overrides from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence-override-prod.xml"
2013-02-08 11:24:19.595/2.722 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational overrides from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/tangosol-coherence-override.xml"
2013-02-08 11:24:19.601/2.728 Oracle Coherence 3.7.1.1 <D5> (thread=Main Thread, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.1 Build 28901
 Grid Edition: Production mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2013-02-08 11:24:19.916/3.043 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded cache configuration from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/security-cache-config.xml"
2013-02-08 11:24:20.393/3.520 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded Reporter configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/reports/report-group.xml"
2013-02-08 11:24:21.262/4.389 Oracle Coherence GE 3.7.1.1 <D4> (thread=Main Thread, member=n/a): TCMP bound to /192.168.1.150:8088 using SystemSocketProvider
2013-02-08 11:24:51.778/34.905 Oracle Coherence GE 3.7.1.1 <Info> (thread=Cluster, member=n/a): Created a new cluster "SecurityCoherenceCluster" with Member(Id=1, Timestamp=2013-02-08 11:24:21.331, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:7376, Role=CoherenceServer, Edition=Grid Edition, Mode=Production, CpuCount=4, SocketCount=1) UID=0xC0A801960000013CB9559D53FE391F98
2013-02-08 11:24:51.816/34.943 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Started cluster Name=SecurityCoherenceCluster

WellKnownAddressList(Size=1,
  WKA{Address=192.168.1.150, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2013-02-08 11:24:21.331, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:7376, Role=CoherenceServer)
  OldestMember=Member(Id=1, Timestamp=2013-02-08 11:24:21.331, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:7376, Role=CoherenceServer)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2013-02-08 11:24:21.331, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:7376, Role=CoherenceServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2013-02-08 11:24:51.783|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2013-02-08 11:24:51.944/35.071 Oracle Coherence GE 3.7.1.1 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2013-02-08 11:24:52.255/35.382 Oracle Coherence GE 3.7.1.1 <Info> (thread=DistributedCache, member=1): Loaded POF configuration from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/security-pof-config.xml"
2013-02-08 11:24:52.265/35.392 Oracle Coherence GE 3.7.1.1 <Info> (thread=DistributedCache, member=1): Loaded included POF configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/coherence-pof-config.xml"
2013-02-08 11:24:52.303/35.430 Oracle Coherence GE 3.7.1.1 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
2013-02-08 11:24:52.375/35.503 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=1):
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7.1, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  PartitionedCache{Name=DistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
  )

Started DefaultCacheServer...

2013-02-08 11:26:21.422/124.550 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-08 11:26:21.174, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:7442, Role=ModelTestTest) joined Cluster with senior member 1
2013-02-08 11:26:21.716/124.843 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2013-02-08 11:26:22.150/125.277 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service DistributedCache with senior member 1
[INFO ][mgmnt  ] Local JMX connector started
2013-02-08 13:07:05.135/6168.262 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2013-02-08 11:26:21.174, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:7442, Role=ModelTestTest) due to a peer departure; removing the member.
2013-02-08 13:07:05.139/6168.266 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2013-02-08 13:07:05.140/6168.267 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 left service DistributedCache with senior member 1
2013-02-08 13:07:05.144/6168.271 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-02-08 13:07:05.141, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:7442, Role=ModelTestTest) left Cluster with senior member 1

Luckily the communication issues are gone. To see what JRockit does on the operating system we again use vmstat and pmstat

[weblogic@middleware-magic ~]$ vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 5393884 155152 694208    0    0    20   209  715   26 29  2 68  1  0
[weblogic@middleware-magic ~]$ mpstat -P ALL
Linux 2.6.32-279.22.1.el6.x86_64 (middleware-magic.com) 	02/08/2013 	_x86_64_	(4 CPU)

01:08:01 PM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
01:08:01 PM  all   28.52    0.41    2.22    1.16    0.01    0.13    0.00    0.00   67.55
01:08:01 PM    0   27.03    0.60    2.38    1.15    0.01    0.13    0.00    0.00   68.71
01:08:01 PM    1   31.10    0.41    2.20    1.14    0.00    0.11    0.00    0.00   65.03
01:08:01 PM    2   28.10    0.31    2.28    1.28    0.00    0.14    0.00    0.00   67.89
01:08:01 PM    3   27.86    0.33    2.02    1.08    0.01    0.13    0.00    0.00   68.57

A remark is in order; the ‘Experienced a …ms communication delay’ messages also do not appear when the parallel collector (-XX:+UseParallelGC) settings are used, which can also be seen in the following measurements

Note the difference in garbage collection times between the G1 collector (the first two) and the parallel collector (the last two). The load test brakes about everything the G1 collector is designed for:

  • Operate concurrently with applications threads like the CMS collector.
  • Compact free space without lengthy GC induced pause times.
  • Need more predictable GC pause durations.
  • Do not want to sacrifice a lot of throughput performance.
  • Do not require a much larger Java heap.

Based on the measurements we will resort to the parallel collector and change the JVM parameters to the following for the WebLogic managed server

<server>
    <name>security-server</name>
    <ssl>
		<enabled>false</enabled>
    </ssl>
    <machine>machine1</machine>
    <listen-port>8001</listen-port>
    <cluster xsi:nil="true"></cluster>
    <web-server>
		<web-server-log>
			<number-of-files-limited>false</number-of-files-limited>
		</web-server-log>
    </web-server>
    <listen-address>middleware-magic.com</listen-address>
    <server-start>
		<java-vendor>Sun</java-vendor>
		<java-home>/home/weblogic/jdk1.7.0_11</java-home>
		<arguments>-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages -Dtangosol.coherence.mode=prod -Dtangosol.coherence.distributed.localstorage=false</arguments>
    </server-start>
  </server>

and to the following for the Coherence cache server

<coherence-server>
    <name>coherence-server1</name>
    <machine>machine1</machine>
    <coherence-cluster-system-resource xsi:nil="true"></coherence-cluster-system-resource>
    <unicast-listen-address>localhost</unicast-listen-address>
    <unicast-listen-port>8088</unicast-listen-port>
    <unicast-port-auto-adjust>true</unicast-port-auto-adjust>
    <coherence-server-start>
		<java-vendor>Sun</java-vendor>
		<java-home>/home/weblogic/jdk1.7.0_11</java-home>
		<class-path>/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules.coherence.server_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar</class-path>
		<arguments>-server -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:NewRatio=2 -XX:SurvivorRatio=128 -XX:MaxTenuringThreshold=0 -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages -Dtangosol.coherence.mode=prod -Dtangosol.coherence.cacheconfig=security-cache-config.xml -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true</arguments>
    </coherence-server-start>
  </coherence-server>

References

[1] Getting Started with the G1 Garbage Collector.
[2] Java Garbage Collection Basics.
[3] jHiccup: Open Source Tool to Measure Variations in Java Performance.


Coherence and WebLogic

In this post, we configure WebLogic and an in-memory data grid, such as Coherence and present scripts to start and stop the environment. We start with creating a Coherence Server (which will be our storage enabled node in the cluster). The steps to create a Coherence Server are provided here. When the server is created, click on the created server and subsequently on the server start, configuration tab, in order to set the class path and some JVM parameters. Enter the following properties:

  • Java Home: Specify the location of the JDK installation directory such that /bin/java exists, in our example we will use /home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0
  • Java Vendor: Oracle
  • Class Path: /home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar: /home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules.coherence.server_12.1.1.0.jar: /home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar
  • Arguments: -jrockit -Xms256m -Xmx256m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200m -XX:+UseCallProfiling -XX:+UseLargePagesForHeap -Dtangosol.coherence.mode=prod -Dtangosol.coherence.cacheconfig=security-cache-config.xml -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true

Above, we have specified the class path to included coherence.jar and weblogic.server.modules.coherence.server_12.1.1.0.jar, which are needed to make Coherence available. The test.jar contains our Coherence configuration and serializable classes. These are presented in the post JBoss RichFaces, Facelets and Coherence on WebLogic.

Note that the JVM parameters also included Coherence system settings, such as, -Dtangosol.coherence.mode=prod and -Dtangosol.coherence.cacheconfig=security-cache-config.xml. With the first one, we tell Coherence to run with production settings. The second one defines the cache configuration file to use. Unfortunately, the configuration provided in a Coherence override is not picked up.

<?xml version='1.0'?>
<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"       xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">
    <cluster-config>
        <member-identity>
            <cluster-name system-property="tangosol.coherence.cluster">SecurityCoherenceCluster</cluster-name>
        </member-identity>
        <unicast-listener>
            <well-known-addresses>
                <socket-address id="1">
                    <address>192.168.1.150</address>
                    <port>8088</port>
                </socket-address>
            </well-known-addresses>
        </unicast-listener>
    </cluster-config>
    <configurable-cache-factory-config>
        <class-name>com.tangosol.net.DefaultConfigurableCacheFactory</class-name>
        <init-params>
            <init-param>
                <param-type>java.lang.String</param-type>
                <param-value system-property="tangosol.coherence.cacheconfig">security-cache-config.xml</param-value>
            </init-param>
        </init-params>
    </configurable-cache-factory-config>
    <license-config>
        <license-mode system-property="tangosol.coherence.mode">prod</license-mode>
    </license-config>
</coherence>

But the well-known-address definition is (as we will shortly see when the server is started).

With the Coherence Server in place, something like the following should be present in the WebLogic configuration file (config.xml)

<coherence-server>
    <name>coherence-server1</name>
    <machine>machine1</machine>
    <coherence-cluster-system-resource xsi:nil="true"></coherence-cluster-system-resource>
    <unicast-listen-address>localhost</unicast-listen-address>
    <unicast-listen-port>8088</unicast-listen-port>
    <unicast-port-auto-adjust>true</unicast-port-auto-adjust>
    <coherence-server-start>
		<java-vendor>Oracle</java-vendor>
		<java-home>/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0</java-home>
		<class-path>/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules.coherence.server_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar</class-path>
		<arguments>-jrockit -Xms256m -Xmx256m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200m -XX:+UseCallProfiling -XX:+UseLargePagesForHeap -Dtangosol.coherence.mode=prod -Dtangosol.coherence.cacheconfig=security-cache-config.xml -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true</arguments>
    </coherence-server-start>
</coherence-server>

Before, we can start the Coherence Server, the node manager must be running (examples of stop and start scripts for the node manager can be found in the post WLST Starting and Stopping a WebLogic Environment). When the node manager is running, in the WebLogic admin console, click in the created server, click the control tab, select the Coherence Server and click start.

The output log is present in the ${DOMAIN_HOME}/servers_coherence/${COHERENCE_SERVER_NAME}/logs

<Jan 9, 2013 11:37:08 AM> <INFO> <NodeManager> <Starting Coherence server with command line: /home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0/bin/java -Dtangosol.coherence.member=coherence-server1 -Dtangosol.coherence.localport=8088 -Dtangosol.coherence.localhost=localhost -Djava.class.path=/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules.coherence.server_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar -jrockit -Xms256m -Xmx256m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200m -XX:+UseCallProfiling -XX:+UseLargePagesForHeap -Dtangosol.coherence.mode=prod -Dtangosol.coherence.cacheconfig=security-cache-config.xml -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true -Dweblogic.RootDirectory=/home/weblogic/weblogic12.1.1/configuration/domains/base_domain weblogic.nodemanager.server.provider.WeblogicCacheServer >
<Jan 9, 2013 11:37:08 AM> <INFO> <NodeManager> <Working directory is '/home/weblogic/weblogic12.1.1/configuration/domains/base_domain'>
<Jan 9, 2013 11:37:08 AM> <INFO> <NodeManager> <Server output log file is '/home/weblogic/weblogic12.1.1/configuration/domains/base_domain/servers_coherence/coherence-server1/logs/coherence-server1.out'>
2013-01-09 11:37:09.756/1.432 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence.xml"
2013-01-09 11:37:09.785/1.460 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational overrides from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/tangosol-coherence-override-prod.xml"
2013-01-09 11:37:09.803/1.478 Oracle Coherence 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded operational overrides from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/tangosol-coherence-override.xml"
2013-01-09 11:37:09.809/1.484 Oracle Coherence 3.7.1.1 <D5> (thread=Main Thread, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.1 Build 28901
 Grid Edition: Production mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2013-01-09 11:37:10.679/2.354 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Loaded Reporter configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/reports/report-group.xml"
2013-01-09 11:37:11.456/3.131 Oracle Coherence GE 3.7.1.1 <D4> (thread=Main Thread, member=n/a): TCMP bound to /192.168.1.150:8088 using SystemSocketProvider
2013-01-09 11:37:42.014/33.689 Oracle Coherence GE 3.7.1.1 <Info> (thread=Cluster, member=n/a): Created a new cluster "SecurityCoherenceCluster" with Member(Id=1, Timestamp=2013-01-09 11:37:11.526, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:5877,member:coherence-server1, Role=WeblogicWeblogicCacheServer, Edition=Grid Edition, Mode=Production, CpuCount=4, SocketCount=1) UID=0xC0A801960000013C1EE295E6FE391F98
2013-01-09 11:37:42.065/33.740 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=n/a): Started cluster Name=SecurityCoherenceCluster

WellKnownAddressList(Size=1,
  WKA{Address=192.168.1.150, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2013-01-09 11:37:11.526, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:5877,member:coherence-server1, Role=WeblogicWeblogicCacheServer)
  OldestMember=Member(Id=1, Timestamp=2013-01-09 11:37:11.526, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:5877,member:coherence-server1, Role=WeblogicWeblogicCacheServer)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2013-01-09 11:37:11.526, Address=192.168.1.150:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:5877,member:coherence-server1, Role=WeblogicWeblogicCacheServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2013-01-09 11:37:42.019|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2013-01-09 11:37:42.195/33.870 Oracle Coherence GE 3.7.1.1 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2013-01-09 11:37:42.428/34.103 Oracle Coherence GE 3.7.1.1 <Info> (thread=DistributedCache, member=1): Loaded POF configuration from "jar:file:/home/weblogic/weblogic12.1.1/configuration/applications/base_domain/security/test.jar!/security-pof-config.xml"
2013-01-09 11:37:42.436/34.111 Oracle Coherence GE 3.7.1.1 <Info> (thread=DistributedCache, member=1): Loaded included POF configuration from "jar:file:/home/weblogic/weblogic12.1.1/installation/coherence_3.7/lib/coherence.jar!/coherence-pof-config.xml"
2013-01-09 11:37:42.545/34.220 Oracle Coherence GE 3.7.1.1 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
2013-01-09 11:37:42.627/34.302 Oracle Coherence GE 3.7.1.1 <Info> (thread=Main Thread, member=1):
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7.1, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  PartitionedCache{Name=DistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
  )

Started DefaultCacheServer...

The application (presented in the post JBoss RichFaces, Facelets and Coherence on WebLogic, which also includes details on how to create shared libraries) will be deployed on a WebLogic managed server with the following settings

<server>
    <name>security-server</name>
    <ssl>
		<enabled>false</enabled>
    </ssl>
    <machine>machine1</machine>
    <listen-port>8001</listen-port>
    <cluster xsi:nil="true"></cluster>
    <web-server>
		<web-server-log>
			<number-of-files-limited>false</number-of-files-limited>
		</web-server-log>
    </web-server>
    <listen-address>middleware-magic.com</listen-address>
    <server-start>
		<java-vendor>Oracle</java-vendor>
		<java-home>/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0</java-home>
		<arguments>-jrockit -Xms512m -Xmx512m -Xns128m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -XX:+UseCallProfiling -XX:+UseLargePagesForHeap -Dtangosol.coherence.mode=prod -Dtangosol.coherence.distributed.localstorage=false</arguments>
    </server-start>
</server>

Note that this server has the storage disabled (-Dtangosol.coherence.distributed.localstorage=false). The cache configuration is set here by using a Coherence override as was present above. When the WebLogic server and the application are started, the following is observed in the Coherence Server logging

2013-01-09 11:44:19.563/431.240 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2013-01-09 11:44:19.326, Address=192.168.1.150:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:3852, Role=WeblogicServer) joined Cluster with senior member 1
2013-01-09 11:44:19.658/431.334 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2013-01-09 11:44:19.710/431.385 Oracle Coherence GE 3.7.1.1 <D5> (thread=Cluster, member=1): Member 2 joined Service DistributedCache with senior member 1

To monitor the Coherence cache server, we have added -Dtangosol.coherence.management=all and -Dtangosol.coherence.management.remote=true as JVM parameters. By using an MBean browser (for example, JRockit Mission Control), we get an idea what is going on in the server

In order to start and stop the Coherence cache servers we can use WLST. The CoherenceServerLifeCycleRuntimeMBean provides methods that transition servers from one state to another. This class is instantiated only on the Admin Server, but we can use it to transition the states of all managed Coherence cache servers. To start Coherence cache servers, we must first configure a Node Manager on each Coherence cache server’s host machine. In order to start Coherence cache servers we can use the following script:

import socket;
admin_server_listen_address = socket.gethostname();
admin_server_url = 't3://' + admin_server_listen_address + ':' + admin_server_listen_port;

print 'CONNECT TO ADMIN SERVER';

connect(admin_username, admin_password, admin_server_url);

domainRuntime();
coherence_server_lifecycles = cmo.getCoherenceServerLifeCycleRuntimes();

for coherence_server_lifecycle in coherence_server_lifecycles:
	if (coherence_server_lifecycle.getState() != 'RUNNING'):
		print 'START COHERENCE SERVER ' + coherence_server_lifecycle.getName();
		task = coherence_server_lifecycle.start();
		while (task.isRunning() == 1):
			print 'STARTING COHERENCE SERVER ' + coherence_server_lifecycle.getName();
			java.lang.Thread.sleep(2000);

print 'DISCONNECT FROM THE ADMIN SERVER';
disconnect();

and the following bash script

#!/bin/sh

# SCRIPT_PATH=$(dirname $0)
SCRIPT=$(readlink -f $0)
SCRIPT_PATH=$(dirname $SCRIPT)

. ${SCRIPT_PATH}/SetEnvironment.sh

${WL_HOME}/common/bin/wlst.sh -loadProperties ${SCRIPT_PATH}/environment.properties ${SCRIPT_PATH}/startCoherence.py

When this script is run the following output is observed

[weblogic@middleware-magic scripts]$ ./CoherenceStartService.sh 

CLASSPATH=/home/weblogic/weblogic12.1.1/installation/patch_wls1211/profiles/default/sys_manifest_classpath/weblogic_patch.jar:/home/weblogic/weblogic12.1.1/installation/patch_ocp371/profiles/default/sys_manifest_classpath/weblogic_patch.jar:/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0/lib/tools.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/server/lib/weblogic_sp.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/server/lib/weblogic.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/server/lib/webservices.jar:/home/weblogic/weblogic12.1.1/installation/modules/org.apache.ant_1.7.1/lib/ant-all.jar:/home/weblogic/weblogic12.1.1/installation/modules/net.sf.antcontrib_1.1.0.0_1-0b2/lib/ant-contrib.jar::/home/weblogic/weblogic12.1.1/installation/utils/config/10.3/config-launch.jar::/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/common/derby/lib/derbynet.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/common/derby/lib/derbyclient.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/common/derby/lib/derbytools.jar::

Initializing WebLogic Scripting Tool (WLST) ...

Welcome to WebLogic Server Administration Scripting Shell

Type help() for help on available commands

CONNECT TO ADMIN SERVER
Connecting to t3://middleware-magic.com:7001 with userid weblogic ...
Successfully connected to Admin Server 'AdminServer' that belongs to domain 'base_domain'.

Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.

Location changed to domainRuntime tree. This is a read-only tree with DomainMBean as the root.
For more help, use help(domainRuntime)

START COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
STARTING COHERENCE SERVER coherence-server1
DISCONNECT FROM THE ADMIN SERVER
Disconnected from weblogic server: AdminServer

To stop Coherence cache servers we can use

import socket;
admin_server_listen_address = socket.gethostname();
admin_server_url = 't3://' + admin_server_listen_address + ':' + admin_server_listen_port;

print 'CONNECT TO ADMIN SERVER';

connect(admin_username, admin_password, admin_server_url);

domainRuntime();
coherence_server_lifecycles = cmo.getCoherenceServerLifeCycleRuntimes();

for coherence_server_lifecycle in coherence_server_lifecycles:
	if (coherence_server_lifecycle.getState() == 'RUNNING'):
		print 'SHUT DOWN COHERENCE SERVER ' + coherence_server_lifecycle.getName();
		task = coherence_server_lifecycle.forceShutdown();
		while (task.isRunning() == 1):
			print 'SHUTTING DOWN COHERENCE SERVER ' + coherence_server_lifecycle.getName();
			java.lang.Thread.sleep(2000);

print 'DISCONNECT FROM THE ADMIN SERVER';
disconnect();

with the following bash script

#!/bin/sh

# SCRIPT_PATH=$(dirname $0)
SCRIPT=$(readlink -f $0)
SCRIPT_PATH=$(dirname $SCRIPT)

. ${SCRIPT_PATH}/SetEnvironment.sh

${WL_HOME}/common/bin/wlst.sh -loadProperties ${SCRIPT_PATH}/environment.properties ${SCRIPT_PATH}/stopCoherence.py

When this script is run the following output is observed

[weblogic@middleware-magic scripts]$ ./CoherenceStopService.sh 

CLASSPATH=/home/weblogic/weblogic12.1.1/installation/patch_wls1211/profiles/default/sys_manifest_classpath/weblogic_patch.jar:/home/weblogic/weblogic12.1.1/installation/patch_ocp371/profiles/default/sys_manifest_classpath/weblogic_patch.jar:/home/weblogic/jrockit-jdk1.6.0_29-R28.2.2-4.1.0/lib/tools.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/server/lib/weblogic_sp.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/server/lib/weblogic.jar:/home/weblogic/weblogic12.1.1/installation/modules/features/weblogic.server.modules_12.1.1.0.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/server/lib/webservices.jar:/home/weblogic/weblogic12.1.1/installation/modules/org.apache.ant_1.7.1/lib/ant-all.jar:/home/weblogic/weblogic12.1.1/installation/modules/net.sf.antcontrib_1.1.0.0_1-0b2/lib/ant-contrib.jar::/home/weblogic/weblogic12.1.1/installation/utils/config/10.3/config-launch.jar::/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/common/derby/lib/derbynet.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/common/derby/lib/derbyclient.jar:/home/weblogic/weblogic12.1.1/installation/wlserver_12.1/common/derby/lib/derbytools.jar::

Initializing WebLogic Scripting Tool (WLST) ...

Welcome to WebLogic Server Administration Scripting Shell

Type help() for help on available commands

CONNECT TO ADMIN SERVER
Connecting to t3://middleware-magic.com:7001 with userid weblogic ...
Successfully connected to Admin Server 'AdminServer' that belongs to domain 'base_domain'.

Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.

Location changed to domainRuntime tree. This is a read-only tree with DomainMBean as the root.
For more help, use help(domainRuntime)

SHUT DOWN COHERENCE SERVER coherence-server1
SHUTTING DOWN COHERENCE SERVER coherence-server1
DISCONNECT FROM THE ADMIN SERVER
Disconnected from weblogic server: AdminServer

This is certainly a step in the right direction to integrate data-grids with application servers. Some more information on where it is going have a look at the Coherence Roadmap, or what do you think about this one: Grid Archive.

References

[1] Using ActiveCache.


High Availability and Polyglot Persistence

When we set-up a system that needs to be highly available, it is good to first analyze how your environment is structured. That is look at what components in the environment can be treated in a different way, such that we can set-up a high available environment in a cost-effective way.

Say, we have an environment in which we are using JMS and a Data Source in one transaction (for the transactions we will use JTA). Now, we have certain options in this environment, say, for example, it is decided that the a message must be processed no matter what. In this case we have to set-up a JMS environment that can persist its messages in case of failures. To persist messages we have two options. It can either be persisted into a database or we can persist it on a file system. Note that in both cases the persistence environment must be highly available as well. To top this we also want that the transactions can go on in the case of server failures. Note that in this case we are dealing we a very complex environment, i.e.,

  • The system must support global transactions between local and distributed resources such as JMS destinations and databases.
  • JMS messages are persisted to the file system and must support fail-over and be highly available.
  • Fail-over of both the node and any WebLogic Server instance specific functionality, such as JMS destinations and JTA transaction recovery, must take place transparently.
  • Distributed transactions must be recoverable and restarted in case of node or WebLogic Server failure.

Data, for example, is only one component of availability; all layers of the system must be available and resilient to failures, which usually means that we have to provide redundancy at all layers (shared storage, operating system, network).

Usually it is possible to reduce the availability requirements for certain components in the environment, which can lead to much simpler cluster, for example,

  • No disk-sharing requirements across the cluster.
  • Data storage does not require high availability.
  • Applications do not use, or participate in, XA transactions because the transaction logs will typically require high availability and fail-over
    • In certain situations last agent optimization may be an appropriate way to relax this constraint.
  • The applications do not use file-based JMS persistent messages because the JMS message stores will typically require high availability and fail-over.

When building (and deploying) an application we can also ask: Are there parts that can be treated differently? For example, split the application into parts that need to be highly available and parts that need to be continuously available. In the case of highly available systems we can live with a down time of a few hours. Continuous available systems, on the other hand, must be up and running within minutes, which means we need to have easily manageable system components. When the application is data-centric it pays off to analyze how data is managed. What type of data model do we need? Do we need a tabular model, i.e., pick data apart and re-assemble it in different ways for different purposes or are there other wishes?

In the example above, the distinction between highly and continuous availability, when we deploy the application as a whole we end-up with a very complex environment in which all the layers (storage etcetera) must be treated as to be continuous available. Here, we started to look if we could design the architecture in such a way that components can be treated differently. A way to treat the components differently is by looking at how data is used. Certain parts queried lots of data in various ways, but with very few transactions. Another point that could be made on these components is that they are not mission critical, such that they can be treated to be only highly available (we can live with a downtime of a few hours). The mission critical component is highly transactional and just queries by id. In the latter case you can ask yourself is a database the ideal solution? What we did is let the mission critical component communicate to a data-grid (in this case Coherence) instead of the database.

Some time later we came across a term called Polyglot Persistence, and started to think hey there is a term for what we are doing. The philosophy of Polyglot Persistence is using multiple data storage technologies, chosen based upon the way data is being used by individual applications. By looking at component boundaries we can choose a particular storage technology chosen for the way the data is manipulated.

When using, for example, a data-grid other components that use the data must be able to deal with a paradigm called eventual consistency. For example, in the case of data-grid such as Coherence, we can set-up cache-store that eventually put the data into a data store. Other applications that use the data store must some how deal with stale data, as new data is held in the data-grid that is written to the data store when the time is ripe. In the case of a traffic control system that notifies passengers with travel information, this is not really a problem, but in a health monitoring system of hospitals it is. Thus, based on the system to be build we can decide what type of persistence best fits our needs and also set-up a cost-effective environment.

Coherence Course

One downside of using, for example, a data-grid such as Coherence is that developers must learn a new interface. To make this possible they asked to set-up a course in Coherence. To let everybody in on something as powerful (and beautiful) as Coherence, I decided to make the material public. In the course you will learn the following:

  • Introduction
  • Object Serialization
  • Configuring the Cache
  • Querying the Cache
  • Cache-aside Architecture
  • Read-through / Write-behind Architecture
  • Cache Events and Parallel Processing

Note that this is a course you can do at your own pace. The exercises lead you step-by-step through the process of building applications that uses Coherence. The material consists of the following:

References

[1] The future is Polyglot Persistence.


Hibernate4 and Coherence

There are two ways to integrate Hibernate and Coherence:

  • Coherence can be used as a second level cache provider for Hibernate.
  • Hibernate can be used as a CacheStore provider for Coherence.

In the case Coherence is used as a second level cache provider for Hibernate, Coherence caching is fully controlled by Hibernate; thus a good understanding of Hibernate caching mechanisms is required. This scenario is a good fit for applications that:

  • Use Hibernate APIs for the data access management.
  • Have complex object models.
  • Have fine-grained transactional requirements.
  • Have an application server cluster that run the Hibernate application.

The set-up using Hibernate3 can be found in the post Hibernate and Coherence. Note that in the case of Hibernate3 we provided implementations for the interfaces org.hibernate.cache.Cache and org.hibernate.cache.CacheProvider. In Hibernate4 this concepts has been changed to a more fine grained implementation structure, for example,

  • At the top we have an implementation for the RegionFactory interface. This implementation defines how to start and stop the cache, sets some defaults (such as if minimal puts are enabled and the access type) and defines the region implementation. It is now possible to define separate implementation for entities and collections etcetera.
    • How entities or collections are cached are defined by implementing regions, such as, EntityRegion – Defines the contract for a cache region which will specifically be used to store entity data. CollectionRegion – Defines the contract for a cache region which will specifically be used to store collection data. The region contracts define an access strategy for the requested access type.
      • To define how the caching is handled we implement the following three interfaces:
        • TransactionalDataRegion – Defines the contract for regions which hold transactionally-managed data.
        • GeneralDataRegion – Contract for general-purpose cache regions.
        • Region – Defines a contract for accessing a particular named region within the underlying cache implementation.

Let us look at an example of how to implement the various interfaces in the case we are dealing with an entity. Our entity looks as follows:

package model.entities;

import java.io.Serializable;

public class Department implements Serializable {

    private Integer departmentNumber;
    private String departmentName;
    private String location;

    public Department() {
    }

    public void setDepartmentNumber(Integer departmentNumber) {
        this.departmentNumber = departmentNumber;
    }

    public Integer getDepartmentNumber() {
        return departmentNumber;
    }

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }

    public String getDepartmentName() {
        return departmentName;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getLocation() {
        return location;
    }

    @Override
    public boolean equals(Object object) {
        System.out.println("DEPARTMENT EQUALS METHOD CALLED " + object);
        if (this == object) {
            return true;
        }

        if (object == null) {
            return false;
        }

        if (!(object instanceof Department)) {
            return false;
        }

        Department department = (Department) object;
        return departmentNumber.equals(department.getDepartmentNumber());
    }

    @Override
    public int hashCode() {
        if (departmentNumber != null) {
            return 31 * departmentNumber.hashCode();
        } else {
            return System.identityHashCode(this);
        }
    }

    @Override
    public String toString() {
        return departmentName + ", " + location;
    }
}

which has the following mapping

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="model.entities">
    <class name="Department" table="DEPT">
        <id name="departmentNumber" type="integer" column="DEPTNO">
            <generator class="assigned"/>
        </id>
        <property name="departmentName" type="string" column="DNAME"/>
        <property name="location" type="string" column="LOC"/>
    </class>
</hibernate-mapping>

We start with defining the contract for accessing a particular named region within the underlying cache implementation, by providing an implementation for the org.hibernate.cache.spi.Region interface

package cache.regions;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.Region;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class CoherenceRegion implements Region {

    private final NamedCache cache;

    public CoherenceRegion(NamedCache cache) {
        this.cache = cache;
    }

    public NamedCache getCache() {
        return cache;
    }

    public String getName() {
        return cache.getCacheName();
    }

    public void destroy() throws CacheException {
        cache.release();
    }

    public boolean contains(Object key) {
        System.out.println("LOOK IF DATA IS IN THE CACHE " + key);
        return cache.containsKey(key);
    }

    public long getSizeInMemory() {
        return -1;
    }

    public long getElementCountInMemory() {
        long size = 0;
        try {
            size = cache.size();
        } catch (CacheException ex) {
            throw new CacheException(ex);
        }
        return size;
    }

    public long getElementCountOnDisk() {
        return -1;
    }

    public Map toMap() {
        Map result = new HashMap();
        try {
            Iterator iterator = cache.keySet().iterator();
            while (iterator.hasNext()) {
                Object key = iterator.next();
                result.put(key, cache.get((Serializable) key));
            }
        } catch (Exception ex) {
            throw new CacheException(ex);
        }
        return result;
    }

    public long nextTimestamp() {
        return CacheFactory.getCluster().getTimeMillis();
    }

    public int getTimeout() {
        return 10000;
    }
}

Next, we provide the contract for general-purpose cache regions (i.e. how to get, put and remove data from the cache), by implementing the org.hibernate.cache.spi.GeneralDataRegion interface

package cache.regions;

import com.tangosol.net.NamedCache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.GeneralDataRegion;

public class CoherenceGeneralDataRegion extends CoherenceRegion implements GeneralDataRegion {

    public CoherenceGeneralDataRegion(NamedCache cache) {
        super(cache);
    }

    public Object get(Object key) throws CacheException {
        System.out.println("GET DATA FROM THE CACHE " + key);
        return getCache().get(key);
    }

    public void put(Object key, Object value) throws CacheException {
        System.out.println("PUT DATA INTO THE CACHE " + key + ", " + value);
        getCache().put(key, value);
    }

    public void evict(Object key) throws CacheException {
        System.out.println("REMOVE DATA FROM THE CACHE " + key);
        getCache().remove(key);
    }

    public void evictAll() throws CacheException {
        getCache().clear();
    }
}

Subsequently, we define the contract for regions which hold transactionally-managed data, by implementing the org.hibernate.cache.spi.TransactionalDataRegion interface

package cache.regions;

import com.tangosol.net.NamedCache;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.TransactionalDataRegion;

public class CoherenceTransactionalDataRegion extends CoherenceGeneralDataRegion implements TransactionalDataRegion {

    private final CacheDataDescription metadata;

    public CoherenceTransactionalDataRegion(NamedCache cache, CacheDataDescription metadata) {
        super(cache);
        this.metadata = metadata;
    }

    public boolean isTransactionAware() {
        return false;
    }

    public CacheDataDescription getCacheDataDescription() {
        return metadata;
    }
}

As a final step we need to build the contract for a cache region which will specifically be used to store entity data (and define which access type to use), by implementing the org.hibernate.cache.spi.EntityRegion interface

package cache.regions;

import cache.strategy.CoherenceNonStrictReadWriteEntityRegionAccessStrategy;
import com.tangosol.net.NamedCache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;

public class CoherenceEntityRegion extends CoherenceTransactionalDataRegion implements EntityRegion {

    public CoherenceEntityRegion(NamedCache cache, CacheDataDescription metadata) {
        super(cache, metadata);
    }

    public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
        switch (accessType) {
            case NONSTRICT_READ_WRITE:
                return new CoherenceNonStrictReadWriteEntityRegionAccessStrategy(this);
            default:
                throw new IllegalArgumentException("unrecognized access strategy type [" + accessType + "]");
        }
    }
}

In the implementation above, we assume the access strategy always to be non-strict read-write. There are four access strategies that can be used:

  • Read only – If the application needs to read, but not modify, instances of a persistent class, a read-only cache can be used. This is the simplest and optimal performing strategy. It is even safe for use in a cluster.
  • Read/write – If the application needs to update data, a read-write cache might be appropriate. This cache strategy should never be used if serializable transaction isolation level is required. If the cache is used in a JTA environment, you must specify the property hibernate.transaction.manager_lookup_class and naming a strategy for obtaining the JTA TransactionManager. In other environments, you should ensure that the transaction is completed when Session.close() or Session.disconnect() is called. If you want to use this strategy in a cluster, you should ensure that the underlying cache implementation supports locking.
  • Non-strict read/write – If the application only occasionally needs to update data (i.e. if it is extremely unlikely that two transactions would try to update the same item simultaneously), and strict transaction isolation is not required, a non-strict-read-write cache might be appropriate. If the cache is used in a JTA environment, you must specify hibernate.transaction.manager_lookup_class. In other environments, you should ensure that the transaction is completed when Session.close() or Session.disconnect() is called.
  • Transactional – The transactional cache strategy provides support for fully transactional cache providers. Such a cache can only be used in a JTA environment and you must specify hibernate.transaction.manager_lookup_class.

To define the contract for transactional and concurrent access to cached entity (and collection) data, we start by implementing the RegionAccessStrategy interface

package cache.strategy;

import cache.regions.CoherenceEntityRegion;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.RegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;

public class CoherenceEntityRegionAccessStrategy implements RegionAccessStrategy {

    private final CoherenceEntityRegion coherenceEntityRegion;

    public CoherenceEntityRegionAccessStrategy(CoherenceEntityRegion coherenceEntityRegion) {
        this.coherenceEntityRegion = coherenceEntityRegion;
    }

    public CoherenceEntityRegion getCoherenceEntityRegion() {
        return coherenceEntityRegion;
    }

    public Object get(Object key, long transactionTimeStamp) throws CacheException {
        return getCoherenceEntityRegion().get(key);
    }

    public boolean putFromLoad(Object key, Object value, long transactionTimeStamp, Object version) throws CacheException {
        return putFromLoad(key, value, transactionTimeStamp, version, true);
    }

    public boolean putFromLoad(Object key, Object value, long transationTimeStamp, Object version, boolean minimalPutsOverride) throws CacheException {
        if (key == null || value == null) {
            return false;
        }

        // check if item is already in the cache
        if (minimalPutsOverride && getCoherenceEntityRegion().contains(key)) {
            return false;
        }

        // key is cached
        getCoherenceEntityRegion().put(key, value);
        return true;
    }

    public SoftLock lockItem(Object key, Object version) throws CacheException {
        getCoherenceEntityRegion().getCache().lock(key);
        return null;
    }

    public SoftLock lockRegion() throws CacheException {
        return null;
    }

    public void unlockItem(Object key, SoftLock softLock) throws CacheException {
        getCoherenceEntityRegion().getCache().unlock(key);
    }

    public void unlockRegion(SoftLock softLock) throws CacheException {
        evictAll();
    }

    public void remove(Object key) throws CacheException {
        evict(key);
    }

    public void removeAll() throws CacheException {
        evictAll();
    }

    public void evict(Object key) throws CacheException {
        getCoherenceEntityRegion().evict(key);
    }

    public void evictAll() throws CacheException {
        getCoherenceEntityRegion().evictAll();
    }
}

Finally, we define the contract for managing transactional and concurrent access to cached entity data, by implementing the EntityRegionAccessStrategy interface

package cache.strategy;

import cache.regions.CoherenceEntityRegion;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;

public class CoherenceNonStrictReadWriteEntityRegionAccessStrategy extends CoherenceEntityRegionAccessStrategy implements EntityRegionAccessStrategy {

    public CoherenceNonStrictReadWriteEntityRegionAccessStrategy(CoherenceEntityRegion region) {
        super(region);
    }

    public EntityRegion getRegion() {
        return getCoherenceEntityRegion();
    }

    public boolean insert(Object key, Object value, Object version) throws CacheException {
        return false;
    }

    public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
        return false;
    }

    public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException {
        return false;
    }

    public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock softLock) throws CacheException {
        return false;
    }
}

To make sure Hibernate uses a second-level cache, we use the following configuration

<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- Database connection settings -->
        <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
        <property name="hibernate.connection.url">jdbc:oracle:thin:@192.168.1.60:1521:orcl11</property>
        <property name="hibernate.connection.username">example</property>
        <property name="hibernate.connection.password">example</property>
        <!-- SQL dialect -->
        <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
        <!-- Enable Hibernate's automatic session context management -->
        <property name="hibernate.current_session_context_class">thread</property>
        <!-- Second-level cache config -->
        <property name="hibernate.cache.region.factory_class">cache.CoherenceRegionFactory</property>
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <!-- Echo all executed SQL to stdout -->
        <property name="hibernate.show_sql">false</property>
        <property name="hibernate.format_sql">false</property>
        <!-- Configure SessionFactory -->
        <mapping resource="model/entities/Department.hbm.xml"/>
        <!-- Cache configuration-->
        <class-cache class="model.entities.Department" usage="nonstrict-read-write"/>
    </session-factory>
</hibernate-configuration>

For the Coherence cache configuration we have used the following

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>hibernate-replicated</scheme-name>
            <init-params>
                <init-param>
                    <param-name>size-limit</param-name>
                    <param-value>1000</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <replicated-scheme>
            <scheme-name>hibernate-replicated</scheme-name>
            <service-name>HibernateReplicatedCache</service-name>
            <serializer>
                <instance>
                    <class-name>com.tangosol.io.DefaultSerializer</class-name>
                </instance>
            </serializer>
            <backing-map-scheme>
                <local-scheme>
                    <high-units>{size-limit 0}</high-units>
                </local-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </replicated-scheme>
    </caching-schemes>
</cache-config>

Now let us test the set-up, by using the following

package model.test;

import model.entities.Department;
import model.logic.DepartmentDAO;
import model.logic.DepartmentDAOBean;

import java.util.List;
import java.util.Random;

public class Test {

    public static void main(String[] args) {
        DepartmentDAO departmentDAO = new DepartmentDAOBean();
        //doRandomTest(departmentDAO);
        doPersistenceTest(departmentDAO);
    }

    private static void doRandomTest(DepartmentDAO departmentDAO) {
        Integer[] integers = {10, 20, 30, 40};
        Random random = new Random();
        while (true) {
            departmentDAO.findEntity(integers[random.nextInt(4)]);
        }
    }

    private static void doPersistenceTest(DepartmentDAO departmentDAO) {
        Integer departmentNumber = 12;
        Department newDepartment = createDepartment(departmentNumber, "SOMEDEPARTMENT", "SOMEWHERE");

        System.out.println("ADD DEPARTMENT ENTITY");
        departmentDAO.addEntity(newDepartment);

        System.out.println("FIND DEPARTMENT ENTITY");
        Department department = departmentDAO.findEntity(20);
        System.out.println("FIND ENTITY " + department);

        System.out.println("FIND DEPARTMENT ENTITIES");
        List<Department> departments = departmentDAO.findEntities();
        System.out.println("FIND ENTITIES " + departments);

        System.out.println("UPDATE DEPARTMENT ENTITY");
        newDepartment.setDepartmentName("Else");
        departmentDAO.updateEntity(newDepartment);

        System.out.println("FIND DEPARTMENT ENTITIES");
        departments = departmentDAO.findEntities();
        System.out.println("FIND ENTITIES " + departments);

        System.out.println("REMOVE DEPARTMENT ENTITY");
        departmentDAO.removeEntity(departmentNumber);

        System.out.println("FIND DEPARTMENT ENTITIES");
        departments = departmentDAO.findEntities();
        System.out.println("FIND ENTITIES " + departments);
    }

    private static Department createDepartment(Integer departmentNumber, String departmentName, String location) {
        Department department = new Department();
        department.setDepartmentNumber(departmentNumber);
        department.setDepartmentName(departmentName);
        department.setLocation(location);
        return department;
    }
}

When we run the test (with also the JVM parameters -Dtangosol.coherence.cacheconfig=hibernate-cache-config.xml -Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true) the following is observed

ADD DEPARTMENT ENTITY
Jun 21, 2012 2:01:45 PM org.hibernate.annotations.common.Version <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.1.Final}
Jun 21, 2012 2:01:45 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.1.2.Final}
Jun 21, 2012 2:01:45 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Jun 21, 2012 2:01:45 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Jun 21, 2012 2:01:45 PM org.hibernate.cfg.Configuration configure
INFO: HHH000043: Configuring from resource: /hibernate.cfg.xml
Jun 21, 2012 2:01:45 PM org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: HHH000040: Configuration resource: /hibernate.cfg.xml
Jun 21, 2012 2:01:45 PM org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
WARN: HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
Jun 21, 2012 2:01:45 PM org.hibernate.cfg.Configuration addResource
INFO: HHH000221: Reading mappings from resource: model/entities/Department.hbm.xml
Jun 21, 2012 2:01:45 PM org.hibernate.internal.util.xml.DTDEntityResolver resolveEntity
WARN: HHH000223: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/. Use namespace http://www.hibernate.org/dtd/ instead. Refer to Hibernate 3.6 Migration Guide!
Jun 21, 2012 2:01:45 PM org.hibernate.cfg.Configuration doConfigure
INFO: HHH000041: Configured SessionFactory: null
Jun 21, 2012 2:01:45 PM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000402: Using Hibernate built-in connection pool (not for production use!)
Jun 21, 2012 2:01:45 PM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000115: Hibernate connection pool size: 20
Jun 21, 2012 2:01:45 PM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000006: Autocommit mode: false
Jun 21, 2012 2:01:45 PM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000401: using driver [oracle.jdbc.OracleDriver] at URL [jdbc:oracle:thin:@192.168.1.60:1521:orcl11]
Jun 21, 2012 2:01:45 PM org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000046: Connection properties: {user=example, password=****}
Jun 21, 2012 2:01:45 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.Oracle10gDialect
Jun 21, 2012 2:01:45 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
Jun 21, 2012 2:01:45 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
2012-06-21 14:01:45.830/0.864 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/temp/frameworks/VoorbeeldSecondLevelCacheHibernate4/lib/coherence/coherence.jar!/tangosol-coherence.xml"
2012-06-21 14:01:45.861/0.895 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/temp/frameworks/VoorbeeldSecondLevelCacheHibernate4/lib/coherence/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-06-21 14:01:45.861/0.895 Oracle Coherence 3.7.1.0 <D5> (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-override.xml" is not specified
2012-06-21 14:01:45.863/0.897 Oracle Coherence 3.7.1.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2012-06-21 14:01:45.996/1.030 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded Reporter configuration from "jar:file:/C:/temp/frameworks/VoorbeeldSecondLevelCacheHibernate4/lib/coherence/coherence.jar!/reports/report-group.xml"
2012-06-21 14:01:46.408/1.442 Oracle Coherence GE 3.7.1.0 <D4> (thread=main, member=n/a): TCMP bound to /192.168.238.1:8088 using SystemSocketProvider
2012-06-21 14:01:49.759/4.794 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0xFCDB" with Member(Id=1, Timestamp=2012-06-21 14:01:46.513, Address=192.168.238.1:8088, MachineId=949, Location=site:,machine:r-PC,process:200, Role=IntellijRtExecutionAppMain, Edition=Grid Edition, Mode=Development, CpuCount=8, SocketCount=8) UID=0xC0A8EE01000001380EEB6E1103B51F98
2012-06-21 14:01:49.767/4.801 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0xFCDB

Group{Address=224.3.7.0, Port=37000, TTL=4}

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2012-06-21 14:01:46.513, Address=192.168.238.1:8088, MachineId=949, Location=site:,machine:r-PC,process:200, Role=IntellijRtExecutionAppMain)
  OldestMember=Member(Id=1, Timestamp=2012-06-21 14:01:46.513, Address=192.168.238.1:8088, MachineId=949, Location=site:,machine:r-PC,process:200, Role=IntellijRtExecutionAppMain)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2012-06-21 14:01:46.513, Address=192.168.238.1:8088, MachineId=949, Location=site:,machine:r-PC,process:200, Role=IntellijRtExecutionAppMain)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2012-06-21 14:01:49.76|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2012-06-21 14:01:49.826/4.860 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-06-21 14:01:49.906/4.940 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=1): Loaded cache configuration from "file:/C:/temp/frameworks/VoorbeeldSecondLevelCacheHibernate4/out/production/VoorbeeldSecondLevelCacheHibernate4/hibernate-cache-config.xml"
2012-06-21 14:01:49.943/4.977 Oracle Coherence GE 3.7.1.0 <D5> (thread=ReplicatedCache:HibernateReplicatedCache, member=1): Service HibernateReplicatedCache joined the cluster with senior service member 1
FIND DEPARTMENT ENTITY
GET DATA FROM THE CACHE model.entities.Department#20
LOOK IF DATA IS IN THE CACHE model.entities.Department#20
PUT DATA INTO THE CACHE model.entities.Department#20, CacheEntry(model.entities.Department)[RESEARCH,DALLAS]
FIND ENTITY RESEARCH, DALLAS
FIND DEPARTMENT ENTITIES
LOOK IF DATA IS IN THE CACHE model.entities.Department#10
PUT DATA INTO THE CACHE model.entities.Department#10, CacheEntry(model.entities.Department)[ACCOUNTING,NEW YORK]
LOOK IF DATA IS IN THE CACHE model.entities.Department#20
LOOK IF DATA IS IN THE CACHE model.entities.Department#30
PUT DATA INTO THE CACHE model.entities.Department#30, CacheEntry(model.entities.Department)[SALES,CHICAGO]
LOOK IF DATA IS IN THE CACHE model.entities.Department#40
PUT DATA INTO THE CACHE model.entities.Department#40, CacheEntry(model.entities.Department)[OPERATIONS,BOSTON]
LOOK IF DATA IS IN THE CACHE model.entities.Department#12
PUT DATA INTO THE CACHE model.entities.Department#12, CacheEntry(model.entities.Department)[SOMEDEPARTMENT,SOMEWHERE]
FIND ENTITIES [ACCOUNTING, NEW YORK, RESEARCH, DALLAS, SALES, CHICAGO, OPERATIONS, BOSTON, SOMEDEPARTMENT, SOMEWHERE]
UPDATE DEPARTMENT ENTITY
FIND DEPARTMENT ENTITIES
LOOK IF DATA IS IN THE CACHE model.entities.Department#10
LOOK IF DATA IS IN THE CACHE model.entities.Department#20
LOOK IF DATA IS IN THE CACHE model.entities.Department#30
LOOK IF DATA IS IN THE CACHE model.entities.Department#40
LOOK IF DATA IS IN THE CACHE model.entities.Department#12
FIND ENTITIES [ACCOUNTING, NEW YORK, RESEARCH, DALLAS, SALES, CHICAGO, OPERATIONS, BOSTON, Else, SOMEWHERE]
REMOVE DEPARTMENT ENTITY
GET DATA FROM THE CACHE model.entities.Department#12
REMOVE DATA FROM THE CACHE model.entities.Department#12
FIND DEPARTMENT ENTITIES
LOOK IF DATA IS IN THE CACHE model.entities.Department#10
LOOK IF DATA IS IN THE CACHE model.entities.Department#20
LOOK IF DATA IS IN THE CACHE model.entities.Department#30
LOOK IF DATA IS IN THE CACHE model.entities.Department#40
FIND ENTITIES [ACCOUNTING, NEW YORK, RESEARCH, DALLAS, SALES, CHICAGO, OPERATIONS, BOSTON]
2012-06-21 14:01:50.346/5.380 Oracle Coherence GE 3.7.1.0 <D4> (thread=ShutdownHook, member=1): ShutdownHook: stopping cluster node

When we really want a performance boost it would be better to set-up Coherence as write-behind. This means the application no longer uses the Hibernate API’s, but will typically use the Coherence API’s. In this case Hibernate will be used as a CacheStore implementation for Coherence, we typically have the following application characteristics:

  • Use Coherence APIs for the data access management.
  • Have simple object models appropriate for the CacheStore class.
  • Have simple transactional requirements.
  • Require a very high performance, which can be achieved by the use of the Coherence APIs, such as write behind.

Examples of the write-behind set-up can be found in the posts:

References

[1] Hibernate Reference Documentation.
[2] Hibernate JavaDocs.


Building a Coherence Cluster with Multiple Application Servers

In this post, we go into the details of configuring the operating system for an application server and an in-memory data grid, such as Coherence; Present scripts to start and stop the environment; Deploy an application that uses JSF 1.2, JBoss RichFaces and Coherence to the domain we set-up in the Fun with JBoss post; Show how class loading in JBoss AS7 works; Add role-based security; Configure mod_cluster; and end with expanding the cluster to multiple machines.

Configure the operating system

When using an application server that runs an in-memory data grid such as Coherence some operating system tweaks are in order. Conifguration tweaks for the Coherence cluster can be found in the Set-up Coherence Clusters post.

Change the hostname and map it to a static ip address

To change the hostname we can follow the following steps:

  • Login as root.
  • Open the file /etc/sysconfig/network and enter a hostname, i.e., HOSTNAME=axis-into-ict.nl.
  • Retrieve the IP-address by using /sbin/ifconfig.
  • Open the file /etc/hosts and add, for example, 192.168.1.50 axis-into-ict.nl.
  • Use the hostname utility to change the hostname: hostname axis-into-ict.nl.
  • Run it again without any parameter to see if the hostname has been changed.
  • Restart the network to apply the changes: service network restart.
  • Logout and login again.

To set-up a static ip-address we can follow these steps. Edit /etc/sysconfig/network, the following gives an example

NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=axis-into-ict.nl
GATEWAY=192.168.1.1

In the case of DHCP the eth0 configuration (/etc/sysconfig/network-scripts/ifcfg-eth0) usually looks like

DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
HWADDR=00:0c:29:76:c8:2d

To have a static ip address we edit /etc/sysconfig/network-scripts/ifcfg-eth0 as follows:

DEVICE=eth0
BOOTPROTO=static
ONBOOT=yes
HWADDR=00:0c:29:76:c8:2d
IPADDR=192.168.1.50
NETMASK=255.255.255.0

When one or more DNS servers are available, edit /etc/resolv.conf and setup the DNS servers, for example,

nameserver 192.168.1.1
nameserver 192.168.1.1

Edit the /etc/hosts when necessary, for example,

127.0.0.1       localhost.localdomain localhost
::1             localhost6.localdomain6 localhost6
192.168.1.50    axis-into-ict.nl axis-into-ict

Restart the network service and check the configuration

[root@axis-into-ict ~]# service network restart
Shutting down interface eth0:                              [  OK  ]
Shutting down loopback interface:                          [  OK  ]
Bringing up loopback interface:                            [  OK  ]
Bringing up interface eth0:                                [  OK  ]

[root@axis-into-ict ~]# /sbin/ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0C:29:76:C8:2D
          inet addr:192.168.1.50  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:410 errors:0 dropped:0 overruns:0 frame:0
          TX packets:114 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:30288 (29.5 KiB)  TX bytes:12023 (11.7 KiB)

Verify the static ip configuration by using

[root@axis-into-ict ~]# ping -c 3 -M do -s 1468 192.168.1.60
PING 192.168.1.60 (192.168.1.60) 1468(1496) bytes of data.
1476 bytes from 192.168.1.60: icmp_seq=1 ttl=128 time=0.837 ms
1476 bytes from 192.168.1.60: icmp_seq=2 ttl=128 time=0.345 ms
1476 bytes from 192.168.1.60: icmp_seq=3 ttl=128 time=0.346 ms

--- 192.168.1.60 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.345/0.509/0.837/0.232 ms

Packet loss minimization

The operating system buffers must be large enough to handle incoming network traffic while the application is paused during garbage collection. Also when UDP (User Datagram Protocol) is used to transmit messages to server instances in a cluster we must limit the need to retransmit UDP messages. In this case the size of the operating system buffers must be set appropriately to avoid excessive UDP datagram loss. To configure Linux to allow for larger buffers we can follow these steps:

  • Edit the /etc/sysctl.conf and add the following lines:
    		# increase TCP max buffer size
    		net.core.rmem_max = 2096304
    		net.core.wmem_max = 2096304
    		net.core.rmem_default=2096304
    		net.core.wmem_default=2096304
    		
  • Run /sbin/sysctl -p to make the changes effective. By executing, for example, cat /proc/sys/net/core/rmem_max we can check the current values.

Maximum number of open file descriptors

Most operating systems handle sockets as a form of file access and use file descriptors to keep track of which sockets are open. To contain the resources per process, the operating system restricts the number of file descriptors per process. Linux limits the number of open file descriptors per process, by default this is equal to 1024. It could be that the 1024 limit does not offer optimal performance. To obtain the current open file limit we can use the ulimit command. The ulimit -aS command shows the current limit, the ulimit -aH command shows the hard limit. To increase the total number of file descriptors for all users we can add the following to the /etc/sysctl.conf file: fs.file-max = 344030. To check the current value we can use cat /proc/sys/fs/file-max. If we want to make sure that a process (running under the jboss user) gets a maximum of 8192 open file descriptors, we have to edit the /etc/security/limits.conf file:

jboss soft nofile 8192
jboss hard nofile 8192

Note that this number applies across all processes running under the jboss user. To make the adjustments active, execute the ulimit -u 8192 command and log out and log in again.

TCP/IP

On some systems the default value for the time wait interval is too high and needs to be adjusted. To determine the number of sockets in TIME_WAIT we can use netstat -a | grep TIME_WAIT | wc -l. When the number approaches the maximum number of file descriptors per process, the application’s throughput will degrade, i.e., new connections have to wait for a free space in the application’s file descriptor table. To check the current value we can use cat /proc/sys/net/ipv4/tcp_keepalive_time and cat /proc/sys/net/ipv4/tcp_keepalive_intvl. The default time wait interval on newer Linux systems is 60 seconds and as such there is no need to change this. If the need arises that TCP/IP settings must be adjusted follow these steps:

  • Edit the /etc/sysctl.conf and add the following lines:
    		net.ipv4.tcp_rmem = 4096    87380   4194304
    		net.ipv4.tcp_wmem = 4096    16384   4194304
    		net.ipv4.tcp_sack = 1
    		net.ipv4.tcp_timestamps = 1
    		net.ipv4.tcp_window_scaling = 1
    		net.ipv4.tcp_keepalive_time = 7200
    		net.ipv4.tcp_keepalive_intvl = 75
    		net.ipv4.tcp_fin_timeout = 60
    		
  • Run /sbin/sysctl -p to make the changes effective. By executing, for example, cat /proc/sys/net/ipv4/tcp_keepalive_time we can check the current values.

Network interface card (NIC)

Configure the network card at it’s maximum link speed and at full duplex. To determine the configuration of the network card we can use:

[root@axis-into-ict jboss]# /sbin/ethtool eth0
Settings for eth0:
	Supported ports: [ TP ]
	Supported link modes:   10baseT/Half 10baseT/Full
							100baseT/Half 100baseT/Full
							1000baseT/Full
	Supports auto-negotiation: Yes
	Advertised link modes:  10baseT/Half 10baseT/Full
							100baseT/Half 100baseT/Full
							1000baseT/Full
	Advertised auto-negotiation: Yes
	Speed: 1000Mb/s
	Duplex: Full
	Port: Twisted Pair
	PHYAD: 0
	Transceiver: internal
	Auto-negotiation: on
	Supports Wake-on: d
	Wake-on: d
	Current message level: 0x00000007 (7)
	Link detected: yes

To change the maximum speed and duplex style we can use, for example, /sbin/ethtool -s eth0 speed 1000 duplex full.

Maximum transaction unit (MTU)

MTU is the maximum packet size, in bytes, that can be transmitted across a link. By default, an MTU of 1500 bytes is assumed and a default packet size of 1500 – 32 = 1468 bytes is used. To determine the MTU we can use the ping utility.

Swapping

Swapping, also known as paging, is the use of secondary storage to store and retrieve data for use in RAM. Swapping is automatically performed by the operating system and typically occurs when the available RAM memory is depleted. Swapping can have a significant impact on the performance of Coherence and should thus be avoided. One thing to avoid swapping is to have enough RAM available – a tool such as top can be used to monitor swap rates. The swappiness (swap out a process or some of its heap due to low resource usage) should also be avoided for Coherence. To obtain the current value for swappiness, we can use cat /proc/sys/vm/swappiness. For Coherence, a low value (0 if possible) should be set. To change the swappiness, open the /etc/sysctl.conf file and add the following:

# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 0 is disabled, 1 is enabled.  See sysctl(8) and
# sysctl.conf(5) for more details.

# Controls IP packet forwarding
net.ipv4.ip_forward = 0

# Controls source route verification
net.ipv4.conf.default.rp_filter = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename
# Useful for debugging multi-threaded applications
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1

# Controls the maximum size of a message, in bytes
kernel.msgmnb = 65536

# Controls the default maxmimum size of a mesage queue
kernel.msgmax = 65536

# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736

# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296

# increase TCP max buffer size
net.core.rmem_max = 2096304
net.core.wmem_max = 2096304
net.core.rmem_default=2096304
net.core.wmem_default=2096304

# set the swappiness to zero
vm.swappiness = 0

Large pages

Large pages are essentially blocks of contiguous physical memory addresses that are reserved for a process. Large pages improve performance of applications that access memory frequently (as is the case when using Coherence). When large pages are used the application uses the translation look-aside buffer (TLB) in the processor more effectively. The TLB is a cache of recently used virtual-to-physical address space translations stored in the processor memory. To obtain data from memory, the processor looks up the TLB to find out the physical addresses (RAM or hard disk) that hold the required data. In the case of large pages, a single entry in the TLB could represent a large contiguous address space and thereby potentially reducing the TLB look-up frequency and avoiding frequent look-ups in the hierarchical page table stored in-memory.

The kernel built with hugepage support (CONFIG_HUGETLBFS and CONFIG_HUGETLB_PAGE selected) should show the number of configured hugepages in the system by running cat /proc/meminfo:

[root@middleware-magic jboss]# cat /proc/meminfo
MemTotal:      4044532 kB
MemFree:       3411928 kB
Buffers:        167968 kB
Cached:         195860 kB
SwapCached:          0 kB
Active:         262596 kB
Inactive:       247148 kB
HighTotal:           0 kB
HighFree:            0 kB
LowTotal:      4044532 kB
LowFree:       3411928 kB
SwapTotal:     6088624 kB
SwapFree:      6088536 kB
Dirty:             232 kB
Writeback:           0 kB
AnonPages:      146020 kB
Mapped:          52732 kB
Slab:            79676 kB
PageTables:      19360 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   8110888 kB
Committed_AS:   426808 kB
VmallocTotal: 34359738367 kB
VmallocUsed:    265976 kB
VmallocChunk: 34359471959 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

where,

  • HugePages_Total is the size of the pool of hugepages.
  • HugePages_Free is the number of hugepages in the pool that are not yet allocated.
  • HugePages_Rsvd is short for reserved, and is the number of hugepages for which a commitment to allocate from the pool has been made, but no allocation has yet been made.
  • Hugepagesize is the configured hugepage size.

Also cat /proc/filesystems should show a filesystem of type hugetlbfs configured in the kernel:

[root@middleware-magic jboss]# cat /proc/filesystems
nodev   sysfs
nodev   rootfs
nodev   bdev
nodev   proc
nodev   cpuset
nodev   binfmt_misc
nodev   debugfs
nodev   securityfs
nodev   sockfs
nodev   usbfs
nodev   pipefs
nodev   anon_inodefs
nodev   futexfs
nodev   tmpfs
nodev   inotifyfs
nodev   eventpollfs
nodev   devpts
        ext2
nodev   ramfs
nodev   hugetlbfs
        iso9660
nodev   mqueue
        ext3
nodev   rpc_pipefs
nodev   autofs

The following command can be used to dynamically allocate/deallocate hugepages: echo 1024 > /proc/sys/vm/nr_hugepages. This command will try to configure 1024 hugepages in the system. The success or failure of allocation depends on the amount of physically contiguous memory that is present in the system at this time. At times, the JVM might not be able to reserve large pages because the pages might not be contiguous. To ensure that the JVM can use large pages, these must be enabled in the operating system as soon as possible after the system starts; otherwise the memory can become too fragmented which leads to a reduction in the number of large pages. In order to accomplish this, we can put the command in the /etc/rc.d/rc.local script, for example,

#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

# set the sharable memory size - in this case we set the memory size to 4GB:
# 1024*1024*1024*4 = 4294967296
echo 4294967296 > /proc/sys/kernel/shmmax

# set the number of huge pages based on the Hugepagesize, i.e., 2048kB
# when we want to reserve 2GB in huge pages we have to set the number of huge pages to:
# (1024*1024*1024*2)/(1024*1024*2) = 2147483648/2097152 = 1024
echo 1024 > /proc/sys/vm/nr_hugepages

# give permission to the group that runs the process to access the shared memory segment
# to this end open the /etc/group file and retrieve the group-id (jboss:x:500:)
echo 500 > /proc/sys/vm/hugetlb_shm_group

Next, we set the locked in-memory address space for the jboss user in the file /etc/security/limits.conf, i.e.,

# memlock - maximum locked in-memory address space (kB), we set this equal to:
# number_of_huge_pages * huge_page_size = 1024 * 2048 = 2097152
jboss  soft    memlock 2097152
jboss  hard    memlock 2097152

Large pages can be exploited by the Java Virtual Machine, for example,

-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParallelGC -XX:ParallelGCThreads=2 -XX:MaxGCPauseMillis=200 -XX:GCTimeRatio=19 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages
  • -server – select the JIT compiler.
  • -Xms – initial heap size.
  • -Xmx – maximum heap size.
  • -XX:NewRatio=N – sets the young generation to heap size / (1 + N).
  • -XX:-UseParallelGC – select the parallel collector for minor collections.
  • -XX:ParallelGCThreads – sets the number of garbage collector threads, i.e., the number of CPUs to be used.
  • -XX:MaxGCPauseMillis – sets the maximum pause time goal.
  • -XX:GCTimeRatio=N – sets the throughput goal that is measured in terms of the time spent doing garbage collection versus the time spent outside of garbage collection. In the case above with N=19, the garbage collection time to application time is set to 1 / (1+N) = 1 / 20, i.e., 5% of the total time is spent in garbage collection.
  • -XX:-UseParallelOldGC – selects the parallel collector for major collections.
  • -XX:+UseTLAB – enables thread-local object allocation.
  • -XX:LargePageSizeInBytes – sets the large page size used for the Java heap. We set this equal to the operating system parameter: Hugepagesize, which in our case is 2048kB
  • -XX:+UseLargePages – use large page memory.

One thing to note is that when large pages are not appropriately configured it can lead to an increase of swapping which should be monitored.

Start and stop scripts

The domain environment we presented in the Fun with JBoss post can be started by using domain.sh. By turning of the auto-start feature of the servers, the domain.sh script will start the process controller and the host controller. When these processes are started, we can use the command-line interface to start the individual servers. To disable auto-start we edit the host.xml file

<host name="axis-into-ict.nl" xmlns="urn:jboss:domain:1.1">
	...
    <jvms>
    	<jvm name="default">
            <heap size="512m" max-size="512m"/>
            <permgen size="256m" max-size="256m"/>
            <jvm-options>
                <option value="-server"/>
                <option value="-XX:NewRatio=2"/>
                <option value="-XX:+UseParallelGC"/>
                <option value="-XX:ParallelGCThreads=2"/>
                <option value="-XX:MaxGCPauseMillis=200"/>
                <option value="-XX:GCTimeRatio=19"/>
                <option value="-XX:+UseParallelOldGC"/>
				<option value="-Dtangosol.coherence.mode=prod"/>
				<option value="-Dtangosol.coherence.distributed.localstorage=false"/>
            </jvm-options>
        </jvm>
    </jvms>
    <servers>
        <server name="server1" group="ha-server-group" auto-start="false">
        </server>
        <server name="server2" group="ha-server-group" auto-start="false">
            <socket-bindings port-offset="1"/>
        </server>
    </servers>
</host>

In which we have also added two system parameters for Coherence. By setting the system property tangosol.coherence.distributed.localstorage to false, we disable storage for the Coherence nodes running on the application servers as we do not want to use the JVMs, the application servers are running in, for storage. To enable storage we are going to start separate stand alone JVMs that run Coherence cache servers. To start up the environment we can use the following script

#!/bin/bash

JBOSS_HOME="/home/jboss/jboss-as-7.1.0.Final"
export JBOSS_HOME

APACHE_HOME="/home/jboss/apache/"
export APACHE_HOME

start_apache() {
	echo "starting Apache HTTP Server"
	${APACHE_HOME}/bin/apachectl -k start
}

start_controllers() {
	echo "starting process controller and host controller"
	${JBOSS_HOME}/bin/domain.sh >/dev/null 2>/dev/null &
	echo "waiting a little for the host controller to finish starting"
	sleep 10
}

start_servers() {
	echo "starting servers"
	${JBOSS_HOME}/bin/jboss-cli.sh --file=${JBOSS_HOME}/scripts/start-servers.cli
}

start_controllers

start_servers

start_apache

In which the start-server.cli looks as follows

connect axis-into-ict.nl:9999
/host=axis-into-ict.nl/server-config=server1:start
/host=axis-into-ict.nl/server-config=server2:start

To stop the environment we can use

#!/bin/bash

JBOSS_HOME="/home/jboss/jboss-as-7.1.0.Final"
export JBOSS_HOME

APACHE_HOME="/home/jboss/apache/"
export APACHE_HOME

stop_apache() {
	echo "stopping Apache HTTP Server"
	${APACHE_HOME}/bin/apachectl -k stop
}

stop_servers() {
	echo "stopping JBoss processes"
	${JBOSS_HOME}/bin/jboss-cli.sh --file=${JBOSS_HOME}/scripts/stop-servers.cli
}

stop_apache

stop_servers

In which the stop-server.cli script looks as follows

connect axis-into-ict.nl:9999
/host=axis-into-ict.nl/server-config=server1:stop
/host=axis-into-ict.nl/server-config=server2:stop
/host=axis-into-ict.nl:shutdown

Class loading

The application presented here uses JSF 1.2, JBoss RichFaces 3.3.1 and Coherence 3.7.1. These classes are by default not present, and we need to do something. In the JBoss application server, instead of the more familiar hierarchical class loading environment, the class loading is based on modules that have to define explicit dependencies on other modules. Deployments are also modules, and do not have access to classes that are defined in jars in the application server unless an explicit dependency on those classes is defined. Even though modules are isolated by default, as part of the deployment process some dependencies on modules defined by the application server are set up automatically. For example, when deploying a Java EE application a dependency on the Java EE API’s will be added to the module automatically. Similarly if the module contains a beans.xml file a dependency on Weld will be added automatically, along with any supporting modules that Weld needs to operate. The same happens when a faces-config.xml is present, which leads to loading of the module javax.faces.api, i.e., the JSF2.1 API is automatically added. As we are using JSF 1.2, we have exclude the automatic JSF dependency by using the jboss-deployment-structure.xml file. A complete list of automatic dependencies can be found here.

Module dependencies are added in a specific order:

  • System Dependencies are added to the module automatically by the container, including the Java EE API’s.
  • User Dependencies are added through jboss-deployment-structure.xml or through the Dependencies in the manifest file.
  • Local Resources are class files packaged up inside the deployment itself, e.g. class files from WEB-INF/classes or WEB-INF/lib of a .war. A .war is considered to be a single module, so classes defined in WEB-INF/lib are treated the same as classes in WEB-INF/classes. All classes packaged in the .war will be loaded with the same class loader.
  • Inter deployment dependencies, i.e., dependencies on other deployments in an .ear deployment, which can include classes in an ear’s lib directory, or classes defined in other ejb jars. An .ear deployment is a multi-module deployment. This means that not all classes inside an .ear will necessarily have access to all other classes in the .ear, unless explicit dependencies have been defined. By default the ear/lib directory is a single module, and every Web or EJB deployment is also a separate module. A sub-deployment (.war and .jar) have a dependency on the parent module, which gives them access to classes in ear/lib, however they do not always have an automatic dependency on each other. This behaviour is controlled via the ear-subdeployments-isolated setting in the ee subsystem configuration. By default this is set to false, which allows a sub-deployment to see classes belonging to another sub-deployment within the .ear.

Our first step to deploy the application is define the appropriate modules. To this end, we create the following directory structure

${JBOSS_HOME}/modules
	/com/coherence
		/main
			module.xml
			coherence.jar
	/javax/faces/api
		/1.2.14
			module.xml
			commons-beanutils-1.7.0.jar
			commons-collections-3.2.jar
			commons-digester-1.8.jar
			commons-logging-1.0.4.jar
			jsf-api.jar
			jsf-facelets.jar
			jsf-impl.jar
			jstl-api-1.2.jar
			jstl-impl-1.2.jar
	/org/jboss/richfaces
		/main
			module.xml
			jhighlight-1.0.jar
			richfaces-api-3.3.1.GA.jar
			richfaces-impl-3.3.1.GA.jar
			richfaces-ui-3.3.1.GA.jar

The module.xml for the Coherence module looks as follows

<module xmlns="urn:jboss:module:1.1" name="com.coherence">
    <dependencies>
	<!-- This dependency is for javax.naming -->
        <module name="javax.api" export="true"/>
	<!-- This dependency is for sun.rmi.server -->
	<module name="sun.jdk" export="true"/>
    </dependencies>
    <resources>
        <resource-root path="coherence.jar"/>
    </resources>
</module>

Here an important note is in order. The module sun.jdk does by default not contain a path for sun.rmi.server and has to be added to the module

<module xmlns="urn:jboss:module:1.1" name="sun.jdk">
    <resources>...</resources>
    <dependencies>
        <system export="true">
            <paths>
				...
				<path name="sun/rmi/server"/>
				...
            </paths>
            <exports>...</exports>
        </system>
    </dependencies>
</module>

The module.xml for the JSF 1.2.14 module looks as follows

<module xmlns="urn:jboss:module:1.1" name="javax.faces.api" slot="1.2.14">
    <dependencies>
		<!-- This dependency is for javax.naming -->
        <module name="javax.api" export="true"/>
        <module name="javax.el.api" export="true"/>
        <module name="javax.servlet.api" export="true"/>
        <module name="javax.servlet.jsp.api" export="true"/>
        <module name="javax.servlet.jstl.api" export="true"/>
        <module name="javax.validation.api" export="true"/>
		<module name="org.apache.log4j" export="true"/>
    </dependencies>
    <resources>
		<resource-root path="commons-beanutils-1.7.0.jar"/>
		<resource-root path="commons-collections-3.2.jar"/>
		<resource-root path="commons-digester-1.8.jar"/>
		<resource-root path="commons-logging-1.0.4.jar"/>
        <resource-root path="jsf-api.jar"/>
		<resource-root path="jsf-facelets.jar"/>
		<resource-root path="jsf-impl.jar"/>
		<resource-root path="jstl-api-1.2.jar"/>
		<resource-root path="jstl-impl-1.2.jar"/>
    </resources>
</module>

Note that the commons-beanutils (org/apache/commons/beanutils), commons-collections (org/apache/commons/collections) and commons-logging (org/apache/commons/logging) are also present as modules and could have been used in the dependencies as well, instead of adding the .jar files. The slot definition will be used to specify the appropriate dependency in the jboss-deployment-structure.xml file. The module.xml for the JBoss RichFaces module looks as follows

<module xmlns="urn:jboss:module:1.1" name="org.jboss.richfaces">
    <dependencies>
		<module name="javax.faces.api" slot="1.2.14" export="true"/>
    </dependencies>
    <resources>
        <resource-root path="jhighlight-1.0.jar"/>
		<resource-root path="richfaces-api-3.3.1.GA.jar"/>
		<resource-root path="richfaces-impl-3.3.1.GA.jar"/>
		<resource-root path="richfaces-ui-3.3.1.GA.jar"/>
    </resources>
</module>

As we are dealing with a .war deployment, we have to add the jboss-deployment-structure.xml file to the WEB-INF directory. In the case of an .ear deployment it must be added in the root META-INF directory. The contents of jboss-deployment-structure.xml looks as follows

<jboss-deployment-structure>
    <deployment>
        <exclusions>
            <module name="javax.faces.api"/>
            <module name="com.sun.jsf-impl"/>
        </exclusions>
        <dependencies>
            <module name="com.coherence"/>
            <module name="javax.faces.api" slot="1.2.14"/>
            <module name="org.jboss.richfaces"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

Here, we exclude the default JSF 2.1 API and load the appropriate modules by using the dependencies element. The .war file still needs to have all the impl jars in the WEB-INF/lib directory, i.e.,

Security.war
	/WEB-INF
		/classes
			/packages with compiled classes
		/lib
			jsf-facelets.jar
			jsf-impl.jar
			jstl-impl-1.2.jar
			richfaces-impl-3.3.1.GA.jar
			richfaces-ui-3.3.1.GA.jar
		faces-config.xml
		jboss-deployment-structure.xml
		web.xml

With the modules in place, we restart the servers by using

[jboss@axis-into-ict bin]$ ./jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /] connect 192.168.1.50:9999
[domain@192.168.1.50:9999 /] /host=axis-into-ict.nl/server-config=server2:restart
{
    "outcome" => "success",
    "result" => "STARTING"
}
[domain@192.168.1.50:9999 /] /host=axis-into-ict.nl/server-config=server1:restart
{
    "outcome" => "success",
    "result" => "STARTING"
}

Security

We add two different users (employee and manager) to the application realm. To this end run add-user.sh (${JBOSS_HOME}/bin) and follow the instructions given on the screen, for example,

[jboss@axis-into-ict bin]$ ./add-user.sh 

What type of user do you wish to add?
 a) Management User (mgmt-users.properties)
 b) Application User (application-users.properties)
(a): b

Enter the details of the new user to add.
Realm (ApplicationRealm) :
Username : employee
Password :
Re-enter Password :
What roles do you want this user to belong to? (Please enter a comma separated list, or leave blank for none) : EMPLOYEE
About to add user 'employee' for realm 'ApplicationRealm'
Is this correct yes/no? yes
Added user 'employee' to file '/home/jboss/jboss-as-7.1.0.Final/standalone/configuration/application-users.properties'
Added user 'employee' to file '/home/jboss/jboss-as-7.1.0.Final/domain/configuration/application-users.properties'
Added user 'employee' with roles EMPLOYEE to file '/home/jboss/jboss-as-7.1.0.Final/standalone/configuration/application-roles.properties'
Added user 'employee' with roles EMPLOYEE to file '/home/jboss/jboss-as-7.1.0.Final/domain/configuration/application-roles.properties'

When a user logs in with MANAGER privileges, the user is able to delete customers. When a user logs in with EMPLOYEE privileges, the delete option is not rendered.

Before we deploy the application, we start a Coherence cache server. The reason for this is that the application server nodes are configured as cache clients that do not store data and at least one node in a Coherence cluster must be present that can store data. To start a cache server we use the following script

#!/bin/sh

JMX_OPTIONS="-Dcom.sun.management.jmxremote.port=7091 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"
COHERENCE_MANAGEMENT_OPTIONS="-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true"
COHERENCE_OPTIONS="-Dtangosol.coherence.cacheconfig=security-cache-config.xml -Dtangosol.coherence.mode=prod ${COHERENCE_MANAGEMENT_OPTIONS} ${JMX_OPTIONS}"
export COHERENCE_OPTIONS

JAVA_HOME="/home/jboss/jdk1.6.0_31"
export JAVA_HOME

MEM_ARGS="-server -Xms512m -Xmx512m -XX:NewRatio=2 -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing"
export MEM_ARGS

CLASSPATH="/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/coherence.jar:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/test.jar"
export CLASSPATH

${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} com.tangosol.net.DefaultCacheServer

To deploy the application we use the command-line utility

[domain@192.168.1.50:9999 /] deploy /home/jboss/jboss-as-7.1.0.Final/deploy/Security.war --server-groups=ha-server-group
[domain@192.168.1.50:9999 /] undeploy Security.war --server-groups=ha-server-group

which also shows how to undeploy it. The Coherence logging shows how the cluster is created

[jboss@axis-into-ict scripts]$ ./default-cache-server.sh
2012-03-10 10:43:24.872/0.390 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/coherence.jar!/tangosol-coherence.xml"
2012-03-10 10:43:24.956/0.474 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/coherence.jar!/tangosol-coherence-override-prod.xml"
2012-03-10 10:43:25.089/0.607 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/test.jar!/tangosol-coherence-override.xml"
2012-03-10 10:43:25.093/0.611 Oracle Coherence 3.7.1.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Production mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2012-03-10 10:43:25.676/1.194 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/test.jar!/security-cache-config.xml"
2012-03-10 10:43:25.891/1.409 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded Reporter configuration from "jar:file:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/coherence.jar!/reports/report-group.xml"
2012-03-10 10:43:26.637/2.155 Oracle Coherence GE 3.7.1.0 <D4> (thread=main, member=n/a): TCMP bound to /192.168.1.50:8088 using SystemSocketProvider
2012-03-10 10:43:57.408/32.926 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0xFCDB" with Member(Id=1, Timestamp=2012-03-10 10:43:26.685, Address=192.168.1.50:8088, MachineId=54112, Location=site:,machine:axis-into-ict,process:11068, Role=CoherenceServer, Edition=Grid Edition, Mode=Production, CpuCount=2, SocketCount=1) UID=0xC0A8013200000135FBFDC4DDD3601F98
2012-03-10 10:43:57.418/32.936 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0xFCDB

Group{Address=224.3.7.0, Port=37000, TTL=4}

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2012-03-10 10:43:26.685, Address=192.168.1.50:8088, MachineId=54112, Location=site:,machine:axis-into-ict,process:11068, Role=CoherenceServer)
  OldestMember=Member(Id=1, Timestamp=2012-03-10 10:43:26.685, Address=192.168.1.50:8088, MachineId=54112, Location=site:,machine:axis-into-ict,process:11068, Role=CoherenceServer)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2012-03-10 10:43:26.685, Address=192.168.1.50:8088, MachineId=54112, Location=site:,machine:axis-into-ict,process:11068, Role=CoherenceServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2012-03-10 10:43:57.409|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2012-03-10 10:43:57.473/32.991 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-03-10 10:43:57.662/33.180 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=1): Loaded POF configuration from "jar:file:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/test.jar!/security-pof-config.xml"
2012-03-10 10:43:57.701/33.219 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=1): Loaded included POF configuration from "jar:file:/home/jboss/jboss-as-7.1.0.Final/modules/com/coherence/main/coherence.jar!/coherence-pof-config.xml"
2012-03-10 10:43:57.763/33.281 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
2012-03-10 10:43:57.788/33.306 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=1):
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7.1, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  PartitionedCache{Name=DistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
  )

Started DefaultCacheServer...

2012-03-10 10:46:35.557/191.075 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-03-10 10:46:35.396, Address=192.168.1.50:8090, MachineId=54112, Location=site:,machine:axis-into-ict,process:11537, Role=JbossModulesMain) joined Cluster with senior member 1
2012-03-10 10:46:35.666/191.184 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2012-03-10 10:46:35.481, Address=192.168.1.50:8092, MachineId=54112, Location=site:,machine:axis-into-ict,process:11566, Role=JbossModulesMain) joined Cluster with senior member 1
2012-03-10 10:46:35.905/191.423 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2012-03-10 10:46:36.117/191.635 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 3 joined Service Management with senior member 1
2012-03-10 10:46:36.682/192.200 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 joined Service DistributedCache with senior member 1
2012-03-10 10:46:36.897/192.415 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 3 joined Service DistributedCache with senior member 1

Here, the last lines (after Started DefaultCacheServer) are the application server nodes that are joining the Coherence cluster

[jboss@axis-into-ict scripts]$ ./start-environment.sh
starting process controller and host controller
waiting a little for the host controller to finish starting
starting servers
{
    "outcome" => "success",
    "result" => "STARTING"
}
{
    "outcome" => "success",
    "result" => "STARTING"
}
starting Apache HTTP Server

When we stop the application servers

[jboss@axis-into-ict scripts]$ ./stop-environment.sh
stopping Apache HTTP Server
stopping JBoss processes
{
    "outcome" => "success",
    "result" => "STOPPING"
}
{
    "outcome" => "success",
    "result" => "STOPPING"
}
{
    "outcome" => "success",
    "result" => undefined,
    "server-groups" => undefined
}

the following is observed in the Coherence logging

2012-03-10 10:55:33.075/728.593 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=3, Timestamp=2012-03-10 10:46:35.481, Address=192.168.1.50:8092, MachineId=54112, Location=site:,machine:axis-into-ict,process:11566, Role=JbossModulesMain) due to a peer departure; removing the member.
2012-03-10 10:55:33.076/728.594 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 3 left service Management with senior member 1
2012-03-10 10:55:33.076/728.594 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 3 left service DistributedCache with senior member 1
2012-03-10 10:55:33.076/728.594 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2012-03-10 10:55:33.076, Address=192.168.1.50:8092, MachineId=54112, Location=site:,machine:axis-into-ict,process:11566, Role=JbossModulesMain) left Cluster with senior member 1
2012-03-10 10:55:33.140/728.658 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): TcpRing disconnected from Member(Id=2, Timestamp=2012-03-10 10:46:35.396, Address=192.168.1.50:8090, MachineId=54112, Location=site:,machine:axis-into-ict,process:11537, Role=JbossModulesMain) due to a peer departure; removing the member.
2012-03-10 10:55:33.140/728.658 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 left service Management with senior member 1
2012-03-10 10:55:33.140/728.658 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 left service DistributedCache with senior member 1
2012-03-10 10:55:33.140/728.658 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-03-10 10:55:33.14, Address=192.168.1.50:8090, MachineId=54112, Location=site:,machine:axis-into-ict,process:11537, Role=JbossModulesMain) left Cluster with senior member 1

When the application servers are started again the following is observed in the Coherence logging

2012-03-10 10:58:43.009/918.527 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2012-03-10 10:58:42.837, Address=192.168.1.50:8090, MachineId=54112, Location=site:,machine:axis-into-ict,process:12772, Role=JbossModulesMain) joined Cluster with senior member 1
2012-03-10 10:58:43.242/918.760 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 4 joined Service Management with senior member 1
2012-03-10 10:58:44.436/919.954 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 4 joined Service DistributedCache with senior member 1
2012-03-10 10:58:44.444/919.962 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=5, Timestamp=2012-03-10 10:58:44.264, Address=192.168.1.50:8092, MachineId=54112, Location=site:,machine:axis-into-ict,process:12801, Role=JbossModulesMain) joined Cluster with senior member 1
2012-03-10 10:58:44.777/920.295 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 5 joined Service Management with senior member 1
2012-03-10 10:58:45.259/920.777 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 5 joined Service DistributedCache with senior member 1

Configure mod_cluster

The advantage of using mod_cluster with respect to mod_jk (or mod_proxy) is a dynamic cluster configuration. As we saw in the Fun with JBoss post, to configure mod_jk we have to provide a static list of servers. When expanding the cluster, for example, to other machines (as will be done below) we have to add the servers to the mod_jk load balancer configuration. When using mod_cluster, servers in the cluster are discovered through an advertising mechanism (UDP messages on a multicast group). The set of proxies to which an application server will communicate is determined either by a static list (configure in the domain.xml file) or using dynamic discovery (by using the advertising mechanism). Load balance factors are calculated and provided by the application servers, rather than computing these in the proxy. Each server forwards any web application context lifecycle events (e.g. web-app deploy/undeploy) to the proxy informing it to start/stop routing requests for a given context to that server.

A mod_cluster distribution can be downloaded here. We will use mod_cluster 1.2.0.Final. Note that the binaries (for example, binaries linux2-x64) contain a full Apache distribution, while the dynamic libraries (for example, dynamic libraries linux2-x64) contain only the modules for mod_cluster (excluding mod_proxy.so, mod_proxy_ajp.so and mod_proxy_http.so). As we already have an Apache installed we will use the dynamic libraries distribution. To configure mod_cluster we first copy the libraries into ${APACHE_HOME}/modules, i.e.,

${APACHE_HOME}
	/conf
		httpd.conf
		jboss-workers.properties
		mod_jk.conf
		mod_cluster.conf
	/modules
		mod_advertise.so
		mod_jk.so
		mod_manager.so
		mod_proxy.so
		mod_proxy_ajp.so
		mod_proxy_http.so
		mod_proxy_cluster.so
		mod_slotmem.so

To configure mod_cluster, we create a mod_cluster configuration file, for example mod_cluster.conf. The configuration has the following contents

LoadModule proxy_module "/home/jboss/apache/modules/mod_proxy.so"
LoadModule proxy_ajp_module "/home/jboss/apache/modules/mod_proxy_ajp.so"
LoadModule proxy_http_module "/home/jboss/apache/modules/mod_proxy_http.so"
LoadModule slotmem_module "/home/jboss/apache/modules/mod_slotmem.so"
LoadModule manager_module "/home/jboss/apache/modules/mod_manager.so"
LoadModule proxy_cluster_module "/home/jboss/apache/modules/mod_proxy_cluster.so"
LoadModule advertise_module "/home/jboss/apache/modules/mod_advertise.so"

NameVirtualHost axis-into-ict.nl:8888

<VirtualHost axis-into-ict.nl:8888>
	EnableMCPMReceive
	ManagerBalancerName mycluster

	AllowDisplay On

	KeepAliveTimeout 60
	MaxKeepAliveRequests 0

	ServerAdvertise On
	AdvertiseGroup 224.0.1.105:23364
	AdvertiseFrequency 10

	<Directory />
    	Order deny,allow
		Deny from all
	    Allow from 192.168.1.
	</Directory>

	<Location /mod_cluster-manager>
		SetHandler mod_cluster-manager
		Order deny,allow
   		Deny from all
   		Allow from 192.168.1.
	</Location>
</VirtualHost>

The used directives are explained here. Next, add the following Include directive to httpd.conf

# put it near the end of the file where all the other includes are present
# mod_cluster configuration
Include conf/mod_cluster.conf

The protocol used by mod_cluster to communicate with the servers in based on the connectors configured in domain.xml. When an AJP connector is configured it will be used, otherwise an HTTP connector will be used. While AJP is generally faster, an HTTP connector can optionally be secured via SSL. In the case of an AJP connector make sure the scheme attribute is set to http, otherwise a request after a form-based log in is not redirected correctly

<subsystem xmlns="urn:jboss:domain:web:1.1" native="false" default-virtual-server="default-host">
	<connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/>
	<connector name="ajp" protocol="AJP/1.3" scheme="http" socket-binding="ajp" enable-lookups="false" max-post-size="1048576" enabled="true" max-connections="150"/>
	<virtual-server name="default-host" enable-welcome-root="true">
		<alias name="localhost"/>
		<alias name="example.com"/>
	</virtual-server>
</subsystem>

Restart the Apache HTTP Server. By accessing the URL: http://hostname:8888/mod_cluster-manager, we get an overview of the configuration

mod_cluster/1.2.0.Final

start of "httpd.conf" configuration
mod_proxy_cluster.c: OK
mod_sharedmem.c: OK
Protocol supported: AJP
mod_advertise.c: OK
Server: axis-into-ict.nl
Server: axis-into-ict.nl VirtualHost: 192.168.1.50:8888 Advertising on Group 224.0.1.105 Port 23364 for http://192.168.1.50:8888 every 10 seconds
end of "httpd.conf" configuration

Auto Refresh show DUMP output show INFO output
Node f817d8c0-737d-3134-beb0-85dee2469701 (ajp://axis-into-ict.nl:9080):

Enable Contexts Disable Contexts
Balancer: mycluster,LBGroup: ,Flushpackets: Off,Flushwait: 10000,Ping: 10000000,Smax: 1,Ttl: 60000000,Status: OK,Elected: 750,Read: 1310513,Transferred: 4869,Connected: 0,Load: 1
Virtual Host 1:

Contexts:

/, Status: ENABLED Request: 0 Disable
/Security, Status: ENABLED Request: 0 Disable
Aliases:

default-host
localhost
example.com
Node 236ade27-f8e4-30c5-aa80-ded57bfe7736 (ajp://axis-into-ict.nl:9081):

Enable Contexts Disable Contexts
Balancer: mycluster,LBGroup: ,Flushpackets: Off,Flushwait: 10000,Ping: 10000000,Smax: 1,Ttl: 60000000,Status: OK,Elected: 383,Read: 850881,Transferred: 2112,Connected: 0,Load: 1
Virtual Host 1:

Contexts:

/, Status: ENABLED Request: 0 Disable
/Security, Status: ENABLED Request: 0 Disable
Aliases:

default-host
localhost
example.com

The mod_cluster configuration can also be viewed by using the command-line interface

[jboss@axis-into-ict ~]$ cd jboss-as-7.1.0.Final/bin/
[jboss@axis-into-ict bin]$ ./jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /] connect 192.168.1.50:9999
[domain@192.168.1.50:9999 /] /profile=full-ha/subsystem=modcluster/mod-cluster-config=configuration:read-resource
{
    "outcome" => "success",
    "result" => {
        "advertise" => true,
        "advertise-socket" => "modcluster",
        "auto-enable-contexts" => true,
        "balancer" => "mycluster",
        "excluded-contexts" => "ROOT,admin-console,invoker,jbossws,jmx-console,juddi,web-console",
        "flush-packets" => false,
        "flush-wait" => -1,
        "max-attemps" => 1,
        "node-timeout" => -1,
        "ping" => 10,
        "proxy-list" => "",
        "proxy-url" => "/",
        "socket-timeout" => 20,
        "ssl" => undefined,
        "sticky-session" => true,
        "sticky-session-force" => false,
        "sticky-session-remove" => false,
        "stop-context-timeout" => 10,
        "ttl" => 60,
        "worker-timeout" => -1
    }
}

When the advertising mechanism is not working (for example, multicast is disabled), we can set the ServerAdvertise directive to Off (also comment all the advertise related directives). When doing this we have to configure the modcluster subsystem within the domain and set the proxy list by hand, for example,

<domain xmlns="urn:jboss:domain:1.1">
    <extensions>
		...
        <extension module="org.jboss.as.modcluster"/>
		...
    </extensions>
    <system-properties>
        <property name="java.net.preferIPv4Stack" value="true"/>
    </system-properties>
    <profiles>
        <profile name="full-ha">
			...
            <subsystem xmlns="urn:jboss:domain:modcluster:1.0">
                <mod-cluster-config advertise-socket="modcluster proxy-list="192.168.1.50:8888"/>
            </subsystem>
			...
        </profile>
    </profiles>
    <interfaces>...</interfaces>
    <socket-binding-groups>
        <socket-binding-group name="ha-sockets" default-interface="public">
			...
            <socket-binding name="modcluster" port="0" multicast-address="224.0.1.105" multicast-port="23364"/>
			...
        </socket-binding-group>
    </socket-binding-groups>
    <deployments>
        <deployment name="Security.war" runtime-name="Security.war">
            <content sha1="5a864da538be690f7dcf282201f3574678edb139"/>
        </deployment>
    </deployments>
    <server-groups>
        <server-group name="ha-server-group" profile="full-ha">
            <jvm name="default"/>
            <socket-binding-group ref="ha-sockets"/>
            <deployments>
                <deployment name="Security.war" runtime-name="Security.war"/>
            </deployments>
        </server-group>
    </server-groups>
</domain>

Multiple machine set-up

Detailed steps can be found in the AS7 Cluster Howto. To get the environment on a different machine we just tar the whole ${JBOSS_HOME} directory and copy the tar to the other machine

[jboss@axis-into-ict temp]$ tar -cvpf /home/jboss/temp/jboss.tar /home/jboss/jboss-as-7.1.0.Final/

[jboss@axis-into-ict temp]$ scp jboss@192.168.1.50:/home/jboss/temp/jboss.tar jboss@192.168.1.51:/home/jboss/temp/
The authenticity of host '192.168.1.50 (192.168.1.50)' can't be established.
RSA key fingerprint is 20:59:8b:b7:0e:24:05:b8:e1:70:28:e4:15:05:fa:95.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.50' (RSA) to the list of known hosts.
jboss@192.168.1.50's password:
The authenticity of host '192.168.1.51 (192.168.1.51)' can't be established.
RSA key fingerprint is 20:59:8b:b7:0e:24:05:b8:e1:70:28:e4:15:05:fa:95.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.51' (RSA) to the list of known hosts.
jboss@192.168.1.51's password:
jboss.tar                                                                                       100%  220MB   2.9MB/s   01:17
Connection to 192.168.1.50 closed.

On the other machine we unpack the tar

[jboss@middleware-magic ~]$ cd /
[jboss@middleware-magic /]$ tar xvf /home/jboss/temp/jboss.jar

Next, we set-up the host controller, i.e., edit the host.xml (${JBOSS_HOME}/domain/configuration) file

<host name="jboss" xmlns="urn:jboss:domain:1.1">
    <management>
        <security-realms>
            <security-realm name="ManagementRealm">
				<server-identities>
                     <secret value="bWFnaWMxMWc="/>
                </server-identities>
                <authentication>
                    <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
                </authentication>
            </security-realm>
            <security-realm name="ApplicationRealm">
                <authentication>
                    <properties path="application-users.properties" relative-to="jboss.domain.config.dir" />
                </authentication>
            </security-realm>
        </security-realms>
        <management-interfaces>
            <native-interface security-realm="ManagementRealm">
                <socket interface="management" port="9999"/>
            </native-interface>
            <http-interface security-realm="ManagementRealm">
                <socket interface="management" port="9990"/>
            </http-interface>
        </management-interfaces>
    </management>
    <domain-controller>
       <remote host="192.168.1.50" port="9999" security-realm="ManagementRealm"/>
    </domain-controller>
    <interfaces>
        <interface name="management">
           <nic name="eth0"/>
        </interface>
        <interface name="public">
           <nic name="eth0"/>
        </interface>
        <interface name="unsecure">
	   <nic name="eth0"/>
        </interface>
    </interfaces>
    <jvms>
    	<jvm name="default">
            <heap size="512m" max-size="512m"/>
            <permgen size="256m" max-size="256m"/>
            <jvm-options>
                <option value="-server"/>
                <option value="-XX:NewRatio=2"/>
                <option value="-XX:+UseParallelGC"/>
                <option value="-XX:ParallelGCThreads=2"/>
                <option value="-XX:MaxGCPauseMillis=200"/>
                <option value="-XX:GCTimeRatio=19"/>
                <option value="-XX:+UseParallelOldGC"/>
				<option value="-Dtangosol.coherence.mode=prod"/>
				<option value="-Dtangosol.coherence.distributed.localstorage=false"/>
            </jvm-options>
        </jvm>
    </jvms>
    <servers>
        <server name="server3" group="ha-server-group" auto-start="false">
        </server>
        <server name="server4" group="ha-server-group" auto-start="false">
            <socket-bindings port-offset="1"/>
        </server>
    </servers>
</host>

The choice of the name of the host is very important, as a corresponding user name must be present in the mgmt-users.properties file on the host where the domain controller runs. Recall, that we did this by using the add-user.sh script (see the Fun with JBoss post in which we added a user called jboss). Another important configuration is the server-identities element, which contains the base 64 code for the password of the user jboss. A handy base64-decoder-encoder is provided here. With the configuration in place we can start the process and host controller on the other machine by using domain.sh. When everything went alright the following should show up in the log of the domain controller

[Host Controller] 19:42:13,338 INFO  [org.jboss.as.domain] (management-handler-threads - 1) JBAS010918: Registered remote slave host "jboss", JBoss AS 7.1.0.Final "Thunder"

Now, we ready to start the other configured servers (server3 and server4). Before we do this, we first start a Coherence cache server on the other machine as well

2012-03-10 20:14:46.944/289.405 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2012-03-10 20:14:46.554, Address=192.168.1.51:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:13750, Role=CoherenceServer) joined Cluster with senior member 1
2012-03-10 20:14:47.091/289.552 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 4 joined Service Management with senior member 1
2012-03-10 20:14:47.795/290.256 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 4 joined Service DistributedCache with senior member 1
2012-03-10 20:14:47.855/290.316 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=1): 1> Transferring vulnerable PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127} to member 4 requesting 128
2012-03-10 20:14:48.084/290.545 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=1): 1> Transferring 129 out of 129 partitions to a machine-safe backup 1 at member 4 (under 129)
2012-03-10 20:14:48.127/290.588 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=1): Transferring 0KB of backup[1] for PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256} to member 4

Note that the data gets partitioned among the Coherence cache servers. To start the servers we can use the command-line interface

[jboss@axis-into-ict bin]$ ./jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /] connect 192.168.1.50:9999
[domain@192.168.1.50:9999 /] /host=jboss/server-config=server3:start
{
    "outcome" => "success",
    "result" => "STARTING"
}
[domain@192.168.1.50:9999 /] /host=jboss/server-config=server4:start
{
    "outcome" => "success",
    "result" => "STARTING"
}

When the servers are started the nodes join the Coherence cluster

2012-03-10 20:19:23.858/566.319 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=5, Timestamp=2012-03-10 20:19:23.349, Address=192.168.1.51:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:14024, Role=JbossModulesMain) joined Cluster with senior member 1
2012-03-10 20:19:24.605/567.066 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 5 joined Service Management with senior member 1
2012-03-10 20:19:26.447/568.908 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 5 joined Service DistributedCache with senior member 1
2012-03-10 20:21:49.001/711.462 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=6, Timestamp=2012-03-10 20:21:48.617, Address=192.168.1.51:8092, MachineId=65081, Location=site:,machine:middleware-magic,process:14202, Role=JbossModulesMain) joined Cluster with senior member 1
2012-03-10 20:21:49.708/712.169 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 6 joined Service Management with senior member 1
2012-03-10 20:21:50.849/713.310 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 6 joined Service DistributedCache with senior member 1

By using an MBean browser we can observe the Coherence cache statistics

How beautiful can software get? “Beautiful programs work better, cost less, match user needs, have fewer bugs, run faster, are easier to fix, and have a longer life span. Beautiful software is as small as it can be, by using existing computing resources where possible. Beautiful software is simple. Beautiful software is achieved by creating a ‘wonderful whole’…”. Coherence is beautiful software!

References

[1] Documentation JBoss AS7.1.
[2] Documentation mod_cluster.


Coherence Monitoring

In this post, we will set-up a tuned environment (operating system, network and Java Virtual Machine) for Coherence. We start with installing our operating system (RedHat Enterprise Linux) on different machines. Next, we will present the steps involved in fine tuning the operating system for Coherence and conduct a network and multi-cast test. Once the operating system is set-up, we will tune the Java Virtual machine and present scripts to start individual nodes of the Coherence cluster. Finally, we will use the Oracle Coherence Monitor from SL-corporation to obtain insight in the network activity and the cache activity. The application that is used is presented here.

Install the operating system

We start with the steps involved in installing our operating system:

  • Create a bootable USB by using for example iso2usb.
  • Press enter to start the installation (note that various install options are available, for example linux mem=2048m noprobe, see the function buttons for more details).
  • Choose the installation language, choose the keyboard type, and the media type that contains the packages to be installed (hard drive).
  • Select the partition that contains the iso image for Red Hat Enterprise Linux (/dev/sda).
  • After a few moments the welcome screen is shown, click next.
  • Enter the installation number (can also be skipped) when applicable and click next.
  • Choose install Red Hat Enterprise Linux Server and click next.
  • The hard drive partitioning screen is shown:
    • select – remove all partitions on selected drives and create default layout.
    • de-select – the sda drive (which is the USB).
    • select review and modify partition layout.
  • Click next. A warning is shown that all partitions (ALL DATA) are going to be removed, click yes.
  • The partition layout is shown and can be modified at will, which we are not going to do, click next
  • The boot loader screen is shown, select configure advanced boot loader options and click next. Note that the default says that the boot loader will be installed on /dev/sda, which is the USB. This means we will need the USB in order to boot the machine.
  • Click next.
    • Click change drive order and make /dev/hda the first and click OK. Now the boot loader will be installed on /dev/hda Master Boot Record (MBR).
    • Click next.
  • Edit the network devices when necessary. We will accept the defaults, i.e., a network device eth0 that sets the hostname automatically by using DHCP. Click next.
  • Choose the location that will be used for the time settings and click next
  • Enter the password for the superuser (root) and click next.
  • The option to customize the packages to be installed is offered. We choose to customize the software selection and click next.
  • The option is shows to select different software packages:
    • Desktop environments: choose GNOME or KDE (both are very nice).
    • Applications: different kind of games, editors etcetera can be chosen, the defaults will suffice.
    • Development: Can be installed afterwards, such as a Java JDK.
    • Servers: The default has printing support selected, which will do in our case.
    • Base system: add the system tools option.
    • Languages: choose additional language support to be installed.
  • Click next to begin the installation.
  • When the installation is finished, remove the USB and click reboot.

On first start up, RedHat Enterprise Linux offers the system to be configured:

  • Click forward on the welcome screen.
  • The license agreement is shown, select yes and click forward.
  • The option to configure the firewall is offered. Disable the firewall and click forward (click yes in the pop-up).
  • Security Enhanced Linux. Set the SELinux setting to enforcing and click forward.
  • No need to enable kdump, click forward.
  • Set the date and time and click forward.
  • Configure software updates and click forward.
  • Create a user:
    • username: oracle
    • fullname: oracle
    • password: magic11g
    • confirm password: magic11g
  • Click forward.
  • Configure the sound card and click forward.
  • Install additional CDs when needed and click finish.

Configure the operating system

Now, that we have our operating system in place, we start with the configuration.

Change the hostname

To change the hostname we can follow the following steps:

  • Login as root.
  • Open the file /etc/sysconfig/network and enter a hostname, i.e., HOSTNAME=middleware-magic.com.
  • Retrieve the IP-address by using /sbin/ifconfig.
  • Open the file /etc/hosts and add, for example, 172.31.0.175 middleware-magic.com.
  • Use the hostname utility to change the hostname: hostname middleware-magic.com.
  • Run it again without any parameter to see if the hostname has been changed.
  • Restart the network to apply the changes: service network restart.
  • Logout and login again.

Some information about hostname resolution. To check to what IP-address the hostname will be resolved we can use:

[oracle@middleware-magic ~]$ perl -e 'use Socket; $ip = gethostbyname($ARGV[0]); $name = inet_ntoa($ip); print "$name\n";' middleware-magic.com
172.31.0.175

[oracle@middleware-magic ~]$ perl -e 'use Socket; $name = gethostbyaddr(inet_aton($ARGV[0]),AF_INET); print "$name\n";' 172.31.0.175
middleware-magic.com

[oracle@edu-wls-rh ~]$ getent hosts middleware-magic.com
172.31.0.175	middleware-magic.com

[oracle@edu-wls-rh ~]$ getent ahosts middleware-magic.com
172.31.0.175   	STREAM middleware-magic.com
172.31.0.175   	DGRAM
172.31.0.175   	RAW

The hostname is looked up based on the rules specified in /etc/nsswitch.conf usually there is something like hosts: files dns. In this case the resolver will first check /etc/hosts and if it cannot find anything it will check /etc/resolv.conf for the DNS servers specified, for example, search environment.local nameserver 203.104.22.22

Packet loss minimization

The operating system buffers must be large enough to handle incoming network traffic while the application is paused during garbage collection. Also when UDP (User Datagram Protocol) is used to transmit messages to server instances in a cluster we must limit the need to retransmit UDP messages. In this case the size of the operating system buffers must be set appropriately to avoid excessive UDP datagram loss. To configure Linux to allow for larger buffers we can follow these steps:

  • Edit the /etc/sysctl.conf and add the following lines:
    		# increase TCP max buffer size
    		net.core.rmem_max = 2096304
    		net.core.wmem_max = 2096304
    		net.core.rmem_default=2096304
    		net.core.wmem_default=2096304
    		
  • Run /sbin/sysctl -p to make the changes effective. By executing, for example, cat /proc/sys/net/core/rmem_max we can check the current values.

Maximum number of open file descriptors

Most operating systems handle sockets as a form of file access and use file descriptors to keep track of which sockets are open. To contain the resources per process, the operating system restricts the number of file descriptors per process. Linux limits the number of open file descriptors per process, by default this is equal to 1024. It could be that the 1024 limit does not offer optimal performance. To obtain the current open file limit we can use the ulimit command. The ulimit -aS command shows the current limit, the ulimit -aH command shows the hard limit. To increase the total number of file descriptors for all users we can add the following to the /etc/sysctl.conf file: fs.file-max = 344030. To check the current value we can use cat /proc/sys/fs/file-max. If we want to make sure that a process (running under the oracle user) gets a maximum of 8192 open file descriptors, we have to edit the /etc/security/limits.conf file:

oracle soft nofile 8192
oracle hard nofile 8192

Note that this number applies across all processes running under the oracle user. To make the adjustments active, execute the ulimit -u 8192 command and log out and log in again.

TCP/IP

On some systems the default value for the time wait interval is too high and needs to be adjusted. To determine the number of sockets in TIME_WAIT we can use netstat -a | grep TIME_WAIT | wc -l. When the number approaches the maximum number of file descriptors per process, the application’s throughput will degrade, i.e., new connections have to wait for a free space in the application’s file descriptor table. To check the current value we can use cat /proc/sys/net/ipv4/tcp_keepalive_time and cat /proc/sys/net/ipv4/tcp_keepalive_intvl. The default time wait interval on newer Linux systems is 60 seconds and as such there is no need to change this. If the need arises that TCP/IP settings must be adjusted follow these steps:

  • Edit the /etc/sysctl.conf and add the following lines:
    		net.ipv4.tcp_rmem = 4096    87380   4194304
    		net.ipv4.tcp_wmem = 4096    16384   4194304
    		net.ipv4.tcp_sack = 1
    		net.ipv4.tcp_timestamps = 1
    		net.ipv4.tcp_window_scaling = 1
    		net.ipv4.tcp_keepalive_time = 7200
    		net.ipv4.tcp_keepalive_intvl = 75
    		net.ipv4.tcp_fin_timeout = 60
    		
  • Run /sbin/sysctl -p to make the changes effective. By executing, for example, cat /proc/sys/net/ipv4/tcp_keepalive_time we can check the current values.

Network interface card (NIC)

Configure the network card at it’s maximum link speed and at full duplex. To determine the configuration of the network card we can use:

[root@middleware-magic oracle]# /sbin/ethtool eth0
Settings for eth0:
	Supported ports: [ TP ]
	Supported link modes:   10baseT/Half 10baseT/Full
							100baseT/Half 100baseT/Full
							1000baseT/Full
	Supports auto-negotiation: Yes
	Advertised link modes:  10baseT/Half 10baseT/Full
							100baseT/Half 100baseT/Full
							1000baseT/Full
	Advertised auto-negotiation: Yes
	Speed: 1000Mb/s
	Duplex: Full
	Port: Twisted Pair
	PHYAD: 0
	Transceiver: internal
	Auto-negotiation: on
	Supports Wake-on: d
	Wake-on: d
	Current message level: 0x00000007 (7)
	Link detected: yes

To change the maximum speed and duplex style we can use, for example, /sbin/ethtool -s eth0 speed 1000 duplex full.

Maximum transaction unit (MTU)

MTU is the maximum packet size, in bytes, that can be transmitted across a link. By default, an MTU of 1500 bytes is assumed and a default packet size of 1500 – 32 = 1468 bytes is used. To determine the MTU we can use the ping utility, for example,

[oracle@middleware-magic ~]$ ping -c 3 -M do -s 1468 172.31.0.175
PING 172.31.0.175 (172.31.0.175) 1468(1496) bytes of data.
1476 bytes from 172.31.0.175: icmp_seq=1 ttl=64 time=0.250 ms
1476 bytes from 172.31.0.175: icmp_seq=2 ttl=64 time=0.075 ms
1476 bytes from 172.31.0.175: icmp_seq=3 ttl=64 time=0.069 ms

--- 172.31.0.175 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.069/0.131/0.250/0.084 ms

Swapping

Swapping, also known as paging, is the use of secondary storage to store and retrieve data for use in RAM. Swapping is automatically performed by the operating system and typically occurs when the available RAM memory is depleted. Swapping can have a significant impact on the performance of Coherence and should thus be avoided. One thing to avoid swapping is to have enough RAM available – a tool such as top can be used to monitor swap rates. The swappiness (swap out a process or some of its heap due to low resource usage) should also be avoided for Coherence. To obtain the current value for swappiness, we can use cat /proc/sys/vm/swappiness. For Coherence, a low value (0 if possible) should be set. To change the swappiness, open the /etc/sysctl.conf file and add the following:

# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 0 is disabled, 1 is enabled.  See sysctl(8) and
# sysctl.conf(5) for more details.

# Controls IP packet forwarding
net.ipv4.ip_forward = 0

# Controls source route verification
net.ipv4.conf.default.rp_filter = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename
# Useful for debugging multi-threaded applications
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1

# Controls the maximum size of a message, in bytes
kernel.msgmnb = 65536

# Controls the default maxmimum size of a mesage queue
kernel.msgmax = 65536

# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736

# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296

# increase TCP max buffer size
net.core.rmem_max = 2096304
net.core.wmem_max = 2096304
net.core.rmem_default=2096304
net.core.wmem_default=2096304

# set the swappiness to zero
vm.swappiness = 0

Large pages

Large pages are essentially blocks of contiguous physical memory addresses that are reserved for a process. Large pages improve performance of applications that access memory frequently (as is the case when using Coherence). When large pages are used the application uses the translation look-aside buffer (TLB) in the processor more effectively. The TLB is a cache of recently used virtual-to-physical address space translations stored in the processor memory. To obtain data from memory, the processor looks up the TLB to find out the physical addresses (RAM or hard disk) that hold the required data. In the case of large pages, a single entry in the TLB could represent a large contiguous address space and thereby potentially reducing the TLB look-up frequency and avoiding frequent look-ups in the hierarchical page table stored in-memory.

The kernel built with hugepage support (CONFIG_HUGETLBFS and CONFIG_HUGETLB_PAGE selected) should show the number of configured hugepages in the system by running cat /proc/meminfo:

[root@middleware-magic oracle]# cat /proc/meminfo
MemTotal:      4044532 kB
MemFree:       3411928 kB
Buffers:        167968 kB
Cached:         195860 kB
SwapCached:          0 kB
Active:         262596 kB
Inactive:       247148 kB
HighTotal:           0 kB
HighFree:            0 kB
LowTotal:      4044532 kB
LowFree:       3411928 kB
SwapTotal:     6088624 kB
SwapFree:      6088536 kB
Dirty:             232 kB
Writeback:           0 kB
AnonPages:      146020 kB
Mapped:          52732 kB
Slab:            79676 kB
PageTables:      19360 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   8110888 kB
Committed_AS:   426808 kB
VmallocTotal: 34359738367 kB
VmallocUsed:    265976 kB
VmallocChunk: 34359471959 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

where,

  • HugePages_Total is the size of the pool of hugepages.
  • HugePages_Free is the number of hugepages in the pool that are not yet allocated.
  • HugePages_Rsvd is short for reserved, and is the number of hugepages for which a commitment to allocate from the pool has been made, but no allocation has yet been made.
  • Hugepagesize is the configured hugepage size.

Also cat /proc/filesystems should show a filesystem of type hugetlbfs configured in the kernel:

[root@middleware-magic oracle]# cat /proc/filesystems
nodev   sysfs
nodev   rootfs
nodev   bdev
nodev   proc
nodev   cpuset
nodev   binfmt_misc
nodev   debugfs
nodev   securityfs
nodev   sockfs
nodev   usbfs
nodev   pipefs
nodev   anon_inodefs
nodev   futexfs
nodev   tmpfs
nodev   inotifyfs
nodev   eventpollfs
nodev   devpts
        ext2
nodev   ramfs
nodev   hugetlbfs
        iso9660
nodev   mqueue
        ext3
nodev   rpc_pipefs
nodev   autofs

The following command can be used to dynamically allocate/deallocate hugepages: echo 1024 > /proc/sys/vm/nr_hugepages. This command will try to configure 1024 hugepages in the system. The success or failure of allocation depends on the amount of physically contiguous memory that is present in the system at this time. At times, the JVM might not be able to reserve large pages because the pages might not be contiguous. To ensure that the JVM can use large pages, these must be enabled in the operating system as soon as possible after the system starts; otherwise the memory can become too fragmented which leads to a reduction in the number of large pages. In order to accomplish this, we can put the command in the /etc/rc.d/rc.local script, for example,

#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

# set the sharable memory size - in this case we set the memory size to 4GB:
# 1024*1024*1024*4 = 4294967296
echo 4294967296 > /proc/sys/kernel/shmmax

# set the number of huge pages based on the Hugepagesize, i.e., 2048kB
# when we want to reserve 2GB in huge pages we have to set the number of huge pages to:
# (1024*1024*1024*2)/(1024*1024*2) = 2147483648/2097152 = 1024
echo 1024 > /proc/sys/vm/nr_hugepages

# give permission to the group that runs the process to access the shared memory segment
# to this end open the /etc/group file and retrieve the group-id (oracle:x:500:)
echo 500 > /proc/sys/vm/hugetlb_shm_group

Next, we set the locked in-memory address space for the oracle user in the file /etc/security/limits.conf, i.e.,

# memlock - maximum locked in-memory address space (kB), we set this equal to:
# number_of_huge_pages * huge_page_size = 1024 * 2048 = 2097152
oracle  soft    memlock 2097152
oracle  hard    memlock 2097152

When using JRockit we have to make a hugetblfs file system available in the directory /mnt/hugepages. This can be accomplished by using mount -t hugetlbfs nodev /mnt/hugepages (note that the /mnt/hugepages directory must exist). To make the /mnt/hugepages directory accessible for the oracle user, we can use chmod -R 777 /mnt/hugepages and add it to /etc/rc.d/rc.local. To make the mount permanent we have to edit the /etc/fstab file, for example,

LABEL=/                 /                       ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
LABEL=SWAP-sda2         swap                    swap    defaults        0 0
nodev                   /mnt/hugepages       hugetlbfs  defaults        0 0

Network test

Coherence ships with a datagram test utility that can be used to test and tune the network performance between two or more machines. When the datagram test is run, a publisher transmits UDP packets to the listener who then measures the throughput, success rate etcetera. Based on the results the environment can then be tuned for performance. The datagram test can be run by using datagram-test.sh, which is located in the ${COHERENCE_HOME}/bin directory. Before the script can be run add the JAVA_HOME property, for example,

#!/bin/sh

JAVA_HOME="/home/oracle/jrrt-4.0.1-1.6.0"
export JAVA_HOME

# specify the Coherence installation directory
SCRIPT_PATH="${BASH_SOURCE[0]}";
...

To run the datagram test, start a listener on one server, by just using datagram-test.sh on the command-line. Then start a publisher on another server, for example, datagram-test.sh hostname_or_ip_of_the_listener_server.

The term multi-cast refers to the ability to send a packet of information from one server and to have that packet delivered in parallel by the network to many servers. Coherence supports both multi-cast and uni-cast clustering. Note that multi-cast is the default and is the recommended setting. In some cases however, multi-cast cannot be used, for example, multi-cast cannot operate over certain types of network equipment, such as WAN routers and some switches that do not support multi-cast. Before we deploy an application that uses multi-cast, we have to determine if multi-cast is enabled. To this end, we can use the multicast-test.sh script, which is also located in the ${COHERENCE_HOME}/bin directory. In this script the variable JAVA_HOME also has to be set, for example,

#!/bin/sh

JAVA_HOME="/home/oracle/jrrt-4.0.1-1.6.0"
export JAVA_HOME

JAVA_OPTIONS="-Dhttp.proxyHost=proxy.middleware-magic.com -Dhttp.proxyPort=3128 -Djava.net.preferIPv4Stack=true"
export JAVA_OPTIONS

# specify the Coherence installation directory
SCRIPT_PATH="${BASH_SOURCE[0]}";
...

The test can be run by starting multicast-test.sh on the servers. When multicast is not working properly, i.e., no packets are received from other servers, we have to resort to well-known-addresses (WKA). To define well-known-addresses we can use the tangosol-coherence-override.xml file, for example,

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config" xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">
    <cluster-config>
        <unicast-listener>
            <well-known-addresses>
                <socket-address id="1">
                    <address>172.31.0.175</address>
                    <port>8088</port>
                </socket-address>
                <socket-address id="2">
                    <address>172.31.0.113</address>
                    <port>8088</port>
                </socket-address>
            </well-known-addresses>
        </unicast-listener>
    </cluster-config>
</coherence>

Something about the load average that is displayed when using, for example, top:

top - 09:16:42 up 4 days, 17:43,  4 users,  load average: 0.91, 0.87, 0.77
Tasks: 129 total,   2 running, 127 sleeping,   0 stopped,   0 zombie
Cpu(s): 19.0%us,  6.8%sy,  0.0%ni, 69.0%id,  0.0%wa,  1.2%hi,  4.0%si,  0.0%st
Mem:   4044532k total,  3909728k used,   134804k free,   239356k buffers
Swap:  6088624k total,        0k used,  6088624k free,   577888k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
27790 oracle    17   0 1535m 540m  10m S 31.3 13.7  10:04.21 java
27750 oracle    18   0 1531m 133m  10m S 22.6  3.4   7:14.01 java
 3992 oracle    15   0  425m  33m  18m S  0.3  0.8   0:09.16 nautilus
    1 root      15   0 10348  688  580 S  0.0  0.0   0:00.61 init
    2 root      RT  -5     0    0    0 S  0.0  0.0   0:00.17 migration/0
    3 root      34  19     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/0
    4 root      RT  -5     0    0    0 S  0.0  0.0   0:00.08 migration/1
    5 root      34  19     0    0    0 S  0.0  0.0   0:00.00 ksoftirqd/1
    6 root      10  -5     0    0    0 S  0.0  0.0   0:00.03 events/0
    7 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 events/1
    8 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 khelper
   49 root      11  -5     0    0    0 S  0.0  0.0   0:00.00 kthread
   54 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/0
   55 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 kblockd/1
   56 root      14  -5     0    0    0 S  0.0  0.0   0:00.00 kacpid
  215 root      12  -5     0    0    0 S  0.0  0.0   0:00.00 cqueue/0
  216 root      12  -5     0    0    0 S  0.0  0.0   0:00.00 cqueue/1

The mathematics behind it are clearly explained in the articles UNIX Load Average Part 1: How It Works and UNIX Load Average Part 2: Not Your Average Average. An example, say we have the following load average: 0.91 0.87 0.77. These numbers represent the number of processes waiting in the run-queue plus the ones running at the moment in periods of 1, 5 and 15 minutes. Looking at the load average number, we have a one minute load average of 0.91, a five minute load average of 0.87 and a fifteen minute load average of 0.77. From this we can draw the following conclusions:

  • On average in the last minute 0.91 processes have been running or are waiting for a response.
  • The trend is that the load is increasing, i.e., an average of 0.91 is higher than 0.87 and 0.77.
  • The system is busy, but we can not conclude how busy based on the load. What can be concluded is that a system with a load average higher than the number of CPUs has too much to do. On the other hand, a system with a load average significantly lower than the number of CPUs is not running up to its capacity.

Tune the Java Virtual Machine

In the posts Tune the JVM that runs Coherence and Tune the JVM that runs Coherence Revisited comprehensive discussions are made for respectively the JRockit JVM and the HotSpot JVM. To incorporate the knowledge presented in the posts in scripts to start cluster nodes, we can use the following to start a default cache server that collects management data:

#!/bin/sh

# JMX configuration for JRockit
#JMX_OPTIONS="-Djava.rmi.server.hostname=172.31.0.113 -Xmanagement:ssl=false,authenticate=false,port=7091,autodiscovery=true"

# JMX configuration for HotSpot
JMX_OPTIONS="-Dcom.sun.management.jmxremote.port=7091 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"

# Coherence options to collect management information
COHERENCE_MANAGEMENT_OPTIONS="-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true"

# Cache configuration to use
COHERENCE_OPTIONS="-Dtangosol.coherence.cacheconfig=tryout-cache-config.xml ${COHERENCE_MANAGEMENT_OPTIONS} ${JMX_OPTIONS}"
export COHERENCE_OPTIONS

# JRockit Home
#JAVA_HOME="/home/oracle/jrrt-4.0.1-1.6.0"

# HotSpot Home
JAVA_HOME="/home/oracle/jdk1.6.0_24"
export JAVA_HOME

# Memory arguments for JRockit
#MEM_ARGS="-jrockit -Xms1024m -Xmx1024m -Xns256m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -XX:+UseCallProfiling -XX:+UseLargePagesForHeap"

# Memory arguments for HotSpot
MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"
export MEM_ARGS

# Set the class path
CLASSPATH="/home/oracle/temp/TryOut/lib/Coherence/coherence-hibernate.jar:/home/oracle/temp/TryOut/lib/Coherence/commonj.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence-work.jar:/home/oracle/temp/TryOut/lib/Database/ojdbc6.jar:/home/oracle/temp/TryOut/lib/Hibernate/jta.jar:/home/oracle/temp/TryOut/lib/Hibernate/ehcache-1.2.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/hibernate3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-logging-1.0.4.jar:/home/oracle/temp/TryOut/lib/Hibernate/dom4j-1.6.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/cglib-2.1.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-collections-2.1.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm.jar:/home/oracle/temp/TryOut/lib/Hibernate/c3p0-0.9.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/antlr-2.7.6.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm-attrs.jar:/home/oracle/temp/TryOut/out/artifacts/test/test.jar"
export CLASSPATH

# start the default cache server
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} com.tangosol.net.DefaultCacheServer

To start other nodes we can use:

#!/bin/sh

# Cache configuration to use
COHERENCE_OPTIONS="-Dtangosol.coherence.cacheconfig=tryout-cache-config.xml"
export COHERENCE_OPTIONS

# JRockit Home
#JAVA_HOME="/home/oracle/jrrt-4.0.1-1.6.0"

# HotSpot Home
JAVA_HOME="/home/oracle/jdk1.6.0_24"
export JAVA_HOME

# Memory arguments for JRockit
#MEM_ARGS="-jrockit -Xms1024m -Xmx1024m -Xns256m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -XX:+UseCallProfiling -XX:+UseLargePagesForHeap"

# Memory arguments for HotSpot
MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"
export MEM_ARGS

# Set the class path
CLASSPATH="/home/oracle/temp/TryOut/lib/Coherence/coherence-hibernate.jar:/home/oracle/temp/TryOut/lib/Coherence/commonj.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence-work.jar:/home/oracle/temp/TryOut/lib/Database/ojdbc6.jar:/home/oracle/temp/TryOut/lib/Hibernate/jta.jar:/home/oracle/temp/TryOut/lib/Hibernate/ehcache-1.2.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/hibernate3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-logging-1.0.4.jar:/home/oracle/temp/TryOut/lib/Hibernate/dom4j-1.6.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/cglib-2.1.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-collections-2.1.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm.jar:/home/oracle/temp/TryOut/lib/Hibernate/c3p0-0.9.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/antlr-2.7.6.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm-attrs.jar:/home/oracle/temp/TryOut/out/artifacts/test/test.jar"
export CLASSPATH

# start the test
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} model.test.Test

To understand what cache size is required, we can determine how many JVMs, how much physical memory, and how many CPUs and servers are required. As a general rule, allocate at least three times the physical heap size as the data set size. This assumes, we are going to keep one backup copy. The cache memory requirement can be calculated as: cache memory requirement = ((size of cache entries + size of indexes) * 2 (for primary and backup)) + JVM work memory (approx 30% of 1GB JVM). A cache entry can be calculated as entry size = serialized form of key + serialized form of value + 150 bytes and the index size as index size = forward index map + backward index map + reference + value size. Note that sizing of a cache is not an exact science and usually assumptions on the size and maximum number of objects have to be made.

Looking at servers, it is recommended that servers be configured with a minimum of 4GB of RAM. Commodity x86 server RAM is available in a density of 2GB per DIMM, so a server with 8 memory slots supports 16GB. One thing to note is that a server with a large amount of RAM is likely to run more JVMs (Coherence nodes). In this case a larger amount of CPU cores will help. Applications that are data-heavy require a higher ratio of RAM to CPU, while applications that are processing-heavy require a lower ratio. This means that it may be sufficient to have two dual core Xeon CPUs in a 32GB server running 15 Coherence nodes that perform cache accesses and updates, while on the other hand an application that makes use of indexing, parallel queries, entry processors and parallel aggregation it is more effective to use two quad cores Xeon CPUs in a 16GB server.

The following rules from the documentation should be followed in determining how many servers are required for reliable high availability configuration and how to configure the number of storage-enabled JVMs:

  • There must be more than two servers. When starting out with two servers with an equal number of JVMs, losing one JVM forces the grid out of machine-safe state. Four or more servers present the most stable topology, but deploying to three servers would work if the following rules are adhered to.
  • For a server that has the largest number of JVMs in the cluster, that number of JVMs must not exceed the total number of JVMs on all the other servers in the cluster.
  • A server with the smallest number of JVMs should run at least half the number of JVMs as the server with the largest number of JVMs.
  • The margin of safety improves as the number JVMs tends toward equality on all computers in the cluster, which is the general practice.

The number of JVMs (nodes) to run per server depends on the server’s number of processors/cores and the amount of memory. As a start, plan to run one JVM for every two cores. This recommendation balances the following factors:

  • Multiple JVMs per server allow Coherence to make more efficient use of network resources. Coherence’s packet-publisher and packet-receiver have a fixed number of threads per JVM (when cores are added, we can add JVMs to scale across the added cores).
  • Too many JVMs increases contention and context switching on processors.
  • Too few JVMs may not be able to handle available memory and may not fully use the network interface card (NIC).
  • For large heap sizes, JVMs must have enough processing capacity available (1 core per 2GB is ideal) to avoid long garbage collection pauses.
    • Pause times increase as the amount of live data increases. Staying below 70% is a good goal, this includes primary data, backup data, indexes and application data.
    • High object allocation rates increase pause times. Note that Coherence applications can cause high object allocation as every network packet generates many objects.
    • CPU-intensive computations increase contention and may result in higher pause times.

Now that we have put most things in place, let us turn our attention to the monitoring of the Coherence cluster.

Monitoring

The steps to set-up the Oracle Coherence Monitor from SL-corporation are the following:

  • We set-up the Oracle Coherence Monitor on a separate Windows machine.
  • Unzip the Oracle Coherence Monitor package rtv_ocm_5.8.0.0.zip to rtvoc_5.8.0.0.
  • Open a command prompt and check if Java is available, by using, java -version.
  • Run the set-up file rtvoc_setup.bat (located in the rtvoc_5.8.0.0 directory).
  • Run the rtvoc_cmd.bat file and verify the environment variables that are set by using set RTV on the command prompt.
  • Create a cluster property file. In the rtvoc_5.8.0.0\conf directory, make a copy of the SampleCluster.properties file and call this, for example, KlantCluster.properties.
  • Configure a connection to the Coherence cluster. In our case, we are going to use the JMX Remote Port option. Note that we added -Djava.rmi.server.hostname=172.31.0.113 -Xmanagement:ssl=false,authenticate=false,port=7091,autodiscovery=true for JRockit and -Dcom.sun.management.jmxremote.port=7091 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false for HotSpot to the script that starts the default cache server. Open the KlantCluster.properties file, and adjust the following parameters:
    • sl.rtview.ocm.node=false (Oracle Coherence Monitor does not connect as a node)
    • tangosol.coherence.cluster=KlantCluster (not used when the Oracle Coherence Monitor does not connect as a node)
    • sl.rtview.ocm.jmxhost=172.31.0.113 (host on which the default cache server, that collects management data, will be running)
    • sl.rtview.ocm.jmxport=7091 (configured JMX port)
  • Edit the coherence_setup.bat file (located in the rtvoc_5.8.0.0\conf directory) and specify the path of the coherence jar files, for example,
    • set COHERENCE_CLASSPATH=C:\documents\Coherence\Voorbeelden\TryOut\lib\Coherence\coherence.jar
    • set COHERENCE_CLASSPATH=%COHERENCE_CLASSPATH%;%RTVOC_HOME%/lib/ocjmxtables.jar
    • set COHERENCE_CLUSTER=KlantCluster

To test the set-up, start the default cache server on one of the Linux machines. On the Windows machine where the Oracle Coherence Monitor (OCM) is installed, perform the following steps to start the monitoring:

  • After the set-up script is run, a shortcuts map is placed on the desktop. Open this map and start the OCM Database.
  • Subsequently, start the OCM Data Server, the OCM Display Server (DS) and the OCM Historian (DS).
  • Finally, start the OCM Monitor, which can be run either as a client or as a web application deployed, for example, on Apache Tomcat.
    • To deploy it as a web application by using Apache Tomcat:
      • Unzip the apache-tomcat-6.0.18-sl.zip file to apache-tomcat-6.0.18-sl.
      • Open the startup.bat file (located in the apache-tomcat-6.0.18-sl\bin directory) and add the variables JAVA_HOME and JRE_HOME such they point to a valid JDK, for example, set JAVA_HOME=C:\Progra~1\Java\jdk1.6.0_21 and set JRE_HOME=C:\Progra~1\Java\jdk1.6.0_21.
      • Start up Apache Tomcat by running startup.bat.
      • Deploy myocm.war (located in the rtvoc_5.8.0.0\webconf directory) to Apache Tomcat, by copying it to the apache-tomcat-6.0.18-sl\webapps directory.
      • The Oracle Coherence Monitor can be reached at http://hostname:8068/myocm/. Login with username: demo and password: demo.
    • To use the client, run the OCM Monitor (DS) in the shortcuts map. Note that flash must be available in order to view the graphs.
  • In the OCM monitor click cluster views, overview and check if one node is present.

On the second machine start a test node, which will start putting data into the cache and getting data from the cache. Subsequently, start two other test nodes, one on each machine.

Default cache server (on machine 172.31.0.113) log:

2012-01-05 11:08:26.245/0.432 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence.xml"
2012-01-05 11:08:26.310/0.497 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-01-05 11:08:26.375/0.562 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tangosol-coherence-override.xml"
2012-01-05 11:08:26.379/0.566 Oracle Coherence 3.7.1.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2012-01-05 11:08:26.974/1.161 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-cache-config.xml"
2012-01-05 11:08:27.029/1.216 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded Reporter configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/reports/report-group.xml"
2012-01-05 11:08:27.389/1.576 Oracle Coherence GE 3.7.1.0 <D4> (thread=main, member=n/a): TCMP bound to /172.31.0.113:8088 using SystemSocketProvider
2012-01-05 11:08:30.709/4.896 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): Created a new cluster with Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2) UID=0xAC1F007100000134AD574F23DBA31F98
2012-01-05 11:08:30.712/4.899 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Started cluster Name=n/a

WellKnownAddressList(Size=2,
  WKA{Address=172.31.0.113, Port=8088}
  WKA{Address=172.31.0.175, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
  OldestMember=Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2012-01-05 11:08:30.709|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2012-01-05 11:08:30.732/4.919 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2012-01-05 11:08:31.018/5.205 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=1): Loaded POF configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-pof-config.xml"
2012-01-05 11:08:31.041/5.228 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=1): Loaded included POF configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/coherence-pof-config.xml"
2012-01-05 11:08:31.085/5.272 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=1): Service DistributedReadWriteCache joined the cluster with senior service member 1
2012-01-05 11:08:31.115/5.302 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=1):
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7.1, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  PartitionedCache{Name=DistributedReadWriteCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257, BackupPartitions=0}
  )

Started DefaultCacheServer...

2012-01-05 11:17:37.822/552.009 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:17:37.939/552.126 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2012-01-05 11:17:38.534/552.721 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:17:39.734/553.921 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=1): 1> Transferring vulnerable PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127} to member 2 requesting 128
2012-01-05 11:17:44.394/558.581 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=1): 1> Transferring 129 out of 129 partitions to a machine-safe backup 1 at member 2 (under 129)
2012-01-05 11:17:44.409/558.596 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=1): Transferring 0KB of backup[1] for PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256} to member 2
2012-01-05 11:19:08.638/642.825 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=3, Timestamp=2012-01-05 11:19:08.622, Address=172.31.0.113:8090, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13350, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:19:08.913/643.100 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 3 joined Service Management with senior member 1
2012-01-05 11:19:10.519/644.706 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 3 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:19:10.528/644.715 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=1): 3> Transferring primary PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170} to member 3 requesting 43
2012-01-05 11:19:28.348/662.535 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=4, Timestamp=2012-01-05 11:19:28.164, Address=172.31.0.175:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8480, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:19:28.686/662.873 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 4 joined Service Management with senior member 1
2012-01-05 11:19:30.817/665.004 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 4 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:19:30.824/665.011 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=1): 3> Transferring primary PartitionSet{171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191} to member 4 requesting 21
2012-01-05 11:19:30.894/665.081 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=1): Transferring 230KB of backup[1] for PartitionSet{192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255} to member 4
2012-01-05 11:19:33.329/667.516 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=1): Transferring 76KB of backup[1] for PartitionSet{192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212} to member 2

Member two server (on machine 172.31.0.175) log:

2012-01-05 11:16:57.254/0.447 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence.xml"
2012-01-05 11:16:57.345/0.538 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-01-05 11:16:57.500/0.693 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tangosol-coherence-override.xml"
2012-01-05 11:16:57.505/0.698 Oracle Coherence 3.7.1.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2012-01-05 11:16:58.234/1.427 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-cache-config.xml"
2012-01-05 11:16:58.886/2.079 Oracle Coherence GE 3.7.1.0 <D4> (thread=main, member=n/a): TCMP bound to /172.31.0.175:8088 using SystemSocketProvider
2012-01-05 11:16:59.179/2.373 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): This Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1) joined cluster with senior Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2)
2012-01-05 11:16:59.200/2.393 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
2012-01-05 11:16:59.200/2.393 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:16:59.218/2.411 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Started cluster Name=n/a

WellKnownAddressList(Size=2,
  WKA{Address=172.31.0.113, Port=8088}
  WKA{Address=172.31.0.175, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest)
  OldestMember=Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
  ActualMemberSet=MemberSet(Size=2
    Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
    Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2012-01-05 11:08:27.427|JOINED,
    2|3.7.1|2012-01-05 11:17:37.831|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[1]}
IpMonitor{AddressListSize=1}

2012-01-05 11:16:59.289/2.482 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2012-01-05 11:16:59.755/2.948 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=2): Loaded POF configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-pof-config.xml"
2012-01-05 11:16:59.784/2.977 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=2): Loaded included POF configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/coherence-pof-config.xml"
2012-01-05 11:16:59.848/3.041 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=2): Service DistributedReadWriteCache joined the cluster with senior service member 1
2012-01-05 11:16:59.895/3.088 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=2): Asking member 1 for 128 primary partitions
2012-01-05 11:18:29.998/93.191 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member(Id=3, Timestamp=2012-01-05 11:19:08.622, Address=172.31.0.113:8090, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13350, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:18:30.274/93.467 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member 3 joined Service Management with senior member 1
2012-01-05 11:18:31.878/95.071 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member 3 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:18:32.282/95.475 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=2): 3> Transferring primary PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41} to member 3 requesting 42
2012-01-05 11:18:32.572/95.765 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=2): Transferring 129KB of backup[1] for PartitionSet{42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83} to member 3
2012-01-05 11:18:49.710/112.903 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member(Id=4, Timestamp=2012-01-05 11:19:28.164, Address=172.31.0.175:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8480, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:18:50.040/113.233 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member 4 joined Service Management with senior member 1
2012-01-05 11:18:52.171/115.364 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member 4 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:18:52.899/116.092 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=2): 3> Transferring primary PartitionSet{42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62} to member 4 requesting 21
2012-01-05 11:18:55.278/118.471 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=2): 3> Transferring primary PartitionSet{63} to member 4 requesting 1

Member three server (on machine 172.31.0.113) log:

2012-01-05 11:19:06.954/0.372 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence.xml"
2012-01-05 11:19:07.016/0.434 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-01-05 11:19:07.084/0.502 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tangosol-coherence-override.xml"
2012-01-05 11:19:07.088/0.506 Oracle Coherence 3.7.1.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2012-01-05 11:19:07.634/1.052 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-cache-config.xml"
2012-01-05 11:19:08.342/1.760 Oracle Coherence GE 3.7.1.0 <D4> (thread=main, member=n/a): TCMP bound to /172.31.0.113:8090 using SystemSocketProvider
2012-01-05 11:19:08.648/2.066 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): This Member(Id=3, Timestamp=2012-01-05 11:19:08.622, Address=172.31.0.113:8090, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13350, Role=ModelTestTest, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2) joined cluster with senior Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2)
2012-01-05 11:19:08.842/2.260 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:19:08.857/2.275 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
2012-01-05 11:19:08.857/2.275 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:19:08.859/2.277 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 2 joined Service Management with senior member 1
2012-01-05 11:19:08.859/2.277 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 2 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:19:08.860/2.278 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Started cluster Name=n/a

WellKnownAddressList(Size=2,
  WKA{Address=172.31.0.175, Port=8088}
  WKA{Address=172.31.0.113, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=3, Timestamp=2012-01-05 11:19:08.622, Address=172.31.0.113:8090, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13350, Role=ModelTestTest)
  OldestMember=Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
  ActualMemberSet=MemberSet(Size=3
    Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
    Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest)
    Member(Id=3, Timestamp=2012-01-05 11:19:08.622, Address=172.31.0.113:8090, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13350, Role=ModelTestTest)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2012-01-05 11:08:27.427|JOINED,
    2|3.7.1|2012-01-05 11:17:37.641|JOINED,
    3|3.7.1|2012-01-05 11:19:08.853|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[2]}
IpMonitor{AddressListSize=1}

2012-01-05 11:19:08.903/2.322 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=3): Service Management joined the cluster with senior service member 1
2012-01-05 11:19:09.253/2.671 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=3): Loaded POF configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-pof-config.xml"
2012-01-05 11:19:09.287/2.705 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=3): Loaded included POF configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/coherence-pof-config.xml"
2012-01-05 11:19:09.347/2.765 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=3): Service DistributedReadWriteCache joined the cluster with senior service member 1
2012-01-05 11:19:10.521/3.939 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=3): Asking member 1 for 43 primary partitions
2012-01-05 11:19:10.896/4.314 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=3): Asking member 2 for 42 primary partitions
2012-01-05 11:19:11.222/4.640 Oracle Coherence GE 3.7.1.0 <D5> (thread=main, member=3): Repeating GetAllRequest for 2 out of 6 items due to the re-distribution of PartitionSet{11, 21}
2012-01-05 11:19:28.349/21.767 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member(Id=4, Timestamp=2012-01-05 11:19:28.164, Address=172.31.0.175:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8480, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:19:28.686/22.104 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 4 joined Service Management with senior member 1
2012-01-05 11:19:30.817/24.235 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 4 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:19:31.267/24.685 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=3): 1> Transferring vulnerable PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19} to member 4 requesting 20
2012-01-05 11:19:31.352/24.770 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=3): Transferring 75KB of backup[1] for PartitionSet{20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41} to member 4
2012-01-05 11:19:34.033/27.451 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=3): 3> Transferring primary PartitionSet{128} to member 4 requesting 1

Member four server (on machine 172.31.0.175) log:

2012-01-05 11:18:47.021/0.657 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence.xml"
2012-01-05 11:18:47.220/0.856 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/tangosol-coherence-override-dev.xml"
2012-01-05 11:18:47.454/1.090 Oracle Coherence 3.7.1.0 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tangosol-coherence-override.xml"
2012-01-05 11:18:47.464/1.100 Oracle Coherence 3.7.1.0 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2012-01-05 11:18:48.098/1.734 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Loaded cache configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-cache-config.xml"
2012-01-05 11:18:49.411/3.047 Oracle Coherence GE 3.7.1.0 <D4> (thread=main, member=n/a): TCMP bound to /172.31.0.175:8090 using SystemSocketProvider
2012-01-05 11:18:49.719/3.355 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): This Member(Id=4, Timestamp=2012-01-05 11:19:28.164, Address=172.31.0.175:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8480, Role=ModelTestTest, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1) joined cluster with senior Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2)
2012-01-05 11:18:49.911/3.547 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:18:49.940/3.576 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member(Id=3, Timestamp=2012-01-05 11:19:08.622, Address=172.31.0.113:8090, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13350, Role=ModelTestTest) joined Cluster with senior member 1
2012-01-05 11:18:49.947/3.583 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 2 joined Service Management with senior member 2
2012-01-05 11:18:49.948/3.584 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 2 joined Service DistributedReadWriteCache with senior member 2
2012-01-05 11:18:49.948/3.584 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
2012-01-05 11:18:49.948/3.585 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:18:49.949/3.585 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 3 joined Service Management with senior member 1
2012-01-05 11:18:49.949/3.585 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 3 joined Service DistributedReadWriteCache with senior member 1
2012-01-05 11:18:49.952/3.588 Oracle Coherence GE 3.7.1.0 <Info> (thread=main, member=n/a): Started cluster Name=n/a

WellKnownAddressList(Size=2,
  WKA{Address=172.31.0.113, Port=8088}
  WKA{Address=172.31.0.175, Port=8088}
  )

MasterMemberSet(
  ThisMember=Member(Id=4, Timestamp=2012-01-05 11:19:28.164, Address=172.31.0.175:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8480, Role=ModelTestTest)
  OldestMember=Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
  ActualMemberSet=MemberSet(Size=4
    Member(Id=1, Timestamp=2012-01-05 11:08:27.427, Address=172.31.0.113:8088, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13253, Role=CoherenceServer)
    Member(Id=2, Timestamp=2012-01-05 11:17:37.641, Address=172.31.0.175:8088, MachineId=65081, Location=site:,machine:middleware-magic,process:8411, Role=ModelTestTest)
    Member(Id=3, Timestamp=2012-01-05 11:19:08.622, Address=172.31.0.113:8090, MachineId=56227, Location=site:,machine:edu-wls-rh,process:13350, Role=ModelTestTest)
    Member(Id=4, Timestamp=2012-01-05 11:19:28.164, Address=172.31.0.175:8090, MachineId=65081, Location=site:,machine:middleware-magic,process:8480, Role=ModelTestTest)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2012-01-05 11:08:27.427|JOINED,
    2|3.7.1|2012-01-05 11:17:37.641|JOINED,
    3|3.7.1|2012-01-05 11:19:08.622|JOINED,
    4|3.7.1|2012-01-05 11:19:28.586|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[3]}
IpMonitor{AddressListSize=1}

2012-01-05 11:18:50.027/3.663 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=4): Service Management joined the cluster with senior service member 1
2012-01-05 11:18:50.564/4.200 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=4): Loaded POF configuration from "jar:file:/home/oracle/temp/TryOut/out/artifacts/test/test.jar!/tryout-pof-config.xml"
2012-01-05 11:18:50.601/4.237 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache:DistributedReadWriteCache, member=4): Loaded included POF configuration from "jar:file:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar!/coherence-pof-config.xml"
2012-01-05 11:18:50.675/4.311 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=4): Service DistributedReadWriteCache joined the cluster with senior service member 1
2012-01-05 11:18:52.174/5.810 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=4): Asking member 1 for 21 primary partitions
2012-01-05 11:18:52.600/6.236 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=4): Asking member 3 for 20 primary partitions
2012-01-05 11:18:52.882/6.519 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=4): Asking member 2 for 21 primary partitions
2012-01-05 11:18:53.151/6.787 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=4): Transferring 74KB of backup[1] for PartitionSet{171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191} to member 3
2012-01-05 11:18:55.275/8.911 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=4): Asking member 2 for 1 primary partitions
2012-01-05 11:18:55.386/9.022 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache:DistributedReadWriteCache, member=4): Asking member 3 for 1 primary partitions
2012-01-05 11:18:55.508/9.144 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache:DistributedReadWriteCache, member=4): Transferring 3KB of backup[1] for PartitionSet{128} to member 3

The reason for showing the logging is that it obtains insight in how the data partitioning in the Coherence cluster is going.

Results

In the cluster views, overview tab metrics and alerts are shown for the cluster.

The cluster views, all caches history tab, shows a heatmap that displays a summary of the recent activity on the caches running in the cluster.

The cluster views, all nodes history tab, shows a heatmap that displays a summary of the recent activity on the nodes running in the cluster. This tab can be used to identify which nodes are generating the most cluster activity (which gives us the possibility to do some pattern analysis in spotting hot spots in the cluster).

Coherence provides a lot of metrics through MBeans (when enabled), such as,

  • Node metrics (memory usage, network packets, packet loss)
  • Service metrics (CPU load, requests, messages, task backlog, requests pending)
  • Cache metrics (total puts/getsm total hits/misses, store writes/reads)

To get an idea of network activity, i.e., the number of packets (unit of network data transfer), the number of messages (command from one node to another, which could be multiple packets depending on the data size) and the number of requests (a message that expects a response message that returns data). The cache services, cache service detail tab, shows a table view of attributes, such as CPU%, requests and messages.

The all nodes, all nodes detail tab, shows detailed information such as the number of packets send, the number of packets received, the number of duplicate packets received and the number of packets resend.

The single cache, cache summary tab, shows an overview of the size and activity such as puts, gets, hits, misses, backups, evictions etcetera.

Activity trends can be viewed in the single cache, activity trends tab.

The single cache, node/group distribution gives us an indication of how well we are scaling the application (As the data is showing a uniform distribution, we are actually doing very well as scaling is concerned).

The Oracle Coherence Monitor from SL corporation is just an incredible tool, that will come in very handy when troubleshooting or monitoring the Coherence cluster. Special thanks to Everett Williams for the great explanation – hoping for more conversations in the future.

References

[1] Oracle Coherence Documentation Library.
[2] Real-Time Monitoring and Management Application for Oracle Coherence In-Memory Data Grids.


JBoss RichFaces, Facelets and Coherence on WebLogic

In this post, we build a JavaServer Faces application that uses JBoss RichFaces components. The application communicates with Coherence in order to store data. Before we get all excited let us start with the WebLogic set-up. The WebLogic environment, next to the AdminServer and the Node Manager, has two managed servers that are clustered. For the different components (JBoss RichFaces, JavaServer Facelets and Coherence) we create the following shared libraries. The coherence-3.7.war shared library has the following contents:

coherence-3.7
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			coherence.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: coherence
Specification-Title: Coherence Library
Specification-Version: 3.7
Specification-Vendor: Middleware Magic
Implementation-Title: Coherence Library
Implementation-Version: 3.7.1
Implementation-Vendor: Middleware Magic

The jsf-1.2.war shared library has the following contents:

jsf-1.2
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			jsf-api.jar
			jsf-facelets.jar
			jsf-impl.jar
			jstl-api-1.2.jar
			jstl-impl-1.2.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: JSF
Specification-Title: JavaServer Faces Library
Specification-Version: 1.2
Specification-Vendor: Middleware Magic
Implementation-Title: JavaServer Faces Library
Implementation-Version: 1.2.14
Implementation-Vendor: Middleware Magic

The jboss-richfaces-3.3.war shared library has the following contents:

jboss-richfaces-3.3
	META-INF
		MANIFEST.MF
	WEB-INF
		lib
			commons-beanutils-1.7.0.jar
			commons-collections-3.2.jar
			commons-digester-1.8.jar
			commons-logging-1.0.4.jar
			jhighlight-1.0.jar
			richfaces-api-3.3.1.GA.jar
			richfaces-impl-3.3.1.GA.jar
			richfaces-ui-3.3.1.GA.jar

in which the MANIFEST.MF contains:

Manifest-Version: 1.0
Created-By: 1.6.0_05 (BEA Systems, Inc.)
Extension-Name: jbossrichfaces
Specification-Title: JBoss RichFaces Library
Specification-Version: 3.3
Specification-Vendor: Middleware Magic
Implementation-Title: JBoss RichFaces Library
Implementation-Version: 3.3.1
Implementation-Vendor: Middleware Magic

When the shared libraries are created deploy these libraries to the cluster.

Set-up Coherence

Next, let us see if we can get Coherence to work in a WebLogic cluster. We create one entity, i.e.,

package model.entities;

import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

import java.io.IOException;

public class Klant implements PortableObject {

    private Integer klantnummer;
    private String naam;
    private String adres;
    private String stad;
    private String provincie;
    private String postcode;
    private Integer gebied;
    private String telefoonnummer;
    private Integer reputatieNummer;
    private Double kredietlimiet;
    private String commentaar;

    public Klant() {
    }

    public Integer getKlantnummer() {
        return klantnummer;
    }

    public void setKlantnummer(Integer klantnummer) {
        this.klantnummer = klantnummer;
    }

    public String getNaam() {
        return naam;
    }

    public void setNaam(String naam) {
        this.naam = naam;
    }

    public String getAdres() {
        return adres;
    }

    public void setAdres(String adres) {
        this.adres = adres;
    }

    public String getStad() {
        return stad;
    }

    public void setStad(String stad) {
        this.stad = stad;
    }

    public String getProvincie() {
        return provincie;
    }

    public void setProvincie(String provincie) {
        this.provincie = provincie;
    }

    public String getPostcode() {
        return postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

    public Integer getGebied() {
        return gebied;
    }

    public void setGebied(Integer gebied) {
        this.gebied = gebied;
    }

    public String getTelefoonnummer() {
        return telefoonnummer;
    }

    public void setTelefoonnummer(String telefoonnummer) {
        this.telefoonnummer = telefoonnummer;
    }

    public Integer getReputatieNummer() {
        return reputatieNummer;
    }

    public void setReputatieNummer(Integer reputatieNummer) {
        this.reputatieNummer = reputatieNummer;
    }

    public Double getKredietlimiet() {
        return kredietlimiet;
    }

    public void setKredietlimiet(Double kredietlimiet) {
        this.kredietlimiet = kredietlimiet;
    }

    public String getCommentaar() {
        return commentaar;
    }

    public void setCommentaar(String commentaar) {
        this.commentaar = commentaar;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }

        if (object == null) {
            return false;
        }

        if (!(object instanceof Klant)) {
            return false;
        }

        Klant klant = (Klant) object;
        return klantnummer.equals(klant.getKlantnummer());
    }

    @Override
    public int hashCode() {
        if (klantnummer != null) {
            return 37 * klantnummer.hashCode();
        } else {
            return System.identityHashCode(this);
        }
    }

    @Override
    public String toString() {
        return naam + ", " + adres;
    }

    public void readExternal(PofReader reader) throws IOException {
        setKlantnummer(reader.readInt(0));
        setNaam(reader.readString(1));
        setAdres(reader.readString(2));
        setStad(reader.readString(3));
        setProvincie(reader.readString(4));
        setPostcode(reader.readString(5));
        setGebied(reader.readInt(6));
        setTelefoonnummer(reader.readString(7));
        setReputatieNummer(reader.readInt(8));
        setKredietlimiet(reader.readDouble(9));
        setCommentaar(reader.readString(10));
    }

    public void writeExternal(PofWriter writer) throws IOException {
        if (getKlantnummer() != null) {
            writer.writeInt(0, getKlantnummer());
        }
        if (getNaam() != null) {
            writer.writeString(1, getNaam());
        }
        if (getAdres() != null) {
            writer.writeString(2, getAdres());
        }
        if (getStad() != null) {
            writer.writeString(3, getStad());
        }
        if (getProvincie() != null) {
            writer.writeString(4, getProvincie());
        }
        if (getPostcode() != null) {
            writer.writeString(5, getPostcode());
        }
        if (getGebied() != null) {
            writer.writeInt(6, getGebied());
        }
        if (getTelefoonnummer() != null) {
            writer.writeString(7, getTelefoonnummer());
        }
        if (getReputatieNummer() != null) {
            writer.writeInt(8, getReputatieNummer());
        }
        if (getKredietlimiet() != null) {
            writer.writeDouble(9, getKredietlimiet());
        }
        if (getCommentaar() != null) {
            writer.writeString(10, getCommentaar());
        }
    }
}

Here, we have implemented PortableObject. The corresponding POF configuration file looks as follows:

<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
            xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">
    <user-type-list>
        <include>coherence-pof-config.xml</include>
        <user-type>
            <type-id>1001</type-id>
            <class-name>model.entities.Klant</class-name>
        </user-type>
    </user-type-list>
    <allow-interfaces>true</allow-interfaces>
    <allow-subclasses>true</allow-subclasses>
</pof-config>

We perform basic cache operations (get, put and remove) for which we define the following interface

package model.logic;

import java.io.Serializable;
import java.util.List;

public interface GenericDAO<T, ID extends Serializable> {
    public void addEntity(ID id, T entity);

    public void removeEntity(ID id);

    public T findEntity(ID id);

    public List<T> findEntities();
}

The interface can be implemented as follows:

package model.logic;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.ValueExtractor;
import com.tangosol.util.extractor.ChainedExtractor;
import com.tangosol.util.filter.EqualsFilter;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public abstract class GenericCoherenceDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {

    private Class<T> persistentClass;
    private NamedCache namedCache;

    public GenericCoherenceDAO() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            setPersistentClass((Class<T>) parameterizedType.getActualTypeArguments()[0]);
        } else {
            System.out.println("Not an instance of parameterized type: " + type);
        }

        setNamedCache(CacheFactory.getCache(getPersistentClass().getName()));
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public void setPersistentClass(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public NamedCache getNamedCache() {
        return namedCache;
    }

    public void setNamedCache(NamedCache namedCache) {
        this.namedCache = namedCache;
    }

    public void addEntity(ID id, T entity) {
        getNamedCache().put(id, entity);
    }

    public void removeEntity(ID id) {
        getNamedCache().remove(id);
    }

    public T findEntity(ID id) {
        return (T) getNamedCache().get(id);
    }

    public List<T> findEntities() {
        ValueExtractor extractor = new ChainedExtractor("getClass.getName");
        Set keys = getNamedCache().keySet(new EqualsFilter(extractor, getPersistentClass().getName()));
        return new ArrayList<T>(getNamedCache().getAll(keys).values());
    }
}

Specific entity functionality is implemented in entity specific DAOs, for example,

package model.logic;

import model.entities.Klant;
import java.util.List;

public interface KlantDAO extends GenericDAO<Klant, Integer> {
    public List<Klant> getKlantData();
}

Which is implemented as follows

package model.logic;

import com.tangosol.net.cache.ContinuousQueryCache;
import com.tangosol.util.Filter;
import com.tangosol.util.QueryHelper;
import model.entities.Klant;

import java.util.*;

public class KlantDAOBean extends GenericCoherenceDAO<Klant, Integer> implements KlantDAO {

    private ContinuousQueryCache continuousQueryCache;

    public KlantDAOBean() {
        Filter filter = QueryHelper.createFilter("kredietlimiet between 4000.0 and 12000.0");
        continuousQueryCache = new ContinuousQueryCache(getNamedCache(), filter);
    }

    public List<Klant> getKlantData() {
        List<Klant> klanten = new ArrayList<Klant>();
        Iterator<Map.Entry<Integer, Klant>> iterator = continuousQueryCache.entrySet().iterator();
        while (iterator.hasNext()) {
            klanten.add(iterator.next().getValue());
        }
        return klanten;
    }
}

The Coherence cache configuration has the following contents:

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <defaults>
        <serializer>
            <instance>
                <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
                <init-params>
                    <init-param>
                        <param-type>String</param-type>
                        <param-value>security-pof-config.xml</param-value>
                    </init-param>
                </init-params>
            </instance>
        </serializer>
    </defaults>
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>near-cache</scheme-name>
            <init-params>
                <init-param>
                    <param-name>front-size-limit</param-name>
                    <param-value>1000</param-value>
                </init-param>
                <init-param>
                    <param-name>back-size-limit</param-name>
                    <param-value>250M</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <near-scheme>
            <scheme-name>near-cache</scheme-name>
            <front-scheme>
                <local-scheme>
                    <high-units>{front-size-limit 0}</high-units>
                    <expiry-delay>{front-expiry-delay 1m}</expiry-delay>
                </local-scheme>
            </front-scheme>
            <back-scheme>
                <distributed-scheme>
                    <scheme-ref>distributed-cache</scheme-ref>
                </distributed-scheme>
            </back-scheme>
            <invalidation-strategy>none</invalidation-strategy>
            <autostart>true</autostart>
        </near-scheme>
        <distributed-scheme>
            <scheme-name>distributed-cache</scheme-name>
            <service-name>DistributedCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backing-map-scheme>
                <partitioned>true</partitioned>
                <local-scheme>
                    <scheme-ref>local-backing-map</scheme-ref>
                </local-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
        <local-scheme>
            <scheme-name>local-backing-map</scheme-name>
            <eviction-policy>hybrid</eviction-policy>
            <high-units>{back-size-limit 0}</high-units>
            <unit-calculator>binary</unit-calculator>
            <expiry-delay>{back-expiry-delay 1h}</expiry-delay>
        </local-scheme>
    </caching-schemes>
</cache-config>

To make sure our cache configuration is used, we create a tangosol-coherence-override.xml with the following contents:

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
           xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">
    <configurable-cache-factory-config>
        <class-name>com.tangosol.net.DefaultConfigurableCacheFactory</class-name>
        <init-params>
            <init-param>
                <param-type>java.lang.String</param-type>
                <param-value system-property="tangosol.coherence.cacheconfig">security-cache-config.xml</param-value>
            </init-param>
        </init-params>
    </configurable-cache-factory-config>
</coherence>

To test the Coherence set-up we will use the following servlet:

package userinterface.servlets;

import model.entities.Klant;
import model.logic.KlantDAO;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Random;

public class TestServlet extends HttpServlet {

    private Random generator;
    private KlantDAO klantDAO;

    @Override
    public void init() throws ServletException {
        klantDAO = (KlantDAO)getServletContext().getAttribute("klantDAO");
        generator = (Random)getServletContext().getAttribute("generator");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doTest();
    }

    private void doTest() {
        // generate a random client
        Klant klant = createKlant();
        // insert or update a client - an update is issued when the client already exists
        klantDAO.addEntity(klant.getKlantnummer(), klant);
        if (generator.nextDouble() &lt; 0.001) {
            // remove a client
            klantDAO.removeEntity(generateKlantNummer());
            // get all client data
            klantDAO.findEntities();
            // get data from the continuous query cache
            klantDAO.getKlantData();
        } else {
            // find a client by ID
            klantDAO.findEntity(generateKlantNummer());
        }
    }

    private Klant createKlant() {
        int klantnummer = generateKlantNummer();

        Klant klant = new Klant();
        klant.setKlantnummer(klantnummer);
        klant.setNaam("Middleware" + klantnummer);
        klant.setAdres("Magic");
        klant.setStad("Pune");
        klant.setProvincie("IN");
        klant.setPostcode("1234AB");
        klant.setGebied(1);
        klant.setTelefoonnummer("123-4567");
        klant.setReputatieNummer(1);
        klant.setKredietlimiet(Math.rint(generator.nextDouble() * 5000.0));
        klant.setCommentaar(Long.toString(Math.abs(generator.nextLong()), 36));

        return klant;
    }

    private Integer generateKlantNummer() {
        return generator.nextInt(10000);
    }
}

with the following servlet configuration in the web.xml deployment descriptor:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">
    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>userinterface.servlets.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/test</url-pattern>
    </servlet-mapping>
	<listener>
        <listener-class>userinterface.listeners.ContextListener</listener-class>
    </listener>
</web-app>

in which the ContextListener looks as follows:

package userinterface.listeners;

import com.tangosol.net.CacheFactory;
import model.logic.KlantDAO;
import model.logic.KlantDAOBean;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.Random;

public class ContextListener implements ServletContextListener {

    private ServletContext context;

    public void contextInitialized(ServletContextEvent servletContextEvent) {
        context = servletContextEvent.getServletContext();
        CacheFactory.ensureCluster();

        Random generator = new Random();
        KlantDAO klantDAO = new KlantDAOBean();

        context.setAttribute("generator", generator);
        context.setAttribute("klantDAO", klantDAO);
    }

    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        context.removeAttribute("generator");
        context.removeAttribute("klantDAO");
        CacheFactory.shutdown();
    }
}

By using a ServletContextListener we initialize the Coherence cluster when the servlet context is initialized and shut the Coherence cluster down when the servlet context is destroyed. To ensure that the data in the cluster is maintained when the servlet context is destroyed (for example, by stopping or undeploying the application) can use a default cache server that is started outside of the WebLogic cluster, for example, by using the following start script:

set COHERENCE_MANAGEMENT_OPTIONS=-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true
set COHERENCE_OPTIONS=%COHERENCE_MANAGEMENT_OPTIONS%

set JAVA_HOME=C:\bea\jrockit_160_24_D1.1.2-4
set MEM_ARGS=-jrockit -Xms256m -Xmx256m -Xns64m -Xgc:throughput

set CLASSPATH=C:\documents\IDM\Voorbeelden\Code\Security\lib\Coherence\coherence.jar;C:\documents\IDM\Voorbeelden\Code\Security\out\artifacts\test\test.jar

%JAVA_HOME%/bin/java %MEM_ARGS% %COHERENCE_OPTIONS% com.tangosol.net.DefaultCacheServer

At last a Windows script instead of the preferred (RedHat) Linux. Package the application as a war file and deploy it to the cluster. To this end create the following directory structure:

application-name
	app
		application-name.war
	plan
		WEB-INF (created by WebLogic)
			weblogic.xml
		Plan.xml (created by WebLogic)

When the application is deployed, WebLogic will automatically create a deployment plan (Plan.xml) and the deployment override WEB-INF/weblogic.xml. Add the following contents to the weblogic.xml such that the deployed shared libraries will be picked by the application:

<weblogic-web-app xmlns="http://xmlns.oracle.com/weblogic/weblogic-web-app"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				  xsi:schemaLocation="http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.2/weblogic-web-app.xsd">
	<security-role-assignment>
		<role-name>EMPLOYEE</role-name>
		<principal-name>employees</principal-name>
	</security-role-assignment>
	<security-role-assignment>
		<role-name>MANAGER</role-name>
		<principal-name>managers</principal-name>
	</security-role-assignment>
	<library-ref>
		<library-name>coherence</library-name>
		<specification-version>3.7</specification-version>
		<implementation-version>3.7.1</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
	<library-ref>
		<library-name>JSF</library-name>
		<specification-version>1.2</specification-version>
		<implementation-version>1.2.14</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
	<library-ref>
		<library-name>jbossrichfaces</library-name>
		<specification-version>3.3</specification-version>
		<implementation-version>3.3.1</implementation-version>
		<exact-match>true</exact-match>
	</library-ref>
</weblogic-web-app>

We also added role mappings to the deployment override, these will be used when we configure security for the application. When the deployment is active, enter the URLs of the test servlet for the servers in the cluster, for example, http://hostname:port/context-root/test. Look in the respective server log files to see how Coherence is doing. The log files are present in the ${DOMAIN_HOME}/servers/<server-name>/logs directory. As the servers are started by the node manager the Coherence log output can be found in the <server-name>.out file. Log output for server1:

2011-10-30 16:10:42.859/212.188 Oracle Coherence 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server1/tmp/_WL_user/coherence/qatg73/WEB-INF/lib/coherence.jar!/tangosol-coherence.xml"
2011-10-30 16:10:42.891/212.220 Oracle Coherence 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational overrides from "zip:C:/bea/user_projects/domains/base_domain/servers/server1/tmp/_WL_user/coherence/qatg73/WEB-INF/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2011-10-30 16:10:42.922/212.251 Oracle Coherence 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational overrides from "zip:C:/bea/user_projects/domains/base_domain/servers/server1/tmp/_WL_user/security/yzugjc/war/WEB-INF/lib/_wl_cls_gen.jar!/tangosol-coherence-override.xml"
2011-10-30 16:10:42.922/212.251 Oracle Coherence 3.7.1.0 <D5> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2011-10-30 16:10:44.109/213.438 Oracle Coherence GE 3.7.1.0 <Warning> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Local address "127.0.0.1" is a loopback address; this cluster node will not connect to nodes located on different machines
2011-10-30 16:10:44.312/213.641 Oracle Coherence GE 3.7.1.0 <D4> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): TCMP bound to /127.0.0.1:8090 using SystemSocketProvider
2011-10-30 16:10:48.203/217.532 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): This Member(Id=2, Timestamp=2011-10-30 16:10:47.938, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2) joined cluster "cluster:0xFCDB" with senior Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2)
2011-10-30 16:10:48.469/217.798 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
2011-10-30 16:10:48.500/217.829 Oracle Coherence GE 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Started cluster Name=cluster:0xFCDB

Group{Address=224.3.7.0, Port=37000, TTL=4}

MasterMemberSet(
  ThisMember=Member(Id=2, Timestamp=2011-10-30 16:10:47.938, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer)
  OldestMember=Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer)
  ActualMemberSet=MemberSet(Size=2
    Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer)
    Member(Id=2, Timestamp=2011-10-30 16:10:47.938, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2011-10-30 16:10:44.312|JOINED,
    2|3.7.1|2011-10-30 16:10:48.359|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[1]}
IpMonitor{AddressListSize=0}

2011-10-30 16:10:48.594/217.923 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=2): Service Management joined the cluster with senior service member 1
2011-10-30 16:10:48.859/218.188 Oracle Coherence GE 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=2): Loaded cache configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server1/tmp/_WL_user/security/yzugjc/war/WEB-INF/lib/_wl_cls_gen.jar!/security-cache-config.xml"
2011-10-30 16:10:49.219/218.548 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member 1 joined Service DistributedCache with senior member 1
2011-10-30 16:10:49.359/218.688 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=2): Loaded POF configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server1/tmp/_WL_user/security/yzugjc/war/WEB-INF/lib/_wl_cls_gen.jar!/security-pof-config.xml"
2011-10-30 16:10:49.375/218.704 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=2): Loaded included POF configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server1/tmp/_WL_user/coherence/qatg73/WEB-INF/lib/coherence.jar!/coherence-pof-config.xml"
2011-10-30 16:10:49.500/218.829 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=2): Service DistributedCache joined the cluster with senior service member 1
2011-10-30 16:10:49.766/219.095 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=2): Asking member 1 for 128 primary partitions
2011-10-30 16:15:16.500/485.829 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member(Id=3, Timestamp=2011-10-30 16:15:16.312, Address=127.0.0.1:8092, MachineId=60314, Location=site:,machine:localhost,process:3320, Role=CoherenceServer) joined Cluster with senior member 1
2011-10-30 16:15:17.125/486.454 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member 3 joined Service Management with senior member 1
2011-10-30 16:15:17.812/487.141 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=2): Member 3 joined Service DistributedCache with senior member 1
2011-10-30 16:15:18.047/487.376 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=2): 3> Transferring primary PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41} to member 3 requesting 42
2011-10-30 16:15:18.078/487.407 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=2): Transferring 0KB of backup[1] for PartitionSet{42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83} to member 3

Log output for server2:

2011-10-30 16:10:42.859/160.219 Oracle Coherence 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server2/tmp/_WL_user/coherence/jjexem/WEB-INF/lib/coherence.jar!/tangosol-coherence.xml"
2011-10-30 16:10:42.891/160.251 Oracle Coherence 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational overrides from "zip:C:/bea/user_projects/domains/base_domain/servers/server2/tmp/_WL_user/coherence/jjexem/WEB-INF/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2011-10-30 16:10:42.906/160.266 Oracle Coherence 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational overrides from "zip:C:/bea/user_projects/domains/base_domain/servers/server2/tmp/_WL_user/security/eequ47/war/WEB-INF/lib/_wl_cls_gen.jar!/tangosol-coherence-override.xml"
2011-10-30 16:10:42.922/160.282 Oracle Coherence 3.7.1.0 <D5> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2011-10-30 16:10:43.969/161.329 Oracle Coherence GE 3.7.1.0 <Warning> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Local address "127.0.0.1" is a loopback address; this cluster node will not connect to nodes located on different machines
2011-10-30 16:10:44.188/161.548 Oracle Coherence GE 3.7.1.0 <D4> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): TCMP bound to /127.0.0.1:8088 using SystemSocketProvider
2011-10-30 16:10:47.797/165.157 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0xFCDB" with Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2) UID=0x7F000001000001335561FA58EB9A1F98
2011-10-30 16:10:47.906/165.266 Oracle Coherence GE 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Started cluster Name=cluster:0xFCDB

Group{Address=224.3.7.0, Port=37000, TTL=4}

MasterMemberSet(
  ThisMember=Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer)
  OldestMember=Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer)
  ActualMemberSet=MemberSet(Size=1
    Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2011-10-30 16:10:47.812|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[]}
IpMonitor{AddressListSize=0}

2011-10-30 16:10:48.047/165.407 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2011-10-30 16:10:48.203/165.563 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member(Id=2, Timestamp=2011-10-30 16:10:47.938, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer) joined Cluster with senior member 1
2011-10-30 16:10:48.234/165.594 Oracle Coherence GE 3.7.1.0 <Info> (thread=[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)', member=1): Loaded cache configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server2/tmp/_WL_user/security/eequ47/war/WEB-INF/lib/_wl_cls_gen.jar!/security-cache-config.xml"
2011-10-30 16:10:48.609/165.969 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 joined Service Management with senior member 1
2011-10-30 16:10:48.953/166.313 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=1): Loaded POF configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server2/tmp/_WL_user/security/eequ47/war/WEB-INF/lib/_wl_cls_gen.jar!/security-pof-config.xml"
2011-10-30 16:10:48.969/166.329 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=1): Loaded included POF configuration from "zip:C:/bea/user_projects/domains/base_domain/servers/server2/tmp/_WL_user/coherence/jjexem/WEB-INF/lib/coherence.jar!/coherence-pof-config.xml"
2011-10-30 16:10:49.062/166.422 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=1): Service DistributedCache joined the cluster with senior service member 1
2011-10-30 16:10:49.750/167.110 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=1): Member 2 joined Service DistributedCache with senior member 1
2011-10-30 16:10:49.812/167.172 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=1): 3> Transferring primary PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127} to member 2 requesting 128
2011-10-30 16:10:49.922/167.282 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=1): 1> Transferring 129 out of 129 partitions to a node-safe backup 1 at member 2 (under 129)
2011-10-30 16:10:49.922/167.282 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=1): Transferring 0KB of backup[1] for PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256} to member 2

Log output for the default cache server (which is started with the management options -Dtangosol.coherence.management=all and -Dtangosol.coherence.management.remote=true in order to get some insight in the cache statistics):

2011-10-30 16:15:14.062/1.516 Oracle Coherence 3.7.1.0 <Info> (thread=Main Thread, member=n/a): Loaded operational configuration from "jar:file:/C:/documents/IDM/Voorbeelden/Code/Security/lib/Coherence/coherence.jar!/tangosol-coherence.xml"
2011-10-30 16:15:14.094/1.532 Oracle Coherence 3.7.1.0 <Info> (thread=Main Thread, member=n/a): Loaded operational overrides from "jar:file:/C:/documents/IDM/Voorbeelden/Code/Security/lib/Coherence/coherence.jar!/tangosol-coherence-override-dev.xml"
2011-10-30 16:15:14.125/1.563 Oracle Coherence 3.7.1.0 <Info> (thread=Main Thread, member=n/a): Loaded operational overrides from "jar:file:/C:/documents/IDM/Voorbeelden/Code/Security/out/artifacts/test/test.jar!/tangosol-coherence-override.xml"
2011-10-30 16:15:14.125/1.563 Oracle Coherence 3.7.1.0 <D5> (thread=Main Thread, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.7.1.0 Build 27797
 Grid Edition: Development mode
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

2011-10-30 16:15:14.484/1.922 Oracle Coherence GE 3.7.1.0 <Info> (thread=Main Thread, member=n/a): Loaded cache configuration from "jar:file:/C:/documents/IDM/Voorbeelden/Code/Security/out/artifacts/test/test.jar!/security-cache-config.xml"
2011-10-30 16:15:14.969/2.407 Oracle Coherence GE 3.7.1.0 <Info> (thread=Main Thread, member=n/a): Loaded Reporter configuration from "jar:file:/C:/documents/IDM/Voorbeelden/Code/Security/lib/Coherence/coherence.jar!/reports/report-group.xml"
2011-10-30 16:15:15.469/2.907 Oracle Coherence GE 3.7.1.0 <Warning> (thread=Main Thread, member=n/a): Local address "127.0.0.1" is a loopback address; this cluster node will not connect to nodes located on different machines
2011-10-30 16:15:15.797/3.235 Oracle Coherence GE 3.7.1.0 <D4> (thread=Main Thread, member=n/a): TCMP bound to /127.0.0.1:8092 using SystemSocketProvider
2011-10-30 16:15:16.188/3.626 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): Failed to satisfy the variance: allowed=16, actual=47
2011-10-30 16:15:16.188/3.626 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): Increasing allowable variance to 19
2011-10-30 16:15:16.516/3.954 Oracle Coherence GE 3.7.1.0 <Info> (thread=Cluster, member=n/a): This Member(Id=3, Timestamp=2011-10-30 16:15:16.312, Address=127.0.0.1:8092, MachineId=60314, Location=site:,machine:localhost,process:3320, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2) joined cluster "cluster:0xFCDB" with senior Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2)
2011-10-30 16:15:16.703/4.141 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member(Id=2, Timestamp=2011-10-30 16:10:47.938, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer) joined Cluster with senior member 1
2011-10-30 16:15:16.922/4.360 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service Management with senior member 1
2011-10-30 16:15:16.922/4.360 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 1 joined Service DistributedCache with senior member 1
2011-10-30 16:15:16.938/4.376 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 2 joined Service Management with senior member 1
2011-10-30 16:15:16.938/4.376 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=n/a): Member 2 joined Service DistributedCache with senior member 1
2011-10-30 16:15:16.953/4.391 Oracle Coherence GE 3.7.1.0 <Info> (thread=Main Thread, member=n/a): Started cluster Name=cluster:0xFCDB

Group{Address=224.3.7.0, Port=37000, TTL=4}

MasterMemberSet(
  ThisMember=Member(Id=3, Timestamp=2011-10-30 16:15:16.312, Address=127.0.0.1:8092, MachineId=60314, Location=site:,machine:localhost,process:3320, Role=CoherenceServer)
  OldestMember=Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer)
  ActualMemberSet=MemberSet(Size=3
    Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer)
    Member(Id=2, Timestamp=2011-10-30 16:10:47.938, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer)
    Member(Id=3, Timestamp=2011-10-30 16:15:16.312, Address=127.0.0.1:8092, MachineId=60314, Location=site:,machine:localhost,process:3320, Role=CoherenceServer)
    )
  MemberId|ServiceVersion|ServiceJoined|MemberState
    1|3.7.1|2011-10-30 16:10:44.312|JOINED,
    2|3.7.1|2011-10-30 16:10:47.938|JOINED,
    3|3.7.1|2011-10-30 16:15:16.719|JOINED
  RecycleMillis=1200000
  RecycleSet=MemberSet(Size=0
    )
  )

TcpRing{Connections=[2]}
IpMonitor{AddressListSize=0}

2011-10-30 16:15:17.125/4.563 Oracle Coherence GE 3.7.1.0 <D5> (thread=Invocation:Management, member=3): Service Management joined the cluster with senior service member 1
2011-10-30 16:15:17.531/4.969 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=3): Loaded POF configuration from "jar:file:/C:/documents/IDM/Voorbeelden/Code/Security/out/artifacts/test/test.jar!/security-pof-config.xml"
2011-10-30 16:15:17.547/4.985 Oracle Coherence GE 3.7.1.0 <Info> (thread=DistributedCache, member=3): Loaded included POF configuration from "jar:file:/C:/documents/IDM/Voorbeelden/Code/Security/lib/Coherence/coherence.jar!/coherence-pof-config.xml"
2011-10-30 16:15:17.672/5.110 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=3): Service DistributedCache joined the cluster with senior service member 1
2011-10-30 16:15:17.766/5.204 Oracle Coherence GE 3.7.1.0 <Info> (thread=Main Thread, member=3):
Services
  (
  ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.7.1, OldestMemberId=1}
  InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
  PartitionedCache{Name=DistributedCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=0, BackupPartitions=0}
  )

Started DefaultCacheServer...

2011-10-30 16:15:17.828/5.266 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=3): Asking member 1 for 43 primary partitions
2011-10-30 16:15:18.016/5.454 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=3): Asking member 2 for 42 primary partitions

# Application is stopped
2011-10-30 16:54:16.969/2344.407 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 2 left service Management with senior member 1
2011-10-30 16:54:16.969/2344.407 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 1 left service Management with senior member 3
2011-10-30 16:54:17.000/2344.438 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=3): Asking member 1 for 44 primary partitions
2011-10-30 16:54:17.109/2344.547 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=3): Asking member 2 for 86 primary partitions
2011-10-30 16:54:17.234/2344.672 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=3): Asking member 1 for 43 primary partitions
2011-10-30 16:54:17.250/2344.688 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 1 left service DistributedCache with senior member 2
2011-10-30 16:54:17.266/2344.704 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=3): Asking member 2 for 42 primary partitions
2011-10-30 16:54:17.281/2344.719 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 2 left service DistributedCache with senior member 3
2011-10-30 16:54:17.875/2345.313 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): TcpRing disconnected from Member(Id=2, Timestamp=2011-10-30 16:10:47.938, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer) due to a peer departure; removing the member.
2011-10-30 16:54:17.875/2345.313 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member(Id=2, Timestamp=2011-10-30 16:54:17.875, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer) left Cluster with senior member 1
2011-10-30 16:54:20.328/2347.766 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): TcpRing connection to Member(Id=1, Timestamp=2011-10-30 16:10:44.312, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer) refused (Connection refused: no further information); removing the member.
2011-10-30 16:54:20.328/2347.766 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member(Id=1, Timestamp=2011-10-30 16:54:20.328, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer) left Cluster with senior member 3

# Application is started again
2011-10-30 16:55:06.750/2394.188 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member(Id=4, Timestamp=2011-10-30 16:55:06.524, Address=127.0.0.1:8088, MachineId=60314, Location=site:,machine:localhost,process:1908, Role=WeblogicServer) joined Cluster with senior member 3
2011-10-30 16:55:07.062/2394.500 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member(Id=5, Timestamp=2011-10-30 16:55:06.875, Address=127.0.0.1:8090, MachineId=60314, Location=site:,machine:localhost,process:3784, Role=WeblogicServer) joined Cluster with senior member 3
2011-10-30 16:55:07.297/2394.735 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 4 joined Service Management with senior member 3
2011-10-30 16:55:07.906/2395.344 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 5 joined Service Management with senior member 3
2011-10-30 16:55:08.938/2396.376 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 4 joined Service DistributedCache with senior member 3
2011-10-30 16:55:09.156/2396.594 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=3): 3> Transferring primary PartitionSet{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127} to member 4 requesting 128
2011-10-30 16:55:09.625/2397.063 Oracle Coherence GE 3.7.1.0 <D4> (thread=DistributedCache, member=3): 1> Transferring 129 out of 129 partitions to a node-safe backup 1 at member 4 (under 129)
2011-10-30 16:55:09.812/2397.250 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=3): Transferring 4KB of backup[1] for PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256} to member 4
2011-10-30 16:55:10.078/2397.516 Oracle Coherence GE 3.7.1.0 <D5> (thread=Cluster, member=3): Member 5 joined Service DistributedCache with senior member 3
2011-10-30 16:55:10.422/2397.860 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=3): 3> Transferring primary PartitionSet{128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170} to member 5 requesting 43
2011-10-30 16:55:10.453/2397.891 Oracle Coherence GE 3.7.1.0 <D5> (thread=DistributedCache, member=3): Transferring 1KB of backup[1] for PartitionSet{171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213} to member 5

The default server logging also shows what happens when the application is stopped and started again. By using an MBean browser that is connected to the default cache server the cache statistics can be observed.

Integrate JBoss RichFaces

To configure JBoss RichFaces, we can use the following web.xml entries:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>server</param-value>
    </context-param>
    <context-param>
        <param-name>org.richfaces.SKIN</param-name>
        <param-value>blueSky</param-value>
    </context-param>
    <context-param>
        <param-name>org.richfaces.CONTROL_SKINNING</param-name>
        <param-value>enable</param-value>
    </context-param>
    <filter>
        <filter-name>RichFaces Filter</filter-name>
        <filter-class>org.ajax4jsf.Filter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>RichFaces Filter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>
	<security-constraint>
        <web-resource-collection>
            <web-resource-name>All</web-resource-name>
            <url-pattern>/faces/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>MANAGER</role-name>
            <role-name>EMPLOYEE</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <login-config>
        <auth-method>FORM</auth-method>
        <form-login-config>
            <form-login-page>/login.jspx</form-login-page>
            <form-error-page>/login.jspx</form-error-page>
        </form-login-config>
    </login-config>
    <security-role>
        <role-name>MANAGER</role-name>
    </security-role>
    <security-role>
        <role-name>EMPLOYEE</role-name>
    </security-role>
</web-app>

in which we have also secured the access to the faces servlet. An example page that adds, deletes and views customers is the following:

<!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
      xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich">
<head>
    <title>Overview</title>
</head>
<body>
<a4j:form id="form">
    <rich:panel header="Customers" style="width:750px">
        <rich:dataTable id="datatable" value="#{bean.klanten}" var="klant" rows="20"
                        reRender="datascroller">
            <f:facet name="caption">
                <h:panelGroup>
                    <h:commandButton id="insert" value="#{res['button.toevoegen']}"
                                     actionListener="#{bean.insertActionListener}"/>
                    <h:commandButton id="alle" value="#{res['button.show']}"
                                     actionListener="#{bean.showCustomersActionListener}"/>
                    <h:commandButton id="rijke" value="#{res['button.showrich']}"
                                     actionListener="#{bean.showRichCustomersActionListener}"/>
                </h:panelGroup>
            </f:facet>
            <f:facet name="header">
                <rich:columnGroup>
                    <rich:column>
                        <h:outputText value="#{res['tabel.header.klantnummer']}"/>
                    </rich:column>
                    <rich:column>
                        <h:outputText value="#{res['tabel.header.naam']}"/>
                    </rich:column>
                    <rich:column>
                        <h:outputText value="#{res['tabel.header.adres']}"/>
                    </rich:column>
                    <rich:column>
                        <h:outputText value="#{res['tabel.header.kredietlimiet']}"/>
                    </rich:column>
                    <rich:column>
                        <h:outputText value="#{res['tabel.header.commentaar']}"/>
                    </rich:column>
                    <rich:column rendered="#{security.manager}">
                        <rich:spacer/>
                    </rich:column>
                </rich:columnGroup>
            </f:facet>
            <rich:column>
                <h:outputText value="#{klant.klantnummer}"/>
            </rich:column>
            <rich:column>
                <h:outputText value="#{klant.naam}"/>
            </rich:column>
            <rich:column>
                <h:outputText value="#{klant.adres}"/>
            </rich:column>
            <rich:column>
                <h:outputText value="#{klant.kredietlimiet}">
                    <f:convertNumber pattern="####0.00"/>
                </h:outputText>
            </rich:column>
            <rich:column>
                <h:outputText value="#{klant.commentaar}"/>
            </rich:column>
            <rich:column rendered="#{security.manager}">
                <a4j:commandLink value="#{res['button.verwijderen']}" onclick="#{rich:component('modalpanel')}.show()"
                                 reRender="deletepersoon">
                    <f:setPropertyActionListener value="#{klant}" target="#{bean.klant}"/>
                </a4j:commandLink>
            </rich:column>
            <f:facet name="footer">
                <rich:datascroller id="datascroller"/>
            </f:facet>
        </rich:dataTable>
        <rich:modalPanel id="modalpanel">
            <rich:panel header="Delete Client">
                <h:panelGrid id="deletepersoon">
                    <h:outputText value="#{bean.klant}"/>
                    <f:facet name="footer">
                        <rich:toolBar height="20" itemSeparator="line">
                            <rich:toolBarGroup location="right">
                                <a4j:commandButton value="save"
                                                   actionListener="#{bean.deleteActionListener}"
                                                   oncomplete="#{rich:component('modalpanel')}.hide()"
                                                   reRender="datatable"/>
                                <a4j:commandButton value="cancel"
                                                   onclick="#{rich:component('modalpanel')}.hide()"/>
                            </rich:toolBarGroup>
                        </rich:toolBar>
                    </f:facet>
                </h:panelGrid>
            </rich:panel>
        </rich:modalPanel>
    </rich:panel>
</a4j:form>
</body>
</html>

The backing bean that controls the page looks as follows:

package userinterface.beans;

import model.entities.Klant;
import userinterface.resources.Utilities;

import javax.faces.event.ActionEvent;
import java.util.List;

public class BackingBean {

    private List<Klant> klanten;
    private Klant klant;
    private boolean showAll = true;

    public List<Klant> getKlanten() {
        if (showAll) {
            klanten = Utilities.getKlantDAO().findEntities();
        } else {
            klanten = Utilities.getKlantDAO().getKlantData();
        }
        return klanten;
    }

    public void setKlanten(List<Klant> klanten) {
        this.klanten = klanten;
    }

    public Klant getKlant() {
        return klant;
    }

    public void setKlant(Klant klant) {
        this.klant = klant;
    }

    public void showCustomersActionListener(ActionEvent actionEvent) {
        showAll = true;
    }

    public void showRichCustomersActionListener(ActionEvent actionEvent) {
        showAll = false;
    }

    public void insertActionListener(ActionEvent actionEvent) {
        Klant newKlant = createKlant();
        Utilities.getKlantDAO().addEntity(newKlant.getKlantnummer(), newKlant);
    }

    public void deleteActionListener(ActionEvent actionEvent) {
        if (getKlant() != null) {
            Utilities.getKlantDAO().removeEntity(getKlant().getKlantnummer());
        }
    }

    private Klant createKlant() {
        int klantnummer = generateKlantNummer();

        Klant klant = new Klant();
        klant.setKlantnummer(klantnummer);
        klant.setNaam("Middleware" + klantnummer);
        klant.setAdres("Magic");
        klant.setStad("Pune");
        klant.setProvincie("IN");
        klant.setPostcode("1234AB");
        klant.setGebied(1);
        klant.setTelefoonnummer("123-4567");
        klant.setReputatieNummer(1);
        klant.setKredietlimiet(Math.rint(Utilities.getGenerator().nextDouble() * 5000.0));
        klant.setCommentaar(Long.toString(Math.abs(Utilities.getGenerator().nextLong()), 36));

        return klant;
    }

    private Integer generateKlantNummer() {
        return Utilities.getGenerator().nextInt(10000);
    }
}

The faces configuration file has the following contents:

<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
              version="1.2">
    <application>
        <message-bundle>userinterface.resources.messagebundle</message-bundle>
        <locale-config>
            <supported-locale>en</supported-locale>
            <supported-locale>nl</supported-locale>
        </locale-config>
        <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
    </application>
    <managed-bean>
        <managed-bean-name>bean</managed-bean-name>
        <managed-bean-class>userinterface.beans.BackingBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
    <managed-bean>
        <managed-bean-name>res</managed-bean-name>
        <managed-bean-class>userinterface.resources.ResourceHandler</managed-bean-class>
        <managed-bean-scope>application</managed-bean-scope>
    </managed-bean>
	<managed-bean>
        <managed-bean-name>security</managed-bean-name>
        <managed-bean-class>userinterface.beans.SecurityBackingBean</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
    </managed-bean>
</faces-config>

In which the view-handler is needed when we want to use facelets. As a little extra let us add some security, for example, only users with the manager role can delete customers. To this end we create the following backing bean:

package userinterface.beans;

import userinterface.resources.Utilities;

public class SecurityBackingBean {

    private String role;
    private String user;

    private static final String EMPLOYEE = "EMPLOYEE";
    private static final String MANAGER = "MANAGER";
    private static final String[] ROLE_NAMES = {EMPLOYEE, MANAGER};

    public SecurityBackingBean() {
        this.user = Utilities.getExternalContext().getRemoteUser();

        for (String roleName : ROLE_NAMES) {
            if (Utilities.getExternalContext().isUserInRole(roleName)) {
                this.role = roleName;
                break;
            }
        }
    }

    public boolean isEmployee() {
        return EMPLOYEE.equals(this.role);
    }

    public boolean isManager() {
        return MANAGER.equals(this.role);
    }

    public String getUser() {
        return this.user;
    }
}

By using this backing bean we can control if certain JSF components are rendered, for example, <rich:column rendered="#{security.manager}">.

When a user logs in with MANAGER privledges, the user able to delete customers:

The Show Rich Customers button lets the user view the contents of the Continuous Query Cache:

When a user logs in with EMPLOYEE privledges, the delete option is not rendered:

References

[1] RichFaces Developer Guide.
[2] RichFaces Component Reference.
[3] RichFaces Project Page.


Tune the JVM that runs Coherence Revisited

In this post we present steps and considerations involved when tuning the HotSpot JVM that runs an application that uses Coherence. In a previous post we already outlined the steps involved in tuning the JRockit JVM. Basically, we can follow the same steps, i.e., tune the heap size and select the appropriate garbage collector. When selecting a garbage collector there are two primary measures: throughput (the percentage of time not spent in garbage collection) and pause time (the time when the application is paused, due to a garbage collection).

The HotSpot JVM has the following collectors available:

  • The serial collector uses a single thread to perform the minor and major garbage collections. With this collector only one thing happens at a time; even when multiple CPUs are available, only one is utilized to perform the collection.
  • The parallel collector uses multiple threads to perform the minor garbage collections. When a parallel collector is used, the garbage collection task is split into parts that are executed simultaneously on different CPUs. Major collections are by default run using a single thread. By enabling the parallel compaction feature the major collections are performed in parallel as well. After a garbage collection has determined the live objects, it can compact the memory by moving the live objects together. When the memory is compacted it is easier for the JVM to allocate new objects.
  • The concurrent collector performs most of the collection concurrently in order to keep the garbage collection pauses short. In contrast a stop-the-world collection is simpler as objects do not change during the collection, but can introduce undesirable pauses.
  • The garbage first collector divides the heap into regions and during garbage collection can collect a subset of the regions. A set of these regions are selected to act as the young generation. Note that the garbage first collector is available in JDK1.7.0 (actually it already was in JDK1.6 update 14) and is still experimental.

Parallel collector

When we are doing a lot of processing it makes sense to choose the parallel collector. Note that when using Coherence we need to obtain data as fast as possible with a minimal amount of pause time. In this case, we can tune the parallel collector for a certain service level, i.e., a goal for the maximum introduced pause time while maintaining a certain throughput. By using the parallel collector we can specify the following service parameters:

  • maximum garbage collection pause time (-XX:MaxGCPauseMillis=N – if this parameter is specified the collector attempts to reach this service level.
  • throughput (-XX:GCTimeRatio=N) – the throughput goal 1 / (1+N) is measured as the time spent garbage collecting versus time spent running the application.

The parameters for the parallel collector can be set as follows:

-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParallelGC -XX:ParallelGCThreads=2 -XX:MaxGCPauseMillis=200 -XX:GCTimeRatio=19 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages
  • -server – select the JIT compiler.
  • -Xms – initial heap size.
  • -Xmx – maximum heap size.
  • -XX:NewRatio=N – sets the young generation to heap size / (1 + N).
  • -XX:-UseParallelGC – select the parallel collector for minor collections.
  • -XX:ParallelGCThreads – sets the number of garbage collector threads, i.e., the number of CPUs to be used.
  • -XX:MaxGCPauseMillis – sets the maximum pause time goal.
  • -XX:GCTimeRatio=N – sets the throughput goal that is measured in terms of the time spent doing garbage collection versus the time spent outside of garbage collection. In the case above with N=19, the garbage collection time to application time is set to 1 / (1+N) = 1 / 20, i.e., 5% of the total time is spent in garbage collection.
  • -XX:-UseParallelOldGC – selects the parallel collector for major collections.
  • -XX:+UseTLAB – enables thread-local object allocation. More information on thread local allocation can be found in the ‘Compaction and Thread Local Area’ section of the Tune the JVM that runs Coherence post.
  • -XX:LargePageSizeInBytes – sets the large page size used for the Java heap. We set this equal to the operating system parameter: Hugepagesize, which in our case is 2048kB
  • -XX:+UseLargePages – use large page memory. The steps involved on how to configure large pages in the operating system can be found in the ‘Call profiling and large pages’ section of the Tune the JVM that runs Coherence post.

Measurement

To run some tests we can using the following scripts:

#!/bin/sh
# set Coherence options to obtain cache statistics
COHERENCE_MANAGEMENT_OPTIONS="-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true"

# set the Coherence cache configuration file
COHERENCE_OPTIONS="-Dtangosol.coherence.cacheconfig=tryout-cache-config.xml ${COHERENCE_MANAGEMENT_OPTIONS}"
export COHERENCE_OPTIONS

# enable this option to use Java 1.6
JAVA_HOME="/home/oracle/jdk1.6.0_24"

#enable this option to use Java 1.7
#JAVA_HOME="/home/oracle/jdk1.7.0"
export JAVA_HOME

# memory arguments used for the parallel collector
MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParallelGC -XX:ParallelGCThreads=2 -XX:MaxGCPauseMillis=200 -XX:GCTimeRatio=19 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"

# memory arguments used for the concurrent collector
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"

# memory arguments used for the incremental concurrent collector
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycleMin=0 -XX:CMSIncrementalDutyCycle=10 -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"

# memory arguments used for the garbage first collector
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages -XX:-UseLoopPredicate"
export MEM_ARGS

# set the classpath
CLASSPATH="coherence-hibernate.jar:commonj.jar:coherence.jar:coherence-work.jar:ojdbc6.jar:jta.jar:ehcache-1.2.3.jar:hibernate3.jar:commons-logging-1.0.4.jar:dom4j-1.6.1.jar:cglib-2.1.3.jar:commons-collections-2.1.1.jar:asm.jar:c3p0-0.9.1.jar:antlr-2.7.6.jar:asm-attrs.jar:test.jar"
export CLASSPATH

# set the command-line to start the default cache server
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} com.tangosol.net.DefaultCacheServer
#!/bin/sh
# set the Coherence cache configuration file
COHERENCE_OPTIONS="-Dtangosol.coherence.cacheconfig=tryout-cache-config.xml"
export COHERENCE_OPTIONS

# options to obtain garbage collection information
MEASUREMENT_OPTIONS="-verbosegc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -Xloggc:/home/oracle/temp/gc.out"
export MEASUREMENT_OPTIONS

# enable this option to use Java 1.6
JAVA_HOME="/home/oracle/jdk1.6.0_24"

#enable this option to use Java 1.7
#JAVA_HOME="/home/oracle/jdk1.7.0"
export JAVA_HOME

# memory arguments used for the parallel collector
MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParallelGC -XX:ParallelGCThreads=2 -XX:MaxGCPauseMillis=200 -XX:GCTimeRatio=19 -XX:+UseParallelOldGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"

# memory arguments used for the concurrent collector
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"

# memory arguments used for the incremental concurrent collector
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages"

# memory arguments used for the garbage first collector
#MEM_ARGS="-server -Xms1024m -Xmx1024m -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages -XX:-UseLoopPredicate"
export MEM_ARGS

# set the classpath
CLASSPATH="coherence-hibernate.jar:commonj.jar:coherence.jar:coherence-work.jar:ojdbc6.jar:jta.jar:ehcache-1.2.3.jar:hibernate3.jar:commons-logging-1.0.4.jar:dom4j-1.6.1.jar:cglib-2.1.3.jar:commons-collections-2.1.1.jar:asm.jar:c3p0-0.9.1.jar:antlr-2.7.6.jar:asm-attrs.jar:test.jar"
export CLASSPATH

# set the command-line to start the test
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} ${MEASUREMENT_OPTIONS} model.test.Test

To get an idea of the how the application is doing we can use jvisualvm (located in the ${JAVA_HOME}/bin directory), for example,

Thread information can be found on the threads tab:

To see which classes occupy the heap, we can use the sampler tab:

Garbage collection information can obtained on the monitor tab:

More detailed garbage collection information can be obtain from the added MEASUREMENT_OPTIONS, i.e.,

# output for the -XX:+PrintGCApplicationStoppedTime option
Total time for which application threads were stopped: 0.0001760 seconds
# output for the -XX:+PrintGCApplicationConcurrentTime option
Application time: 0.5882530 seconds
...
# output for the -verbosegc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps options
1787.096: [GC [PSYoungGen: 331731K->6970K(337472K)] 1027141K->703972K(1037888K), 0.0225070 secs] [Times: user=0.04 sys=0.00, real=0.02 secs]
Total time for which application threads were stopped: 0.0227760 seconds
Application time: 0.0250060 seconds
...
1793.293: [GC [PSYoungGen: 331706K->3635K(337984K)] 1028708K->702533K(1038400K), 0.0164910 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
1793.325: [Full GC [PSYoungGen: 3635K->0K(337984K)] [ParOldGen: 698897K->19384K(700416K)] 702533K->19384K(1038400K) [PSPermGen: 40255K->39956K(81920K)], 0.3813170 secs] [Times: user=0.29 sys=0.02, real=0.39 secs]
Total time for which application threads were stopped: 0.4218670 seconds
Application time: 0.0016200 seconds
...
1798.766: [GC [PSYoungGen: 325504K->11112K(336640K)] 344888K->30496K(1037056K), 0.0154580 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
Total time for which application threads were stopped: 0.0159380 seconds
Application time: 0.1704330 seconds
...
3470.295: [GC-- [PSYoungGen: 337920K->337920K(342144K)] 1035431K->1038331K(1042560K), 0.1103830 secs] [Times: user=0.13 sys=0.00, real=0.11 secs]
3470.405: [Full GC [PSYoungGen: 337920K->0K(342144K)] [ParOldGen: 700411K->25867K(700416K)] 1038331K->25867K(1042560K) [PSPermGen: 40003K->39987K(83968K)], 0.2131430 secs] [Times: user=0.29 sys=0.00, real=0.22 secs]
Total time for which application threads were stopped: 0.3239480 seconds
Application time: 0.0004270 seconds
...
5075.141: [GC [PSYoungGen: 329440K->3008K(338816K)] 1025250K->701386K(1039232K), 0.0133860 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
5075.154: [Full GC [PSYoungGen: 3008K->0K(338816K)] [ParOldGen: 698378K->16712K(700416K)] 701386K->16712K(1039232K) [PSPermGen: 40040K->40023K(83968K)], 0.4227600 secs] [Times: user=0.36 sys=0.01, real=0.42 secs]
Total time for which application threads were stopped: 0.4365580 seconds
Application time: 0.0004490 seconds

The garbage collection log has the following structure: collector type: occupancy before the collection -> occupancy after the collection, pause time in seconds. When we look at the collection occurring at 1793.293, we have a minor collection in which the parallel collector is used. Here 331706 – 3335 = 328371kB were collected in 16 milliseconds. Subsequently, a major collection occurred at 1793.325, in which the total heap usage dropped from 702533kB to 19384kB. The message afterward shows that the application was stopped for 421 milliseconds. As can be seen from the logging above minor collections do not typically introduce long pause times. However, major collections, though infrequent, introduce a much larger pause time. If pause times introduced by the major collections can be controlled not to run into the seconds range this is something we can live with. One remark is in order though, when the heap is increased it is very likely the major collection pause time to increase as well. Note that this is dependent on the number of live objects on the heap. When using an in-memory cache we should strive to an object occupancy of no more than one-third of the heap (with the heap size being around 2048MB). This usually means that, we have to run more JVM instances if we want to store more data or resort to storing data off-heap or use the elastic data feature that automatically fails-over to disk when the configured RAM part is full. More information about Coherence storage can be found in the post Data Storage Structures in Coherence.

Some handy command-line tools that ship with the HotSpot JVM are:

  • jstat – to monitor the memory usage and garbage collection statistics.
  • jmap – to print shared object memory maps or heap memory details.
  • jhat – parses a java heap dump file (generated, for example, by jmap) and launches a web server that can be reached at:http://hostname:7000.
  • jconsole – a graphical monitoring tool that also provides an MBean browser.

An example jstat output is the following:

[oracle@edu-wls-rh bin]$ ./jstat -gcutil 8556 1 1
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT
  0.00  22.05  43.99  33.90  50.15   1652   31.886     5    1.341   33.228

This tells us that we have had 1652 minor collections (YGC) that took 31.886 seconds and 5 major collections (FGC) that took 1.341 seconds.

To obtain a heap summary, the garbage collection algorithm used, the heap configuration and generation wise heap usage, we can use jmap as

[oracle@edu-wls-rh bin]$ ./jmap -heap 8556
Attaching to process ID 8556, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 19.1-b02

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 1073741824 (1024.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 21757952 (20.75MB)
   MaxPermSize      = 85983232 (82.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 334299136 (318.8125MB)
   used     = 27925328 (26.631668090820312MB)
   free     = 306373808 (292.1808319091797MB)
   8.353395205903254% used
From Space:
   capacity = 12058624 (11.5MB)
   used     = 3997696 (3.8125MB)
   free     = 8060928 (7.6875MB)
   33.15217391304348% used
To Space:
   capacity = 11599872 (11.0625MB)
   used     = 0 (0.0MB)
   free     = 11599872 (11.0625MB)
   0.0% used
PS Old Generation
   capacity = 717225984 (684.0MB)
   used     = 540258960 (515.2310943603516MB)
   free     = 176967024 (168.76890563964844MB)
   75.32618338601631% used
PS Perm Generation
   capacity = 81788928 (78.0MB)
   used     = 41034352 (39.13340759277344MB)
   free     = 40754576 (38.86659240722656MB)
   50.17103537535056% used

To dump the Java heap in hprof binary format to a file, we can use

[oracle@edu-wls-rh bin]$ ./jmap -dump:live,file=/home/oracle/temp/dump.out,format=b 8556
Dumping heap to /home/oracle/temp/dump.out ...
Heap dump file created

To analyze the dump, we can use jhat

[oracle@edu-wls-rh bin]$ ./jhat /home/oracle/temp/dump.out
Reading from /home/oracle/temp/dump.out...
Dump file created Tue Sep 27 17:33:55 CEST 2011
Snapshot read, resolving...
Resolving 278608 objects...
Chasing references, expect 55 dots.......................................................
Eliminating duplicate references.......................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

When accessing the HTTP server (http://hostname:7000), the following output is observed:

All Classes (excluding platform)
...
Package com.tangosol.util.internal
class com.tangosol.util.internal.BMEventFabric [0xbc0ccf88]
class com.tangosol.util.internal.BMEventFabric$EventHolder [0xbc0cf618]
class com.tangosol.util.internal.BMEventFabric$EventQueue [0xbbfe8ca8]
class com.tangosol.util.internal.QueueFabric [0xbc0cc420]
class com.tangosol.util.internal.QueueFabric$LinkedNode [0xbc0ce330]
class com.tangosol.util.internal.QueueFabric$LinkedQueue [0xbbfe82d0]

Package com.tangosol.util.registry
class com.tangosol.util.registry.FlatRegistry [0xbaf09958]

Package com.tangosol.util.stats
class com.tangosol.util.stats.MovingAverage [0xbbbbd020]

Package model.entities
class model.entities.Klant [0xbaece690]
class model.entities.Klant$$EnhancerByCGLIB$$68fd3cc1 [0xbcc8f068]

Package model.logic
class model.logic.GenericCoherenceDAO [0xbaea5888]
class model.logic.GenericDAO [0xbae9e938]
class model.logic.KlantDAO [0xbae9ecf8]
class model.logic.KlantDAOBean [0xbaea5bf8]

Package model.test
class model.test.Test [0xbae9df08]

Package net.sf.cglib.core
class net.sf.cglib.core.AbstractClassGenerator [0xbcc089d0]
class net.sf.cglib.core.AbstractClassGenerator$1 [0xbcc293d0]
class net.sf.cglib.core.AbstractClassGenerator$Source [0xbcc0f198]
...
Other Queries
- All classes including platform
- Show all members of the rootset
- Show instance counts for all classes (including platform)
- Show instance counts for all classes (excluding platform)
- Show heap histogram
- Show finalizer summary
- Execute Object Query Language (OQL) query

When we want to know something about the throughput, it is best measured by using metrics that are particular to the application (such as, for example, by collecting total gets and puts statistics in the case of Coherence). We used a load test that is described in detail in the post Data Storage Structures in Coherence. This test randomly inserts or updates customers and randomly either deletes a customer, obtain all customers in the cache and obtain the results obtained by the continuous query cache or looks-up a customer by id. Some Coherence statistics from the jconsole MBean browser after the test has been running for two hours and five minutes are:

server1 server2
total gets 131642552 130903461
total puts 8100147 8051657
task average duration [ms] 0.0560 0.0599
request average duration [ms] 0.1657 0.2577

Concurrent collector

When shorter pause times introduced by the garbage collector are preferred, the concurrent collector can be used. The concurrent collector trades processor resources (which would otherwise be available to the application) for shorter major collection pause times. On a machine with multiple processors at least one processor is utilized for garbage collection, while other processors are available for application threads. When the concurrent collector is unable to reclaim memory before the tenured generation fills up, the application threads are stopped. This is a so-called concurrent mode failure and indicates the need to adjust the concurrent collector parameters.

The parameters for the concurrent collector can be set as follows:

-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages
  • -XX:+UseParNewGC – enables parallel minor collections when using the concurrent collector.
  • -XX:+UseConcMarkSweepGC – selects the concurrent collector.

Typically, the concurrent collector comes to full bloom when running on a multi-processor machine. When running the concurrent collector on a machine with a single processor, it is beneficial to run it in incremental mode. This mode is meant to lessen the impact of long concurrent phases by periodically stopping the concurrent phase to yield back the processor to the application. The incremental mode divides the work done by the collector into chunks which are scheduled between minor collections.

The parameters for the incremental concurrent collector can be set as follows:

-server -Xms1024m -Xmx1024m -XX:NewRatio=2 -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages
  • -XX:+CMSIncrementalMode – enables incremental mode.
  • -XX:+CMSIncrementalPacing – enables automatic pacing, i.e., the incremental mode duty cycle is automatically adjusted based on statistics collected while the JVM is running.

Measurement

The load test is run, while using the non-incremental mode concurrent collector. Some graphical insight into the garbage collection can be obtained from jvisualvm:

A snippet of the garbage collection logging looks as follows:

2.517: [Full GC 2.517: [CMS: 0K->8010K(699072K), 0.0703740 secs] 106288K->8010K(1013632K), [CMS Perm : 21247K->21209K(21248K)], 0.0705030 secs] [Times: user=0.07 sys=0.00, real=0.07 secs]
Total time for which application threads were stopped: 0.0706930 seconds
Application time: 1.0022240 seconds
...
6.544: [Full GC 6.544: [CMS: 8010K->10606K(699072K), 0.1078110 secs] 114566K->10606K(1013632K), [CMS Perm : 35279K->35253K(35352K)], 0.1079470 secs] [Times: user=0.10 sys=0.01, real=0.11 secs]
Total time for which application threads were stopped: 0.1080470 seconds
Application time: 0.0017350 seconds
...
508.686: [GC 508.686: [ParNew: 287010K->5629K(314560K), 0.0113350 secs] 315834K->34514K(1013632K), 0.0114150 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Total time for which application threads were stopped: 0.0121350 seconds
Application time: 0.9609660 seconds
...
3954.124: [GC 3954.124: [ParNew: 289779K->10553K(314560K), 0.0206580 secs] 442506K->163439K(1013632K), 0.0207290 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
Total time for which application threads were stopped: 0.0212160 seconds
Application time: 0.3176170 seconds
...
9241.526: [GC 9241.526: [ParNew: 285412K->4726K(314560K), 0.0113590 secs] 634729K->354142K(1013632K), 0.0114430 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
Total time for which application threads were stopped: 0.0120750 seconds
Application time: 0.1760080 seconds
...
9246.619: [GC 9246.619: [ParNew: 284342K->8748K(314560K), 0.0137730 secs] 633758K->358304K(1013632K), 0.0138450 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
Total time for which application threads were stopped: 0.0144290 seconds
Application time: 0.0054080 seconds
9246.638: [GC [1 CMS-initial-mark: 349555K(699072K)] 361133K(1013632K), 0.0133700 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
9246.652: [CMS-concurrent-mark-start]
9246.755: [CMS-concurrent-mark: 0.103/0.103 secs] [Times: user=0.13 sys=0.00, real=0.10 secs]
9246.755: [CMS-concurrent-preclean-start]
9246.758: [CMS-concurrent-preclean: 0.003/0.003 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
9246.758: [CMS-concurrent-abortable-preclean-start]
9248.734: [CMS-concurrent-abortable-preclean: 1.364/1.976 secs] [Times: user=2.29 sys=0.24, real=1.98 secs]
9248.735: [GC[YG occupancy: 167555 K (314560 K)]9248.735: [Rescan (parallel) , 0.0763630 secs]9248.811: [weak refs processing, 0.0005260 secs] [1 CMS-remark: 349555K(699072K)] 517111K(1013632K), 0.0770400 secs] [Times: user=0.15 sys=0.00, real=0.08 secs]
9248.812: [CMS-concurrent-sweep-start]
9249.594: [CMS-concurrent-sweep: 0.777/0.783 secs] [Times: user=1.14 sys=0.07, real=0.78 secs]
9249.595: [CMS-concurrent-reset-start]
9249.596: [CMS-concurrent-reset: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
...
9251.110: [GC 9251.110: [ParNew: 288364K->7808K(314560K), 0.0169870 secs] 307182K->26796K(1013632K), 0.0170530 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
Total time for which application threads were stopped: 0.0173600 seconds
Application time: 0.6031800 seconds

In the beginning a few major collections are run. This is due to the resizing of the permanent space. When the JVM starts, lots of classes are loaded and the current permanent space is resized when needed. The resizing of the permanent space triggers a major collection, so it is important to size the permanent space appropriately. In general, the initial (-XX:PermSize) and maximum (-XX:MaxPermSize) are set equal to prevent resizing events. In this case, we have to make sure the configured size is appropriate for the total size of classes to be loaded. Otherwise, we will run into a java.lang.OutOfMemoryError: PermGen Space.

A concurrent collector cycle starts with CMS-initial-mark. The CMS-concurrent-mark indicates the end of the marking phase and the CMS-concurrent-sweep indicates the end of the sweeping phase. The precleaning phase (CMS-concurrent-preclean) represents work that can be done concurrently in preparation for the remark phase (CMS-remark). The initial mark pause is short. The concurrent (no pause) phases (mark, preclean and sweep) last significantly longer; it could be that during this time multiple minor collections are run as well. The remark pause is to some extent comparable in length to a minor collection; it is affected by application characteristics (a high rate of object modifications can increase the pause) and the time since the last minor collection (the number of objects in the young generation can increase the pause).

Some Coherence statistics from the jconsole MBean browser after the test has been running for two hours and three minutes are:

server1 server2
total gets 127496059 126932646
total puts 7881554 7836024
task average duration [ms] 0.0557 0.0617
request average duration [ms] 0.1671 0.2614

Garbage first (G1) collector

The G1 collector divides the heap into regions and during a garbage collection can collect a subset of these regions. It dynamically selects a set of regions to act as the young generation. We can specify a goal for the introduced pause time. The collector can estimate how much regions it can collect in the specified time. The regions with the most garbage to collect are selected first. Initially, the G1 collector will behave as the concurrent collector but with some advantages such as better compaction.

The parameters for the G1 collector can be set as follows:

-server -Xms1024m -Xmx1024m -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:-UseLoopPredicate -XX:+UseTLAB -XX:LargePageSizeInBytes=2048k -XX:+UseLargePages
  • -XX:+UnlockExperimentalVMOptions – enables experimental options
  • -XX:+UseG1GC – select the G1 collector
  • -XX:MaxGCPauseMillis – set the pause time target for the G1 collector
  • -XX:-UseLoopPredicate – disable loop optimizations as compiler optimizations can miscompile some loops and lead to incorrect results.

Measurement

Some graphical insight into the garbage collection can be obtained from jvisualvm:

A snippet of the garbage collection logging looks as follows:

...
15.050: [GC pause (young), 0.02904800 secs]
   [Parallel Time:  28.8 ms]
      [GC Worker Start Time (ms):  15050.1  15065.1
       Avg: 15057.6, Min: 15050.1, Max: 15065.1, Diff:  15.0]
      [Update RS (ms):  11.7  1.6
       Avg:   6.7, Min:   1.6, Max:  11.7, Diff:  10.2]
         [Processed Buffers : 4 29
          Sum: 33, Avg: 16, Min: 4, Max: 29, Diff: 25]
      [Ext Root Scanning (ms):  11.4  0.0
       Avg:   5.7, Min:   0.0, Max:  11.4, Diff:  11.4]
      [Mark Stack Scanning (ms):  0.0  0.0
       Avg:   0.0, Min:   0.0, Max:   0.0, Diff:   0.0]
      [Scan RS (ms):  0.0  1.0
       Avg:   0.5, Min:   0.0, Max:   1.0, Diff:   1.0]
      [Object Copy (ms):  5.3  10.9
       Avg:   8.1, Min:   5.3, Max:  10.9, Diff:   5.6]
      [Termination (ms):  0.0  0.0
       Avg:   0.0, Min:   0.0, Max:   0.0, Diff:   0.0]
         [Termination Attempts : 1 1
          Sum: 2, Avg: 1, Min: 1, Max: 1, Diff: 0]
      [GC Worker End Time (ms):  15078.5  15078.5
       Avg: 15078.5, Min: 15078.5, Max: 15078.5, Diff:   0.0]
      [GC Worker Times (ms):  28.5  13.5
       Avg:  21.0, Min:  13.5, Max:  28.5, Diff:  15.0]
      [Other:   7.8 ms]
   [Clear CT:   0.0 ms]
   [Other:   0.2 ms]
      [Choose CSet:   0.0 ms]
   [ 95M->36M(1024M)]
 [Times: user=0.03 sys=0.01, real=0.03 secs]
Total time for which application threads were stopped: 0.0293990 seconds
Application time: 0.1566000 seconds
...
2679.026: [GC pause (young), 0.03752900 secs]
   [Parallel Time:  36.3 ms]
      [GC Worker Start Time (ms):  2679026.3  2679036.2
       Avg: 2679031.3, Min: 2679026.3, Max: 2679036.2, Diff:   9.9]
      [Update RS (ms):  15.6  7.4
       Avg:  11.5, Min:   7.4, Max:  15.6, Diff:   8.2]
         [Processed Buffers : 1 27
          Sum: 28, Avg: 14, Min: 1, Max: 27, Diff: 26]
      [Ext Root Scanning (ms):  18.2  2.4
       Avg:  10.3, Min:   2.4, Max:  18.2, Diff:  15.8]
      [Mark Stack Scanning (ms):  0.0  0.0
       Avg:   0.0, Min:   0.0, Max:   0.0, Diff:   0.0]
      [Scan RS (ms):  0.1  0.3
       Avg:   0.2, Min:   0.1, Max:   0.3, Diff:   0.3]
      [Object Copy (ms):  1.6  15.4
       Avg:   8.5, Min:   1.6, Max:  15.4, Diff:  13.8]
      [Termination (ms):  0.0  0.0
       Avg:   0.0, Min:   0.0, Max:   0.0, Diff:   0.0]
         [Termination Attempts : 1 1
          Sum: 2, Avg: 1, Min: 1, Max: 1, Diff: 0]
      [GC Worker End Time (ms):  2679061.8  2679061.8
       Avg: 2679061.8, Min: 2679061.8, Max: 2679061.8, Diff:   0.0]
      [GC Worker Times (ms):  35.5  25.6
       Avg:  30.6, Min:  25.6, Max:  35.5, Diff:   9.9]
      [Other:   5.8 ms]
   [Clear CT:   0.2 ms]
   [Other:   1.1 ms]
      [Choose CSet:   0.0 ms]
   [ 537M->50M(1024M)]
 [Times: user=0.04 sys=0.00, real=0.04 secs]
Total time for which application threads were stopped: 0.0379760 seconds
Application time: 0.1687850 seconds
...
7400.105: [GC pause (young), 0.02248700 secs]
   [Parallel Time:  21.2 ms]
      [GC Worker Start Time (ms):  7400105.2  7400105.2
       Avg: 7400105.2, Min: 7400105.2, Max: 7400105.2, Diff:   0.0]
      [Update RS (ms):  4.3  4.0
       Avg:   4.1, Min:   4.0, Max:   4.3, Diff:   0.3]
         [Processed Buffers : 18 14
          Sum: 32, Avg: 16, Min: 14, Max: 18, Diff: 4]
      [Ext Root Scanning (ms):  6.6  6.8
       Avg:   6.7, Min:   6.6, Max:   6.8, Diff:   0.2]
      [Mark Stack Scanning (ms):  0.0  0.0
       Avg:   0.0, Min:   0.0, Max:   0.0, Diff:   0.0]
      [Scan RS (ms):  0.2  0.2
       Avg:   0.2, Min:   0.2, Max:   0.2, Diff:   0.0]
      [Object Copy (ms):  9.3  9.3
       Avg:   9.3, Min:   9.3, Max:   9.3, Diff:   0.1]
      [Termination (ms):  0.0  0.0
       Avg:   0.0, Min:   0.0, Max:   0.0, Diff:   0.0]
         [Termination Attempts : 1 1
          Sum: 2, Avg: 1, Min: 1, Max: 1, Diff: 0]
      [GC Worker End Time (ms):  7400125.6  7400125.6
       Avg: 7400125.6, Min: 7400125.6, Max: 7400125.6, Diff:   0.0]
      [GC Worker Times (ms):  20.4  20.4
       Avg:  20.4, Min:  20.4, Max:  20.4, Diff:   0.0]
      [Other:   0.8 ms]
   [Clear CT:   0.2 ms]
   [Other:   1.1 ms]
      [Choose CSet:   0.0 ms]
   [ 546M->69M(1024M)]
 [Times: user=0.05 sys=0.00, real=0.03 secs]
Total time for which application threads were stopped: 0.0237370 seconds
Application time: 1.2824250 seconds
...
Heap
 garbage-first heap   total 1048576K, used 511044K [0x00000000bae00000, 0x00000000fae00000, 0x00000000fae00000)
  region size 1024K, 437 young (447488K), 6 survivors (6144K)
 compacting perm gen  total 36864K, used 36786K [0x00000000fae00000, 0x00000000fd200000, 0x0000000100000000)
   the space 36864K,  99% used [0x00000000fae00000, 0x00000000fd1ec880, 0x00000000fd1eca00, 0x00000000fd200000)
No shared spaces configured.

Some Coherence statistics from the jconsole MBean browser after the test has been running for two hours and two minutes are:

server1 server2
total gets 117469308 117174477
total puts 7381259 7360893
task average duration [ms] 0.0876 0.0668
request average duration [ms] 0.1753 0.2732

The garbage first collector gives very good results with respect to pause times, but note that this comes at a cost when it comes to throughput (the total gets and puts are a significant factor lower than the concurrent collector - which only had to run once in the two hour time span; the rest were minor collections performed by the parallel collector).

References

[1] Memory Management in the Java HotSpot Virtual Machine.
[2] Java HotSpot Virtual Machine Garbage Collection Tuning.
[3] Monitoring and Managing Java Applications.
[4] Diagnosing a Garbage Collection Problem.
[5] The Garbage First (G1) Collector.


Data Storage Structures in Coherence

In this post we are going to conduct a little experiment in which we are going to use different cache configurations and draw some conclusions on the performance where possible. Coherence is extremely pluggable, i.e., we start with a basic set-up and configuration wise we will plug in different cache configurations.

Introduction

Coherence has three layers:

  • Named cache – seen by the application as a cloud-like structure that provides access to the data stored in the cache.
  • Cache service – responsible for the cache data distribution and retrieval. Can be replicated (data is replicated to all the nodes) or partitioned (data is partitioned across all the nodes). Two data structures are available: near-cache and continuous-query-cache. These consist of two tiers, which usually consist of a local cache in the front and a partitioned cache in the back. Note that the continuous query cache populates the front cache based on a query and that the near cache populates the front cache when items are requested.
  • Backing map – responsible for the data storage. Note that in the case of a partitioned cache an additional backup storage map exists in order to ensure no data is lost if a certain node fails. Some examples are:
    • Local cache – stores all the data on the heap (fastest access). It is used as a backing map in the replicated and partitioned cache and as the front cache for the near-cache and continuous-query-cache.
    • External cache – stores the data off-heap (more storage capacity but at the cost of lesser performance).
      • NIO memory manager – stores the data in memory but outside the Java heap.
      • NIO file manager – stores the data in memory mapped files, which affects performance.
    • Read-write cache – has an internal cache (usually a local cache) and a cache loader to load data from an external source or a cache store that adds the ability to update data in an external source.

The following tests will be run:

  • Distributed Cache
    • Backing map – local cache
    • Backing map – external cache nio memory
    • Backing map – external cache nio file
    • Backing map – ram journal backed by a flash journal (elastic data feature)
    • Backing map – flash journal
    • Backing map – read-write cache with the internal cache configured as a local cache
  • Near cache
    • front – local cache
    • back – distributed cache with a local cache as backing map.

Basic set-up

We have one entity

package model.entities;

import com.tangosol.io.ExternalizableLite;
import com.tangosol.io.pof.PofReader;
import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;
import com.tangosol.util.ExternalizableHelper;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class Klant implements ExternalizableLite {

    private Integer klantnummer;
    private String naam;
    private String adres;
    private String stad;
    private String provincie;
    private String postcode;
    private Integer gebied;
    private String telefoonnummer;
    private Integer reputatieNummer;
    private Double kredietlimiet;
    private String commentaar;

    public Klant() {
    }

    public Integer getKlantnummer() {
        return klantnummer;
    }

    public void setKlantnummer(Integer klantnummer) {
        this.klantnummer = klantnummer;
    }

    public String getNaam() {
        return naam;
    }

    public void setNaam(String naam) {
        this.naam = naam;
    }

    public String getAdres() {
        return adres;
    }

    public void setAdres(String adres) {
        this.adres = adres;
    }

    public String getStad() {
        return stad;
    }

    public void setStad(String stad) {
        this.stad = stad;
    }

    public String getProvincie() {
        return provincie;
    }

    public void setProvincie(String provincie) {
        this.provincie = provincie;
    }

    public String getPostcode() {
        return postcode;
    }

    public void setPostcode(String postcode) {
        this.postcode = postcode;
    }

    public Integer getGebied() {
        return gebied;
    }

    public void setGebied(Integer gebied) {
        this.gebied = gebied;
    }

    public String getTelefoonnummer() {
        return telefoonnummer;
    }

    public void setTelefoonnummer(String telefoonnummer) {
        this.telefoonnummer = telefoonnummer;
    }

    public Integer getReputatieNummer() {
        return reputatieNummer;
    }

    public void setReputatieNummer(Integer reputatieNummer) {
        this.reputatieNummer = reputatieNummer;
    }

    public Double getKredietlimiet() {
        return kredietlimiet;
    }

    public void setKredietlimiet(Double kredietlimiet) {
        this.kredietlimiet = kredietlimiet;
    }

    public String getCommentaar() {
        return commentaar;
    }

    public void setCommentaar(String commentaar) {
        this.commentaar = commentaar;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }

        if (object == null) {
            return false;
        }

        if (!(object instanceof Klant)) {
            return false;
        }

        Klant klant = (Klant) object;
        return klantnummer.equals(klant.getKlantnummer());
    }

    @Override
    public int hashCode() {
        if (klantnummer != null) {
            return 37 * klantnummer.hashCode();
        } else {
            return System.identityHashCode(this);
        }
    }

    @Override
    public String toString() {
        return naam + ", " + adres;
    }

    public void readExternal(PofReader reader) throws IOException {
        setKlantnummer(reader.readInt(0));
        setNaam(reader.readString(1));
        setAdres(reader.readString(2));
        setStad(reader.readString(3));
        setProvincie(reader.readString(4));
        setPostcode(reader.readString(5));
        setGebied(reader.readInt(6));
        setTelefoonnummer(reader.readString(7));
        setReputatieNummer(reader.readInt(8));
        setKredietlimiet(reader.readDouble(9));
        setCommentaar(reader.readString(10));
    }

    public void writeExternal(PofWriter writer) throws IOException {
        if (getKlantnummer() != null) {
            writer.writeInt(0, getKlantnummer());
        }
        if (getNaam() != null) {
            writer.writeString(1, getNaam());
        }
        if (getAdres() != null) {
            writer.writeString(2, getAdres());
        }
        if (getStad() != null) {
            writer.writeString(3, getStad());
        }
        if (getProvincie() != null) {
            writer.writeString(4, getProvincie());
        }
        if (getPostcode() != null) {
            writer.writeString(5, getPostcode());
        }
        if (getGebied() != null) {
            writer.writeInt(6, getGebied());
        }
        if (getTelefoonnummer() != null) {
            writer.writeString(7, getTelefoonnummer());
        }
        if (getReputatieNummer() != null) {
            writer.writeInt(8, getReputatieNummer());
        }
        if (getKredietlimiet() != null) {
            writer.writeDouble(9, getKredietlimiet());
        }
        if (getCommentaar() != null) {
            writer.writeString(10, getCommentaar());
        }
    }

    public void readExternal(DataInput dataInput) throws IOException {
        setKlantnummer(dataInput.readInt());
        setNaam(ExternalizableHelper.readSafeUTF(dataInput));
        setAdres(ExternalizableHelper.readSafeUTF(dataInput));
        setStad(ExternalizableHelper.readSafeUTF(dataInput));
        setProvincie(ExternalizableHelper.readSafeUTF(dataInput));
        setPostcode(ExternalizableHelper.readSafeUTF(dataInput));
        setGebied(dataInput.readInt());
        setTelefoonnummer(ExternalizableHelper.readSafeUTF(dataInput));
        setReputatieNummer(dataInput.readInt());
        setKredietlimiet(dataInput.readDouble());
        setCommentaar(ExternalizableHelper.readSafeUTF(dataInput));
    }

    public void writeExternal(DataOutput dataOutput) throws IOException {
        if (getKlantnummer() != null) {
            dataOutput.writeInt(getKlantnummer());
        }
        if (getNaam() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getNaam());
        }
        if (getAdres() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getAdres());
        }
        if (getStad() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getStad());
        }
        if (getProvincie() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getProvincie());
        }
        if (getPostcode() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getPostcode());
        }
        if (getGebied() != null) {
            dataOutput.writeInt(getGebied());
        }
        if (getTelefoonnummer() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getTelefoonnummer());
        }
        if (getReputatieNummer() != null) {
            dataOutput.writeInt(getReputatieNummer());
        }
        if (getKredietlimiet() != null) {
            dataOutput.writeDouble(getKredietlimiet());
        }
        if (getCommentaar() != null) {
            ExternalizableHelper.writeSafeUTF(dataOutput, getCommentaar());
        }
    }
}

Here, we have implemented PortableObject and ExternalizableLite. We perform basic cache operations (get, put and remove) for which we define the following interface

package model.logic;

import java.io.Serializable;
import java.util.List;

public interface GenericDAO<T, ID extends Serializable> {
    public void addEntity(ID id, T entity);

    public void removeEntity(ID id);

    public T findEntity(ID id);

    public List<T> findEntities();
}

The interface can be implemented as follows:

package model.logic;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.ValueExtractor;
import com.tangosol.util.extractor.ChainedExtractor;
import com.tangosol.util.filter.EqualsFilter;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public abstract class GenericCoherenceDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {

    private Class<T> persistentClass;
    private NamedCache namedCache;

    public GenericCoherenceDAO() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            setPersistentClass((Class<T>) parameterizedType.getActualTypeArguments()[0]);
        } else {
            System.out.println("Not an instance of parameterized type: " + type);
        }

        setNamedCache(CacheFactory.getCache(getPersistentClass().getName()));
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public void setPersistentClass(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public NamedCache getNamedCache() {
        return namedCache;
    }

    public void setNamedCache(NamedCache namedCache) {
        this.namedCache = namedCache;
    }

    public void addEntity(ID id, T entity) {
        getNamedCache().put(id, entity);
    }

    public void removeEntity(ID id) {
        getNamedCache().remove(id);
    }

    public T findEntity(ID id) {
        return (T) getNamedCache().get(id);
    }

    public List<T> findEntities() {
        ValueExtractor extractor = new ChainedExtractor("getClass.getName");
        Set keys = getNamedCache().keySet(new EqualsFilter(extractor, getPersistentClass().getName()));
        return new ArrayList<T>(getNamedCache().getAll(keys).values());
    }
}

Specific entity functionality is implemented in entity specific DAOs, for example,

package model.logic;

import model.entities.Klant;
import java.util.Set;

public interface KlantDAO extends GenericDAO<Klant, Integer> {
    public Set<Klant> getKlantData();
}

Which is implemented as follows

package model.logic;

import com.tangosol.net.cache.ContinuousQueryCache;
import com.tangosol.util.Filter;
import com.tangosol.util.QueryHelper;
import model.entities.Klant;
import java.util.Set;

public class KlantDAOBean extends GenericCoherenceDAO<Klant, Integer> implements KlantDAO {

    private ContinuousQueryCache continuousQueryCache;

    public KlantDAOBean() {
        Filter filter = QueryHelper.createFilter("kredietlimiet between 4000.0 and 12000.0");
        continuousQueryCache = new ContinuousQueryCache(getNamedCache(), filter);
    }

    public Set<Klant> getKlantData() {
        return continuousQueryCache.entrySet();
    }
}

To test the environment we will use the following:

package model.test;

import model.entities.Klant;
import model.logic.KlantDAO;
import model.logic.KlantDAOBean;

import java.util.Random;

public class Test {

    private Random generator = new Random();

    public static void main(String[] args) {
        Test test = new Test();

        KlantDAO klantDAO = new KlantDAOBean();

        test.doRandomReadWriteTest(klantDAO);
    }

    private void doRandomReadWriteTest(KlantDAO klantDAO) {
        while (true) {
            // generate a random client
            Klant klant = createKlant();
            // insert or update a client - an update is issued when the client already exists
            klantDAO.addEntity(klant.getKlantnummer(), klant);
            if (generator.nextDouble() &lt; 0.001) {
                // remove a client
                klantDAO.removeEntity(generateKlantNummer());
                // get all client data
                klantDAO.findEntities();
                // get data from the continuous query cache
                klantDAO.getKlantData();
            } else {
                // find a client by ID
                klantDAO.findEntity(generateKlantNummer());
            }
        }
    }

    private Klant createKlant() {
        int klantnummer = generateKlantNummer();

        Klant klant = new Klant();
        klant.setKlantnummer(klantnummer);
        klant.setNaam("Middleware" + klantnummer);
        klant.setAdres("Magic");
        klant.setStad("Pune");
        klant.setProvincie("IN");
        klant.setPostcode("1234AB");
        klant.setGebied(1);
        klant.setTelefoonnummer("123-4567");
        klant.setReputatieNummer(1);
        klant.setKredietlimiet(Math.rint(generator.nextDouble() * 5000.0));
        klant.setCommentaar(Long.toString(Math.abs(generator.nextLong()), 36));

        return klant;
    }

    private Integer generateKlantNummer() {
        int klantnummer = generator.nextInt(10000);
        if (klantnummer == 0 || (klantnummer &gt;= 100 && klantnummer &lt;= 109)) {
            return 42;
        } else {
            return klantnummer;
        }
    }
}

We further create two start scripts. One to start a default cache server and another to start the test.

#!/bin/sh
# coherence options
COHERENCE_MANAGEMENT_OPTIONS="-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true"
COHERENCE_OPTIONS="-Dtangosol.coherence.cacheconfig=tryout-cache-config.xml ${COHERENCE_MANAGEMENT_OPTIONS}"
export COHERENCE_OPTIONS

JAVA_HOME="/home/oracle/documents/jrrt-4.0.1-1.6.0"
#JAVA_HOME="/home/oracle/documents/jdk1.6.0_24"
export JAVA_HOME
MEM_ARGS="-jrockit -Xms1024m -Xmx1024m -Xns256m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -XX:+UseCallProfiling"
#MEM_ARGS="-server -Xmx1024m -Xms1024 -Xmn256m -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycleMin=0 -XX:CMSIncrementalDutyCycle=10"
export MEM_ARGS

CLASSPATH="/home/oracle/temp/TryOut/lib/Coherence/coherence-hibernate.jar:/home/oracle/temp/TryOut/lib/Coherence/commonj.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence-work.jar:/home/oracle/temp/TryOut/lib/Database/ojdbc6.jar:/home/oracle/temp/TryOut/lib/Hibernate/jta.jar:/home/oracle/temp/TryOut/lib/Hibernate/ehcache-1.2.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/hibernate3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-logging-1.0.4.jar:/home/oracle/temp/TryOut/lib/Hibernate/dom4j-1.6.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/cglib-2.1.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-collections-2.1.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm.jar:/home/oracle/temp/TryOut/lib/Hibernate/c3p0-0.9.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/antlr-2.7.6.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm-attrs.jar:/home/oracle/temp/TryOut/out/artifacts/test/test.jar"
export CLASSPATH

# start the default cache server
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} com.tangosol.net.DefaultCacheServer
#!/bin/sh
# coherence options
COHERENCE_MANAGEMENT_OPTIONS="-Dtangosol.coherence.management=all -Dtangosol.coherence.management.remote=true"
COHERENCE_OPTIONS="-Dtangosol.coherence.cacheconfig=tryout-cache-config.xml"
export COHERENCE_OPTIONS

JAVA_HOME="/home/oracle/documents/jrrt-4.0.1-1.6.0"
#JAVA_HOME="/home/oracle/documents/jdk1.6.0_24"
export JAVA_HOME
MEM_ARGS="-jrockit -Xms1024m -Xmx1024m -Xns256m -XXkeepAreaRatio:25 -Xgc:pausetime -XpauseTarget:200ms -XX:+UseCallProfiling"
#MEM_ARGS="-server -Xmx1024m -Xms1024 -Xmn256m -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycleMin=0 -XX:CMSIncrementalDutyCycle=10"
export MEM_ARGS

CLASSPATH="/home/oracle/temp/TryOut/lib/Coherence/coherence-hibernate.jar:/home/oracle/temp/TryOut/lib/Coherence/commonj.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence.jar:/home/oracle/temp/TryOut/lib/Coherence/coherence-work.jar:/home/oracle/temp/TryOut/lib/Database/ojdbc6.jar:/home/oracle/temp/TryOut/lib/Hibernate/jta.jar:/home/oracle/temp/TryOut/lib/Hibernate/ehcache-1.2.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/hibernate3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-logging-1.0.4.jar:/home/oracle/temp/TryOut/lib/Hibernate/dom4j-1.6.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/cglib-2.1.3.jar:/home/oracle/temp/TryOut/lib/Hibernate/commons-collections-2.1.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm.jar:/home/oracle/temp/TryOut/lib/Hibernate/c3p0-0.9.1.jar:/home/oracle/temp/TryOut/lib/Hibernate/antlr-2.7.6.jar:/home/oracle/temp/TryOut/lib/Hibernate/asm-attrs.jar:/home/oracle/temp/TryOut/out/artifacts/test/test.jar"
export CLASSPATH

# start the test
${JAVA_HOME}/bin/java ${MEM_ARGS} ${COHERENCE_OPTIONS} model.test.Test

Distributed cache

A distributed, or partitioned cache, is a collection of data that is distributed across a number of nodes such that exactly one node in the cluster is responsible for a piece of data. In this case the size of the cache and the processing power associated with the management of the cache can grow linearly with the size of the cluster. Operations against data in the cache involve at most one other server. Note that the distributed cache allows for a backup to be configured, in which case any cluster node can fail without data loss.

Local cache

First we will see if there is any difference as to which serialization mechanism is used. In this case we will run two tests. One that uses ExternalizableLite and one that use the Portable Object Format (POF). As a backing map we will use a local cache, i.e., we will use the following cache configuration:

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <!--defaults>
        <serializer>
            <instance>
                <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
                <init-params>
                    <init-param>
                        <param-type>String</param-type>
                        <param-value>tryout-pof-config.xml</param-value>
                    </init-param>
                </init-params>
            </instance>
        </serializer>
    </defaults-->
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>distributed-cache</scheme-name>
            <init-params>
                <init-param>
                    <param-name>back-size-limit</param-name>
                    <param-value>250M</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>distributed-cache</scheme-name>
            <service-name>DistributedCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backing-map-scheme>
                <local-scheme>
                    <scheme-ref>local-backing-map</scheme-ref>
                </local-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
        <local-scheme>
            <scheme-name>local-backing-map</scheme-name>
            <eviction-policy>hybrid</eviction-policy>
            <high-units>{back-size-limit 0}</high-units>
            <unit-calculator>binary</unit-calculator>
            <expiry-delay>{back-expiry-delay 1h}</expiry-delay>
        </local-scheme>
    </caching-schemes>
</cache-config>

Note that for ExternalizableLite no extra configuration is needed. When we want to use POF we have to enable the defaults section. The POF configuration file looks as follows:

<pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
            xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config coherence-pof-config.xsd">
    <user-type-list>
        <include>coherence-pof-config.xml</include>
        <user-type>
            <type-id>1001</type-id>
            <class-name>model.entities.Klant</class-name>
        </user-type>
    </user-type-list>
    <allow-interfaces>true</allow-interfaces>
    <allow-subclasses>true</allow-subclasses>
</pof-config>

Each test runs for 30 minutes and we will use the JRockit flight recording as the analysis tool.

Some statistics from the MBean browser

  ExternalizableLite Portable Object Format
total puts 1689685 1700739 1633664 1646144
total gets 35740849 35951947 33766585 33843792
task average duration [ms] 0.0548 0.0553 0.0575 0.0561
request average duration [ms] 0.1881 0.2411 0.1848 0.2421
receiver success rate 0.9999 0.9999 0.9999 0.9999
publisher success rate 0.9999 0.9999 0.9999 0.9999

here is not much difference performance wise between the two serializable mechanisms. As we are also setting up a read-write cache, which has a bug when using POF that is solved in Coherence 3.7.1, we will choose ExternalizableLite as the serialization mechanism.

External cache

We start with the following configuration. This configures a distributed cache that uses an off-heap backing map.

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>distributed-cache</scheme-name>
            <init-params>
                <init-param>
                    <param-name>back-size-limit</param-name>
                    <param-value>250M</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>distributed-cache</scheme-name>
            <service-name>DistributedCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backup-storage>
                <type>off-heap</type>
                <initial-size>1MB</initial-size>
                <maximum-size>50MB</maximum-size>
            </backup-storage>
            <backing-map-scheme>
                <partitioned>true</partitioned>
                <external-scheme>
                    <scheme-ref>external-backing-map</scheme-ref>
                </external-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
        <external-scheme>
            <scheme-name>external-backing-map</scheme-name>
            <nio-memory-manager>
                <initial-size>1MB</initial-size>
                <maximum-size>50MB</maximum-size>
            </nio-memory-manager>
            <high-units>{back-size-limit 0}</high-units>
            <unit-calculator>binary</unit-calculator>
            <expiry-delay>{back-expiry-delay 1h}</expiry-delay>
        </external-scheme>
    </caching-schemes>
</cache-config>

To configure a distributed cache that uses a file-mapped backing map we can use the following:

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>distributed-cache</scheme-name>
            <init-params>
                <init-param>
                    <param-name>back-size-limit</param-name>
                    <param-value>250M</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>distributed-cache</scheme-name>
            <service-name>DistributedCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backup-storage>
                <type>file-mapped</type>
                <initial-size>1MB</initial-size>
                <maximum-size>50MB</maximum-size>
                <directory>/home/oracle/temp/backup</directory>
            </backup-storage>
            <backing-map-scheme>
                <partitioned>true</partitioned>
                <external-scheme>
                    <scheme-ref>external-backing-map</scheme-ref>
                </external-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
        <external-scheme>
            <scheme-name>external-backing-map</scheme-name>
            <nio-file-manager>
                <initial-size>1MB</initial-size>
                <maximum-size>50MB</maximum-size>
                <directory>/home/oracle/temp/storage</directory>
            </nio-file-manager>
            <high-units>{back-size-limit 0}</high-units>
            <unit-calculator>binary</unit-calculator>
            <expiry-delay>{back-expiry-delay 1h}</expiry-delay>
        </external-scheme>
    </caching-schemes>
</cache-config>

Elastic data

Background information on the elastic data feature can be found here. To configure a distributed cache that uses a ram journal backed by a flash journal we can use the following:

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>distributed-cache</scheme-name>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>distributed-cache</scheme-name>
            <service-name>DistributedCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backing-map-scheme>
                <ramjournal-scheme/>
				<!--flashjournal-scheme/-->
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
    </caching-schemes>
</cache-config>

The journaling behavior is configured by using the tangosol-coherence-override.xml file, for example,

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
           xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config coherence-operational-config.xsd">
    <cluster-config>
        <journaling-config>
            <ramjournal-manager>
                <maximum-value-size>16KB</maximum-value-size>
                <maximum-size system-property="tangosol.coherence.ramjournal.size">25%</maximum-size>
            </ramjournal-manager>
            <flashjournal-manager>
                <maximum-value-size>64KB</maximum-value-size>
                <maximum-file-size>2048KB</maximum-file-size>
                <block-size>256KB</block-size>
                <maximum-pool-size>16MB</maximum-pool-size>
                <directory>/home/oracle/temp/journaling</directory>
                <async-limit>16MB</async-limit>
            </flashjournal-manager>
        </journaling-config>
    </cluster-config>
</coherence>

The RAM journal manager contains the configuration for a RAM journal that manages memory buffers for journal-based storage in-memory. Note that a RAM journal always uses a flash journal to store large objects that is also used as an overflow when the amount of total memory is reached.

  • maximum value size – binary values stored in the RAM journal that exceed the maximum value are delegated to the flash journal.
  • maximum size – the maximum amount of RAM.
  • maximum file size – maximum of the underlying journal files.
  • block size – the size of the write buffer (a multiple of the disk’s optimal size and a power of two).
  • maximum pool size – size of the buffer pool.
  • directory – directory where the journal files are placed.
  • async limit – maximum of the backlog (the amount of data that has yet to be persisted.

Read-write cache

To configure a distributed cache that uses a read-write cache with the internal cache configured as a local cache we can use the following:

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>distributed-read-write-cache</scheme-name>
            <init-params>
                <init-param>
                    <param-name>back-size-limit</param-name>
                    <param-value>250M</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>distributed-read-write-cache</scheme-name>
            <service-name>DistributedReadWriteCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backup-count-after-writebehind>0</backup-count-after-writebehind>
            <backing-map-scheme>
                <read-write-backing-map-scheme>
                    <scheme-ref>read-write-backing-map</scheme-ref>
                </read-write-backing-map-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
        <read-write-backing-map-scheme>
            <scheme-name>read-write-backing-map</scheme-name>
            <internal-cache-scheme>
                <local-scheme>
                    <scheme-ref>local-backing-map</scheme-ref>
                </local-scheme>
            </internal-cache-scheme>
            <cachestore-scheme>
                <class-scheme>
                    <class-name>com.tangosol.coherence.hibernate.HibernateCacheStore</class-name>
                    <init-params>
                        <init-param>
                            <param-type>String</param-type>
                            <param-value>{cache-name}</param-value>
                        </init-param>
                    </init-params>
                </class-scheme>
            </cachestore-scheme>
            <write-delay>{write-delay 10s}</write-delay>
            <write-batch-factor>{write-batch-factor 0.75}</write-batch-factor>
            <write-requeue-threshold>{write-requeue-threshold 128}</write-requeue-threshold>
            <refresh-ahead-factor>{refresh-ahead-factor 0.1}</refresh-ahead-factor>
        </read-write-backing-map-scheme>
        <local-scheme>
            <scheme-name>local-backing-map</scheme-name>
            <eviction-policy>hybrid</eviction-policy>
            <high-units>{back-size-limit 0}</high-units>
            <unit-calculator>binary</unit-calculator>
            <expiry-delay>{back-expiry-delay 1h}</expiry-delay>
        </local-scheme>
    </caching-schemes>
</cache-config>

Results

Some statistics from the MBean browser:

  Local cache NIO Memory NIO File
total puts 1689685 1700739 1535619 1551896 1430721 1441634
total gets 35740849 35951947 31607278 31942770 29822538 30078638
task average duration [ms] 0.0548 0.0553 0.0806 0.0804 0.0845 0.0873
request average duration [ms] 0.1881 0.2411 0.2138 0.2685 0.2743 0.2936
  RAM journal Flash journal Read-write cache
total puts 1684498 1689806 1441890 1468968 1684498 1689806
total gets 34594278 34733602 31192666 31870588 34594278 34733602
task average duration [ms] 0.0582 0.0619 0.0919 0.1031 0.0582 0.0619
request average duration [ms] 0.1961 0.2460 0.2169 0.2836 0.1961 0.2460

The numbers were to be expected, i.e., the in-memory variants are performing better than the file-based ones.

Near cache

To configure a near cache with a local cache as the front cache and a distributed cache with a local cache as the back cache we can use the following:

<cache-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://xmlns.oracle.com/coherence/coherence-cache-config"
              xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-cache-config coherence-cache-config.xsd">
    <caching-scheme-mapping>
        <cache-mapping>
            <cache-name>*</cache-name>
            <scheme-name>near-cache</scheme-name>
            <init-params>
                <init-param>
                    <param-name>front-size-limit</param-name>
                    <param-value>1000</param-value>
                </init-param>
                <init-param>
                    <param-name>back-size-limit</param-name>
                    <param-value>250M</param-value>
                </init-param>
            </init-params>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <near-scheme>
            <scheme-name>near-cache</scheme-name>
            <front-scheme>
                <local-scheme>
                    <high-units>{front-size-limit 0}</high-units>
                    <expiry-delay>{front-expiry-delay 1m}</expiry-delay>
                </local-scheme>
            </front-scheme>
            <back-scheme>
                <distributed-scheme>
                    <scheme-ref>distributed-cache</scheme-ref>
                </distributed-scheme>
            </back-scheme>
            <invalidation-strategy>none</invalidation-strategy>
            <autostart>true</autostart>
        </near-scheme>
        <distributed-scheme>
            <scheme-name>distributed-cache</scheme-name>
            <service-name>DistributedCache</service-name>
            <thread-count>5</thread-count>
            <backup-count>1</backup-count>
            <backing-map-scheme>
                <local-scheme>
                    <scheme-ref>local-backing-map</scheme-ref>
                </local-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
        <local-scheme>
            <scheme-name>local-backing-map</scheme-name>
            <eviction-policy>hybrid</eviction-policy>
            <high-units>{back-size-limit 0}</high-units>
            <unit-calculator>binary</unit-calculator>
            <expiry-delay>{back-expiry-delay 1h}</expiry-delay>
        </local-scheme>
    </caching-schemes>
</cache-config>

Results

Some garbage collection statistics from the flight recordings:

  Local cache NIO Memory NIO File RAM journal Flash journal Read write cache Near cache
Garbage collections 509 531 495 548 507 492 531
Average main pause [ms] 128.4 117.0 117.9 119.9 124.5 126.1 157.8
Maximum main pause [ms] 275.9 265.4 248.4 189.6 241.1 289.4 302.8

The following are the hot packages(classes):

  • com.tangosol.util (ExternalizableHelper) – used when objects are deserialized/serialized which is happening a lot as we are constantly getting object from and putting objects into the cache.
  • com.tangosol.io (AbstractByteArrayReadBuffer and ByteArrayWriteBuffer) – used when objects are deserialized/serialized.
  • com.tangosol.coherence.component.util.daemon.queueProcessor.packetProcessor (PacketPublisher and PacketReceiver) – used when there are two or more nodes in the cluster.
  • com.tangosol.coherence.component.util.daemon.queueProcessor.server.grid.partionedService (PartionedCache)
  • with the near cache com.tangosol.net.cache (OldCache)
  • with POF com.tangosol.io.pof (PofBufferReader and PofBufferWriter) – used when objects are deserialized/serialized when POF is enabled.

There is nothing out of the ordinary, but at least we have some nice examples on how the set-up difference cache configurations.

References

[1] Introduction to Caches.
[2] Implementing Storage and Backing Maps.
[3] Caching Data Sources.


  • Testimonials

  • RSS Middleware Magic – JBoss

  • Receive FREE Updates


    FREE Email updates of our new posts Enter your email address:



  • Magic Archives

  • Sitemeter Status

  • ClusterMap 7-Nov-2011 till Date

  • ClusterMap 6-Nov-2010 till 7-Nov-2011

  • Copyright © 2010-2012 Middleware Magic. All rights reserved. | Disclaimer