Want dramatic performance improvement without changing code? That is the promise of cache. But can it deliver? OpenJPA is an Apache persistence project. An elegant feature of OpenJPA is you can speed up your lookups and reduce the load on back-end databases with a Java Cache and NO code changes. This article will show you how to install, configure, and experiment with IBM WebSphere eXtreme Scale product in conjunction with OpenJPA. You can experiment with this without spending any cash, as the cache comes in a free evaluation. The links below will guide you to the download.
You can use WebSphere eXtreme Scale (WXS) instead of caching in OpenJPA to take advantage of embedded, embedded-partitioned, and remote caching.
This is the first of two articles. This one will address using OpenJPA and eXtreme Scale without an application server. The focus is Plain Old Java Objects (POJOs) and the JDK. Part 2 will take an example with an application server and explore similar testing.
You can explore the installation, configuration, and testing of OpenJPA, IBM WebSphere eXtreme Scale, Informix, and DB2 in the following steps:
- Download, install, and configure the following:
- OpenJPA
- WebSphere Extreme Scale Cache
- Informix Innovator C Edition or DB2 Express C
- Test OpenJPA, with no cache.
- Modify the configuration to use the WebSphere eXtreme Scale cache.
- Test OpenJPA, with cache.
- Modify the OpenJPA sample to act as a simple test harness.
- Modify the OpenJPA configuration to connect to Informix or DB2.
- Analysis of results.
Enjoy your new-found performance improvements!
To avoid any confusion: OpenJPA is an Apache project. WebSphere eXtreme Scale, Informix, and DB2 are IBM products. Whereas Informix and DB2 have downloads with free license charges, WebSphere eXtreme Scale only has a free trial download. At the end of the trial period you must get a license to continue using XS. With that out of the way, let's get back to the technologies!
The download and install shouldn't present much of a challenge. You will need to register on the IBM web site. There is no charge for getting an ID for the downloads used in this article. Here are the links you need:
If you only want to experiment with OpenJPA and XS caching, then you don't have to download a database. When doing the performance testing, it becomes much more interesting to see users, SQL, buffer pool hit rates, etc. The examples will be from Informix and DB2. You are encouraged to pick one and work with it. If you choose, you can skip ahead and use the Derby database bundled with OpenJPA.
Since there are a lot of resources describing how to install this software, they won't be covered here. As you download the binaries, look for the links for install guides and other documentation if you want more information.
After completing the downloads, your directory listing on Linux may look
similar to Listing 1, but please use the md5sum
to confirm you got what you really wanted.
Listing 1. Directory listing of downloads for Linux
-rw-r--r-- 1 lurie lurie 29418160 2010-12-31 16:47 apache-openjpa-2.0.1-binary.zip -rw-r--r-- 1 lurie lurie 427579388 2010-12-31 17:35 db2exc_972_LNX_x86.tar.gz -rw-r--r-- 1 lurie lurie 69655311 2010-12-31 17:08 extremescaletrial710.zip -rw-r--r-- 1 lurie lurie 356157440 2010-12-31 17:34 iif.11.70.UC1IE.Linux-RHEL5.tar |
Unzip/untar the files into staging directories. Table 1 shows the software and installation commands to start each install.
Table 1. Installation quickstart, the .sh commands are UNIX/Linux, .bat for Windows
| Software | Installation or execution command |
|---|---|
| OpenJPA | apache-openjpa-2.0.1/examples/hellojpa/ant |
| WebSphere eXtreme Scale | ObjectGrid/gettingstarted/env.sh, runcat.sh, runcontainer.sh c1, runclient.sh i hello world |
| Informix Dynamic Server | sudo informix/ids_install |
| DB2 | expc/db2setup |
Follow the defaults for Informix and DB2. Let the script create a sample database instance for you. The graphical entry point for DB2 is shown in Figure 1.
Figure 1. Install entry point for DB2
Listing 2 shows the output of running the ant
script provided with OpenJPA. Even though caching hasn't been introduced
yet, it took 115 milliseconds to create a table. Inserting a row, based on
persisting a Java object, took 12 milliseconds. Reading the object back
took 1 millisecond. Perhaps it would be a mild overstatement to say this
is exciting stuff, but it will get more interesting as we go.
Listing 2. OpenJPA output from baseline test
lurie@merlin:/work/dwOpenJPA/work/openjpa/apache-openjpa-2.0.1/examples/hellojpa$ ant
Buildfile: build.xml
pre-compile:
compile:
[javac] Compiling 2 source files
run:
[java] 4232 hellojpa TRACE [main] openjpa.jdbc.SQL - t 8204368, conn 15666395
executing stmnt 22424679 CREATE TABLE Message (id BIGINT NOT NULL, created TIMESTAMP,
message VARCHAR(255), PRIMARY KEY (id))
[java] 4347 hellojpa TRACE [main] openjpa.jdbc.SQL - t 8204368, conn 15666395
[115 ms] spent
[java] 4683 hellojpa TRACE [main] openjpa.jdbc.SQL - t 8204368, conn 15975876
executing prepstmnt 29412736 INSERT INTO Message
(id, created, message) VALUES (?, ?, ?) [params=?, ?, ?]
[java] 4695 hellojpa TRACE [main] openjpa.jdbc.SQL - t 8204368, conn 15975876
[12 ms] spent
[java] 4969 hellojpa TRACE [main] openjpa.jdbc.SQL - t 8204368, conn 20336357
executing prepstmnt 32685187 SELECT t0.id, t0.created, t0.message FROM Message t0
[java] 4970 hellojpa TRACE [main] openjpa.jdbc.SQL - t 8204368, conn 20336357
[1 ms] spent
[java] Hello Persistence! (created on: Mon Jan 03 13:18:48 EST 2011)
BUILD SUCCESSFUL
Total time: 10 seconds
|
Modify the configuration to use the WebSphere eXtreme Scale cache
The next step is to activate the WebSphere eXtreme Scale cache without
making any changes to the Java code! You can do this by modifying the
OpenJPA persistence.xml file, and by adding the XS jar to the classpath in
the example build.xml, as shown in Listing 3 and Listing 4. Notice that
the hellojpa build file uses the build file in
the parent directory.
Be sure to use the IBM JDK when using the eXtreme Scale cache.
Listing 3. Modifications to apache-openjpa-2.0.1/examples/META-INF/persistence.xml
<property name="openjpa.ConnectionPassword"
value="secret"/>
<property name="openjpa.DataCache"
value="com.ibm.websphere.objectgrid.openjpa.ObjectGridDataCache(
ObjectGridName=BasicTestObjectGrid,ObjectGridType=EMBEDDED,
maxNumberOfReplicas=4)"/>
<property name="openjpa.QueryCache"
value="com.ibm.websphere.objectgrid.openjpa.ObjectGridQueryCache()"/>
<property name="openjpa.RemoteCommitProvider" value="sjvm"/>
<properties>
<persistence-unit>
|
Listing 4. Modifications to apache-openjpa-2.0.1/examples/build.xml
<fileset dir="${root}">
<include name="openjpa-all-*.jar"/>
<include name="lib/derby*.jar"/>
<fileset>
<!-- add path to the eXtreme Scale jar file -->
<pathelement path="xs"/>
<fileset dir="/home/lurie/tmp/xs71/ObjectGrid/lib">
<include name="objectgrid.jar"/>
<fileset>
<!-- end of mods to find eXtreme Scale jar file -->
</path>
|
You've now enabled the cache, and made no changes to the Java program, yet the cache is now ready to go.
Run hellojpa with caching enabled
That's it! Time to run the sample. If you haven't already done so, configure the path to use the IBM JVM, and re-run the sample at the command line by typing ant, as shown in Listing 5.
Listing 5. Running OpenJPA sample program with eXtreme Scale Cache enabled
/work/dwOpenJPA/work/openjpa/apache-openjpa-2.0.1/examples/hellojpa$ ant
[java] ReplicatedPar I CWOBJ1511I: BasicTestObjectGrid:IBM_SYSTEM_ENTITYMANAGER_MAPSET:0
(primary) is open for business.
[java] ReplicatedPar I CWOBJ1511I: BasicTestObjectGrid:MAPSET_BasicTestObjectGrid:0
(primary) is open for business.
[java] ObjectGridRes I CWOBJ3134I: The ObjectGrid type is embedded and the default
maximum number of replicas is 47. The maximum number of replicas must be
greater than or equal to the number of JVMs in the system.
[java] hellojpa TRACE [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176,
conn 362616221> executing prepstmnt 652224224 INSERT INTO Message
(id, created, message) VALUES (?, ?, ?) [params=?, ?, ?]
[java] hellojpa TRACE [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176,
conn 362616221> [212 ms] spent
... lines deleted ...
[java] hellojpa TRACE [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176,
conn 696330625> executing prepstmnt 856306442 SELECT t0.id, t0.created,
t0.message FROM Message t0
[java] hellojpa TRACE [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176,
conn 696330625> [1 ms] spent
|
The results don't really differ from the first case. Why? If there is only one row in the database, then a cache isn't going to make too much difference. Sorry if this is demonstrating a grasp of the obvious. To make this more interesting, we need a better test that will include a few thousand rows.
You are probably tired of having all the SQL TRACE messages scrolling
across your screen. To switch to only warning messages, edit the build.xml
file to read as follows:
value="DefaultLevel=WARN,SQL=WARN".
Modify the OpenJPA sample to act as a simple test harness: Adding looping to Main.java
For production applications, it is critical to study the expected workload and develop a test harness that mirrors reality as much as possible. Full scale testing of transaction systems with significant simulated historical data, like a year, is basic common sense unless you like production system emergencies.
In this case, you can simply create a loop to insert a lot of objects, and
then read them back. While it will demonstrate the effectiveness of the
cache, it doesn't represent a proper test harness unless you're running
helloJPA in production.
Listing 6 shows the changes to the Main.java program, and how to insert 100 rows. This is not a grand challenge. Since this test is about performance, you will be adding Informix to the configuration in the next section. Derby is fine for development, but when it comes to heavy lifting, Informix is a far better choice. The sample files also include the configuration for running on DB2. When testing with Informix, the loop will insert a lot more rows which will make it interesting.
Listing 6. Modify openjpa Main.java to put in 100 rows
EntityManager em = factory.createEntityManager();
// *** loop here to put a bunch of rows in the database
for ( int i=0; i<100;i++)
{
// *** don't forget to put a closing } below
// Begin a new local transaction so that we can persist a new entity
em.getTransaction().begin();
// Create and persist a new Message entity
em.persist(new Message("Hello Persistence!"));
// Commit the transaction, which will cause the entity to
// be stored in the database
em.getTransaction().commit();
// *** end of loop
}
|
Cache doesn't really help if you only read items once. Modify
Main.java as shown in Listing 7 to read and
report timings for two passes at what you have persisted to disk.
Listing 7. Main.java does two reads of the persisted objects
// Create a fresh, new EntityManager
EntityManager em2 = factory.createEntityManager();
// **** set up a timer of how long the queries take
long starttm = System.currentTimeMillis();
// Perform a simple query for all the Message entities
Query q = em2.createQuery("select m from Message m");
// Go through each of the entities and print out each of their
// messages, as well as the date on which it was created
for (Message m : (List<Message> q.getResultList()) {
// *** better comment this out or 20,000 prints are coming back!
// System.out.println(m.getMessage()
// + " (created on: " + m.getCreated() + ")");
}
// *** report on the first run
long end1sttm = System.currentTimeMillis();
System.out.println("\n\nfirst run took: " + (end1sttm-starttm) +
" millisec\n\n\n");
// **** second run should be in local cache
// Perform a simple query for all the Message entities
Query q2 = em2.createQuery("select m from Message m");
// Go through each of the entities and print out each of their
// messages, as well as the date on which it was created
for (Message m : (List<Message> q2.getResultList()) {
//System.out.println(m.getMessage()
//+ " (created on: " + m.getCreated() + ")");
}
long end2ndtm = System.currentTimeMillis();
System.out.println("\n\nsecond run, from cache took: "
+ (end2ndtm-end1sttm) + " millisec\n\n\n");
// Again, it is always good to clean up after ourselves
em2.close();
|
The results, as shown in listing 8, show a dramatic speed-up for using WebSphere eXtreme Scale Cache. And remember, this is with no application code changes! I know you will grant me a pass on no code changes for adding the loop to generate the heavier workload.
Listing 8. Output from test run: Dramatic speed-up using WebSphere eXtreme Scale with Derby database
[java] [1/26/11 11:00:11:776 EST] 3a883a88 SystemOut O
[java]
[java] first run took: 3761 millisec
[java]
[java]
[java]
[java] [1/26/11 11:00:11:865 EST] 3a883a88 SystemOut O
[java]
[java] second run, from cache took: 89 millisec
[java]
[java]
|
The performance improvement is over 40 times better, 3761 milliseconds to 89 milliseconds. This is hardware dependent so your mileage will vary. There are a number of environmental factors that can also impact performance. For example, if you are paging/swapping any relevant performance, then data is off the table.
Modify the OpenJPA configuration to connect to Informix or DB2
A more realistic test is to use OpenJPA with an industrial strength
database. The good news is changing the database from Derby to Informix
only requires some simple modifications in the
build.xml file, as shown in Listing 9. The
database specification is changed, and the path to the jdbc jar is
required.
Listing 9. Modifications to build.xml to use Informix Dynamic Server
build.xml
<project default="usagewarning">>
<property name="parent" value="${basedir}/.."/>
<property name="root" value="${parent}/.."/>
<!-- database connection properties
<property name="dbdriver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="dburl"
value="jdbc:derby:${basedir}/${example}-database;create=true"/>
<property name="dbuser" value=""/>
<property name="dbpass" value=""/>
-->
<!-- database connection properties -->
<!-- informix instead of derby -->
<property name="dbdriver" value="com.informix.jdbc.IfxDriver"/>
<property name="dburl"
value="jdbc:informix-sqli://merlin:54321/idsopenjpa:informixserver=ids115"/>
<property name="dbuser" value="informix"/>
<property name="dbpass" value="idsr0cks"/>
<target name="usagewarning">
PATH CHANGES
<path id="classpath"
description="The classpath to use for compiling and running">
<pathelement path="${parent}"/>
<fileset dir="${root}">
<include name="**/*.jar"/>
</fileset>
<pathelement path="xs"/>
<fileset dir="/home/lurie/tmp/xs71/ObjectGrid/lib">
<include name="objectgrid.jar"/>
</fileset>
<pathelement path="ifx"/>
<fileset dir="/opt/IBM/informix/jdbc/lib">
<include name="ifxjdbc.jar"/>
</fileset>
</path>
Informix Configuration
Don't create any tables, just a database. It seems almost too easy.
informix@merlin:~$ dbaccess - -
> create database idsopenjpa with buffered log;
Database created.
|
So was it fast? Reading this would be a waste of time if it wasn't fast! As shown in Listing 10, the Main.java program was modified to insert 10,000 rows. Informix can crank out 10,000 rows in 1 second because of its advanced buffer pool management and industrial strength architecture. There is still a significant performance improvement by having the data stored in cache in the same address space with the Java application. Beating 49 milliseconds for cache access while traversing a TCP/IP round trip is a significant challenge for any database.
Listing 10. Output from test run: Dramatic speedup using WebSphere eXtreme Scale with Informix database
[java] [1/26/11 17:28:38:751 EST] 72887288 SystemOut O
[java]
[java] first run took: 1096 millisec rows processed= 10000
[java]
[java]
[java]
[java] [1/26/11 17:28:38:800 EST] 72887288 SystemOut O
[java]
[java] second run, from cache took: 49 millisec
[java]
|
If you are curious about what is happening at the database level, look at listing 11 to see the schema.
Listing 11. Informix database schema
create table "informix".message
(
id decimal(32,0) not null ,
created datetime year to fraction(3),
message varchar(255),
primary key (id)
);
|
Conclusion: Enjoy your new-found performance improvements!
You have covered a lot of ground here with a rapid introduction to OpenJPA, WebSphere eXtreme Scale, and the use of a Java cache with the Informix Dynamic Server database. The sample files provided include all of the previously shown code, and of course include how to do this with DB2.
Please experiment with this yourself!
If you'd like to hear more on this topic, don't miss the Informix International Users Group (see Resources for more details), where Marty be presenting on this topic.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample files for this article | sampleFiles.tar | 50B | HTTP |
Information about download methods
Learn
- Use an RSS feed to request notification for the upcoming articles in
this series. (Find out more about RSS feeds of
developerWorks content.)
- Enable C++ applications for Web services
using XML-RPC (developerWorks, Jun 2006) is a step-by-step guide
to exposing C++ methods as services.
- Go to the Informix area on developerWorks, to get the resources you need to
advance your Informix skills.
- Visit the Informix International Users
Group, where Marty will be presenting on this topic at the IIUG Informix
Conference.
- Stay current with developerWorks technical events
and webcasts focused on a variety of IBM products and IT industry
topics.
- Attend a free developerWorks Live!
briefing to get up-to-speed quickly on IBM products and tools as
well as IT industry trends.
- Learn more about Information Management at
the developerWorks
Information Management zone. Find technical documentation, how-to
articles, education, downloads, product information, and more.
- Follow developerWorks on
Twitter.
- See the following article by Marty Lurie
called WebSphere tuning for the impatient which includes a discussion of
environmental aspects relevant to performance tuning.
- See the following article by Marty Lurie
called Real Time Data Acquisition to learn about connecting your
exercise bike to Informix or DB2 Using Java and Linux to capture real-time
data.
- See the following article by Marty Lurie
called Simulating Massively Parallel Database Processing on
Linux.
- See the following articles by Marty Lurie
called Federating multiple databases Part 1, and Part 2.
- See the following article by Marty Lurie
called Tunneling secure traffic via ssh.
- See the following article by Marty Lurie
called Web click stream analysis on Linux.
- See the following article by Marty Lurie
called Informix administration.
- See the following article by Marty Lurie
called Web polling.
Get products and technologies
- Build your next
development project with IBM trial
software, available for download directly from
developerWorks.
- Download a free
copy of Informix Innovator-C, a
version of Informix designed for small workloads.
- Download an
evaluation copy of WebSphere eXtreme Scale.
- Download DB2 Express-C, a free edition
of DB2 for Linux, Windows, and Mac that is easy to use and provides a
solid base to build and deploy applications.
Discuss
- Participate in the discussion forum.
- Check out the developerWorks
blogs and get involved in the developerWorks
community.

Marty Lurie started his computer career generating chads while attempting to write Fortran on an IBM 1130. His day job is in Systems Engineering for IBM's Informix organization, but if pressed he will admit he mostly plays with computers. His favorite program is the one he wrote to connect his Nordic Track to his laptop (the laptop lost two pounds, and lowered its cholesterol by 20%). Marty is an IBM-certified DB2 DBA, IBM-certified Business Intelligence Solutions Professional, and an Informix-certified Professional.




