Performance Zone is brought to you in partnership with:

I'm a Lead engineer at Terracotta, Software AG. I have 10+ years of experience with Java, but I also speak other languages, C, C++, Javascript, Coffeescript, PHP, Perl... See my blog to know about my different personal projects! Aurelien is a DZone MVB and is not an employee of DZone and has posted 17 posts at DZone. You can read more from them at their website. View Full User Profile

BigMemory 4.0 technical overview

03.13.2013
| 1280 views |
  • submit to reddit

For those out there who are working with huge data sets (from gigabytes to terabytes), BigMemory is a product worth to consider, as it allows your java application to handle large volumes of data in memory. Meaning that you get fast access to your data.

Version 4.0 is out since a few days, let’s have a technical look at what’s inside.

1) “Fast data access at terabyte scale”

There’s an interesting whitepaper that was published last year. This reports the results of scaling a test application. The size of the data set started at 2GB and went up to 1.8TB. The throughput remained within a range of approximately 10% of the mean with no garbage-collection induced latency spikes. In sum, the speed of reading/writing to BigMemory scales at around the same speed from gigabytes to terabytes of data.

The architecture is the following:

Each instance of your application is using Ehcache to cache the hotset of data in heap. Then you define in Ehcache the size of the BigMemory store you want. This part is named offheap, as it is memory that is not handled by the Garbage Collector (thus that is not heap)

You can replicate your cache/BigMemory store amongst multiple instances of your application, by connecting them to the Terracotta server. Please not that the Terracotta server can also use BigMemory to store more data.

BigMemoryArchi

In terms of development, if you’re familiar with Ehcache you won’t be lost.

Creating a Bigmemory instance will look like this:

import net.sf.ehcache.*;
import net.sf.ehcache.config.*;

Configuration cfg = new Configuration()
    .terracotta(new TerracottaClientConfiguration().url("localhost:9510"))
    .cache(new CacheConfiguration().name("myDataTableExample")
    .maxBytesLocalHeap(1, MemoryUnit.GIGABYTES)
    .maxBytesLocalOffHeap(4, MemoryUnit.GIGABYTES)
    .terracotta(new TerracottaConfiguration())
);
CacheManager manager = CacheManager.newInstance(cfg);
Ehcache myDataTableExample = manager.getEhcache("myDataTableExample");

String key = "some key";
SomeCustomEntity value = ....
SomeCustomEntity newValue = ....

myDataTableExample.put(new Element(key, value));

myDataTableExample.replace(new Element(key, newValue));

value = (SomeCustomEntity)myDataTableExample.get(key).getObjectValue();

myDataTableExample.remove(key);

manager.shutdown();

2) “Monitoring”

This refers to the monitoring tool called TMC.
After having installed the BigMemory archive, you will be able to start it from the command line with one of these scripts, depending on the version you’re using:

tools/management-console/bin/start-tmc.sh

or

management-console/bin/start-tmc.sh

Then the monitoring application can be accessed in your browser on

http://localhost:9889/tmc

TMC

In this example, the store is clustered (=shared amongst different JVMs) through the Terracotta server, and the monitoring console is getting the info from the Terracotta server.

This means that in case you’re in standalone mode (the store running in a single JVM), you’re not using the Terracotta server. You’ll need to indicate in your configuration that you intend to publish your data to the monitoring console:

ManagementRESTServiceConfiguration restCfg = new ManagementRESTServiceConfiguration();
restCfg.setSecurityServiceLocation("http://localhost:9889/tmc/api/assertIdentity");

Configuration cfg = new Configuration()
    .managementRESTService(restCfg)
    .cache(new CacheConfiguration().name("myDataTableExample")
    .maxBytesLocalHeap(1, MemoryUnit.GIGABYTES)
    .maxBytesLocalOffHeap(4, MemoryUnit.GIGABYTES)
);

3) “Fast restart for disaster recovery”

Now things become even more interesting. Not only all data is in memory, but it can be persisted to disk, so in case of a crash or after restarting the application, the data is loaded back to memory.

There are 4 options, but I’ll focus on the two most important : localRestartable and distributed

a) localRestartable is used for a standalone configuration, persisting the data to the disk

Configuration cfg = new Configuration()
    .diskStore(new DiskStoreConfiguration().path("/mydisk/mystore/"))
    .cache(new CacheConfiguration().name("myPersistentDataTableExample")
    .maxBytesLocalHeap(1, MemoryUnit.GIGABYTES)
    .maxBytesLocalOffHeap(4, MemoryUnit.GIGABYTES)
    .persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.LOCALRESTARTABLE))
);

b) distributed is used for a clustered configuration, persisting the data to the terracotta server, that will have the responsibility to persist it on disk

