Tuning For Faster JVM Startup

This blog will show you how I reduced the jvm startup time with 60%.

I wanted to use the jvm as base for scripting what I normally do in bash. But even the simplest ‘Hello world’ took about 697ms to execute. This takes about < 1ms if I use bash.
So I looked into the options I have to slim down the jvm startup time. The test I made was a ‘(println “Hello world.”)’, a small Clojure one liner.

The baseline, on the test system is:
java -Xbootclasspath/a:./clojure-1.8.0.jar clojure.main -e '(println "Hello world")' which took about 697ms.
If you add some jvm startup params it is getting a little bit better:
java -Xbootclasspath/a:./clojure-1.8.0.jar -XX:+TieredCompilation -XX:TieredStopAtLevel=1 clojure.main -e '(println "Hello world")' this will bring down the startup time to 545ms.
A reduction of about 20%. Not bad for two additional parms.

These two parms actual tell the jvm to behave as a -client instead of the default -server. I am on OSX and using a 64bit jvm on a server class system (>2 cpu and >2GB memory).

This was still not enough for me. I wanted to have an even faster startup. So at the end I ended up with this java -Xbootclasspath/a:./clojure-1.8.0.jar -Xshare:on -XX:+TieredCompilation -XX:TieredStopAtLevel=1 clojure.main -e '(println "Hello world and CDS enabled and -client enabled")' which gave me a startup time of 271ms. A reduction down to 40% of the original 697ms.

That last step is based on Class Data Sharing, the reason I added -Xshare:on. For some background information you can look at CDS.

CDS is a file which the jre writes its bootstrap classes into, to speed up the jvm startup. Not all jvm install programs create that file. So have a go and use java -Xshare:dump. You will notice a different startup time already, if the jvm installer did not create this particular file.

For me I have added the clojure v1.8.0 classes to this CDS file and that’s the reason I went from 697ms downto 271ms (60% reduction) of startup time.
You need some shell scripting capabilities but follow the next script:

# start up the jre to generate its own cds file list
java -Xshare:dump -XX:DumpLoadedClassList=jre-cds-list
# generate our own cds list
jar -tf clojure-1.8.0.jar | grep class | sed 's/.class//g' > our-cds-list
# combine the two cds lists into one
cat jre-cds-list our-cds-list > combined-cds-list
# generate the new combined cds jsa file
java -Xbootclasspath/a:./clojure-1.8.0.jar -XX:SharedClassListFile=combined-cds-list -Xshare:dump

Happy coding. And don’t forget this is just for scripting not for long running java programs.

docker ca certificate for private registry on osx

Docker has changed to ssl as from v1.3.1. But until now I could not use it with local / on-premise docker registries and had to fall-back to –insecure options.
Today I read a docker issue at 805 and the last comment of ‘rossbachp’ gave the solution.

Get your hand on the public CA key part of your self signed server key. That is the one you have used to sign your self signed certificate for your server.
Create inside your boot2docker ‘boot2docker ssh’ a directory named after the private registry you want to access:
boot2docker ssh
sudo su -
cd /var/lib/boot2docker
mkdir registry.acme.org
cd registry.acme.org
cp /from/some/location/ca.pem .

Create a script in /var/lib/boot2docker/bootlocal.sh

#!/bin/bash
cat /var/lib/boot2docker/registry.acme.org/ca.pem >> /etc/ssl/cacert.pem

Now you can push your docker images to your on-premise docker registry.

camel cxf https server endpoint

I wanted to configure in camel a cxf https endpoint. Normally I do it the forceful way to update the jdk certificates but it can be done in another way.
Define the jax-ws contract first endpoint, although that can be done also in a code first manner.

This is the defined endpoint, it is directly taken from a camel sample named ‘camel-cxf-contract-first-blueprint’.

 
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
	xmlns:camel="http://camel.apache.org/schema/blueprint" xmlns:sec="http://cxf.apache.org/configuration/security"
	xmlns:http="http://cxf.apache.org/transports/http/configuration"
	xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
	xsi:schemaLocation="
             http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
             http://camel.apache.org/schema/blueprint/cxf http://camel.apache.org/schema/blueprint/cxf/camel-cxf.xsd
             http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd
             http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd">
 
	<cxf:cxfEndpoint id="reportEndpoint"
		address="https://localhost:9080/part-five/webservices/incident"
		serviceClass="org.apache.camel.example.reportincident.ReportIncidentEndpoint"
		wsdlURL="wsdl/report_incident.wsdl">
		<cxf:properties>
			<entry key="loggingFeatureEnabled" value="true"/>
		</cxf:properties>
	</cxf:cxfEndpoint>
 
	<httpj:engine-factory bus="cxf">
		<httpj:engine port="9080">
			<httpj:tlsServerParameters>
				<sec:keyManagers keyPassword="changeit">
					<sec:keyStore type="JKS" password="changeit" resource="certs/keystore.jks" />
				</sec:keyManagers>
			</httpj:tlsServerParameters>
		</httpj:engine>
	</httpj:engine-factory>
 
	<camelContext xmlns="http://camel.apache.org/schema/blueprint">
        <route>
        <from uri="cxf:bean:reportEndpoint"/>
        <convertBodyTo type="org.apache.camel.example.reportincident.InputReportIncident"/>
        <log message="Received report incident ${body.incidentId}"/>
        <setHeader headerName="Exchange.FILE_NAME">
            <simple>report-incident-${body.incidentId}.xml</simple>
        </setHeader>
        <to uri="file:work/incident"/>
        <log message="Stored a copy of the incident as ${header.CamelFileNameProduced}"/>
        <choice>
            <when>
                <simple>${body.phone.isEmpty}</simple>
                <to uri="seda:emailMe"/>
            </when>
            <otherwise>
                <to uri="seda:callMe"/>
            </otherwise>
        </choice>
        <to uri="language:constant:classpath:ok.xml"/>
        <convertBodyTo type="org.apache.camel.example.reportincident.OutputReportIncident"/>
    </route>
    <route>
        <from uri="seda:callMe"/>
        <log message="We are going to call ${body.phone}"/>
    </route>
    <route>
        <from uri="seda:emailMe"/>
        <log message="We are going to email ${body.email}"/>
    </route>
</camelContext>
 
</blueprint>

Update the xml code snippet to make it readable again. (2015/01/25)

REST vs SOAP aka async vs sync

Had today another discussion about the async properties of the rest protocol vs the sync properties of the soap protocol in http mode. This other person was convinced that rest was async and soap could only do sync. But that’s not true. They are both sync or async but that depends on how you design the flow through your application(s).

Maybe with an example I can make myself clearer: For creating an Order you need the Order to be created by a back-end system. And you know that the Order has been created if the back-end system returns to you with an Order.CREATED status.

There are two ways to create an Order and get the status CREATED. The first sync way is for the client to call the back-end system with the Order information and during this call the back-end system creates the Order and returns within the same call with the Order.status as being created.
The second async way is to call the back-end system with the Order information and in that same call you receive from the back-end system a Status of Order.RECEIVED. Later in time you get an answer back from the back-end system that the Order has been created.

Both ways can be done through REST or SOAP or whatever. The design made it sync or async. Not the protocol used.

apache redirect config generator

Sometimes you gather all kind of nifty small utilities to do all kind of things. This is also such a small thingy.
It generates a apache httpd config part of redirecting a vhost http to https to mod_cluster.
You can find it here. It will open in a new window and is a small AngularJS application.

JAAS authorization with JBoss Fuse

The customer I was working with had a need for JAAS Authorization for the ActiveMQ broker in his JBoss Fuse install. I thought I did it by the book. But it was at the end not enough. I had done this configuration for a FuseSource installation version 7.1.x but it didn’t work for a 7.2.x (JBoss Fuse 6.0.0.redhat-024). For the current, at this writing, version of JBoss Fuse you have to do it like this:

Add or change the plugins settings of etc/activemq.xml into:

<plugins>
<jaasAuthenticationPlugin configuration=”karaf”/>
<authorizationPlugin>
<map>
<authorizationMap groupClass=”org.apache.karaf.jaas.boot.principal.RolePrincipal”><authorizationEntries><authorizationEntry queue=”>” read=”admin,broker” write=”admin,broker” admin=”admin,broker”/>

<authorizationEntry topic=”>” read=”admin,broker” write=”admin,broker” admin=”admin,broker”/>
<authorizationEntry topic=”ActiveMQ.Advisory.>” read=”admin,broker” write=”admin,broker” admin=”admin,broker”/>
</authorizationEntries>
</authorizationMap>
</map>
</authorizationPlugin>
</plugins>
It is all about the ‘groupClass’ attribute inside the ‘authorizationMap’ element.
You can read more about this at https://community.jboss.org/thread/233546.

Creating a osgi jdbc driver

For work I have to work with different datasource connections. Not only in a JEE environment but also in a OSGI environment. A datasource needs also a jdbc connection. And a jdbc driver jar bundled in osgi format is not always available. I normally try to find a osgi jdbc jar in the servicemix repository but that will work only for OSS drivers.

For a closed source jdbc driver to be converted to a bundle version of the jar you could use a maven plugin. But that is more work then the following:

Fire up a Fusesource or JBoss Fuse instance and have the jdbc driver available on the disk. Inside the fuse console execute the command ‘osgi:install wrap:file:///tmp/ojdbc6.jar’.  When the command finished it will return a number.

Use this number to go to the cache directory with this number (data/cache/bundlexxx/version0.0). Inside the directory you will find the ojdbc6.jar named as bundle.jar. Take the bundle.jar and rename it (back) to ojdbc6-osgi.jar. The -osgi addition is just a naming convention I adopted. Place ojdbc6-osgi.jar in your package manager.