Configuration cfg = new Configuration()
    .diskStore(new DiskStoreConfiguration().path("/mydisk/mystore/"))
    .terracotta(new TerracottaClientConfiguration().url("localhost:9510"))
    .cache(new CacheConfiguration().name("myPersistentDataTableExample")
    .maxBytesLocalHeap(1, MemoryUnit.GIGABYTES)
    .maxBytesLocalOffHeap(4, MemoryUnit.GIGABYTES)
    .terracotta(new TerracottaConfiguration())
    .persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.DISTRIBUTED))
);

And add in the terracotta server config (tc-config.xml):

<restartable enabled="true"/>

<offheap>
<enabled>true</enabled>
<maxDataSize>....</maxDataSize>
</offheap>

4) “Search support”

As we’ve seen, with BigMemory we have a <Key, Value> In Memory Data Store that can be clustered and persisted to disk.

Since the goal is to keep as much data in memory and still provide convenient access to the data, we also have Query support, similarly to what you would find in a database.

It would take a whole post to describe all the functionalities for search support, so here is a simple example:

Say we put instances of a Person class in memory, that would have these two fields:

private String familyName;
private Integer age;

Finding every person having their family name starting by ‘A’ would be :

import net.sf.ehcache.search.*;
import net.sf.ehcache.search.aggregator.*;

Query query = myPersistentDataTableExample.createQuery()
     .addCriteria(new ILike("familyName", "A%"))
     .includeValues()
     .addOrderBy(new Criteria("familyName"), Direction.ASCENDING);

Results results = query.execute();
List<Result> all = results.all();
for (Result result : all) {
    Person person = (Person)result.getValue();
}

5) “Hadoop Ready”

This is another interesting functionality.
In case you’re not so familiar with Hadoop, this is a system that allows you to process big data sets.

It is very powerful because you can use commodity servers and Hadoop will take care of distributing the work amongst them.

Hadoop has a custom filesystem, named HDFS, and you first need to import your data on the HDFS system, before it can be processed.

However, you can’t get the results in realtime, since you need to wait for the whole process to be done before you can access to the data on HDFS.

There are some solutions emerging, like Cloudera’s Impala realtime queries.

BigMemory tackles the problem by providing a Hadoop connector. With this connector, Hadoop can send the data to BigMemory as soon as it is processed, making it available to memory in realtime.

In Hadoop, the OutputFormat and RecordWriter interfaces define how the output of the map/reduce jobs are handled.

E.g. by default, the TextOutputFormat will put the data out to a file on the HDFS system.
Instead, you can use EhcacheOutputFormat, that is a custom OutputFormat implementation that will write data to BigMemory.

If we take the famous Hadoop Wordcount example,

  public static void main(String[] args) throws Exception {
          JobConf conf = new JobConf(WordCount.class);
          conf.setJobName("wordcount");

          conf.setOutputKeyClass(Text.class);
          conf.setOutputValueClass(IntWritable.class);

          conf.setMapperClass(Map.class);
          conf.setCombinerClass(Reduce.class);
          conf.setReducerClass(Reduce.class);

          conf.setInputFormat(TextInputFormat.class);
          conf.setOutputFormat(TextOutputFormat.class);

          FileInputFormat.setInputPaths(conf, new Path(args[0]));
          FileOutputFormat.setOutputPath(conf, new Path(args[1]));

          JobClient.runJob(conf);
        }

this will turn into

  public static void main(String[] args) throws Exception {
          JobConf conf = new JobConf(WordCount.class);
          conf.setJobName("wordcount");

          conf.setOutputKeyClass(Text.class);
          conf.setOutputValueClass(EhcacheElementWritable.class);

          conf.setMapperClass(Map.class);
          conf.setCombinerClass(Reduce.class);
          conf.setReducerClass(Reduce.class);

          conf.setInputFormat(TextInputFormat.class);
          conf.setOutputFormatClass(EhcacheOutputFormat.class);   //

          FileInputFormat.setInputPaths(conf, new Path(args[0]));

          JobClient.runJob(conf);
        }

You also need to define the ehcache.xml configuration (following ehcache format).
Then in your application, you will be able to initialize it as a standard ehcache and get the data as soon as it is in memory.

6) More
There is other stuff under the hood.

A Toolkit library is available for clustered objects (like Collections, Locks, synchronization…).

The security functionality has been improved. As in version 3.7, SSL based communication is available in order to have a secure setup. Additionally, you can leverage an LDAP or Active Directory server to store credentials.

And also, Java 7 is  supported…

So if you’re interested in the big data world, you should definitely check it out here.

Don’t hesitate to leave comments if you need more precisions!



Published at DZone with permission of Aurelien Broszniowski, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)