Terracotta recrute

28 03 2013

J’en profite pour passer une petite annonce… Terracotta, la société derrière Ehcache, Quartz et BigMemory recrute.

Nous sommes partis d’une startup composée de geeks, et nous nous développons rapidement.

A savoir, Terracotta est une société basée à San Francisco et emploie déjà plusieurs français… Et oui, les développeurs français sont  très appréciés!!!

Le niveau technique général est très élevé, mais les gens sont très sympas (pas de techos qui, parcequ’il s’y connait, va mépriser les autres), si vous voulez rejoindre une société où vous travaillerez avec les APIs/outils à la pointe de la technologie, c’est le bon endroit.

Nous avons plusieurs figures très impliquées dans l’opensource parmi les employés : Greg Luck (Ehcache), James House (Quartz), Alex Snaps (Committer sur de nombreux projets tel Hibernate), Ludovic Orban (Bitronix Transaction Manager), Mathilde Lemée (Fluentlenium).

Notre philosophie c’est : Des développeurs passionnés, qui collaborent à travers le monde pour faire les meilleurs produits possibles.

Le job est en remote, donc travail à 100% de chez soi, et à savoir qu’il faut parler anglais lors des réunions (pas besoin d’être shakespeare, mais être capable de se débrouiller un minimum) et être prêt à passer 2 semaines par an à San Francisco.

Le côté vraiment sympa est d’avoir la possibilité de travailler comme on veut : Mac ? Linux ? Intellij? Netbeans? la dernière API xxx? Tant qu’on atteint le but fixé, on a la liberté de ses outils. ‘Get the job done, whatever the way’.

Les problématiques se situent au niveau du caching, de la concurrence en Java et de la gestion mémoire, mais il n’est pas nécessaire d’être un crack dans ce domaine, il faut d’abord être passionné par les nouvelles technologies autour de Java et l’Opensource.

Si vous êtes interessé et voulez plus d’infos, contactez moi par mail:  aurelien [at] terracottatech.com

Aurélien





Pratiques de caching avançées

27 03 2013

Cet article résume les différents points que nous avons abordés (ou pas par manque de temps) lors du labs à la conférence Devoxx, avec Mathilde Lemee (@MathildeLemee).

1) Le mot ‘cache’ est tiré du Quebecquois, cache, qui dénomme originellement l’endroit ou on entrepose des réserves. Il vient du français ‘cache’ qui désignait l’endroit où on cachait ses réserves (comme un grenier ou une cave) pour les coup durs.

Bref, le cache c’est la zone mémoire dans laquelle on stocke des données. Et en particulier un ‘hotset’ de données, c’est à dire le sous-ensemble de données qui est utilisé le plus souvent. Ce sous-ensemble est généralement beaucoup lu et peu écrit/mis à jour (10% écriture et 90% de lecture).

La raison primordiale d’utiliser un cache est la vitesse. On utilise un cache lorsque l’on veut augmenter les performances de son application.

L’avantage du cache est sa proximité. Par rapport à la source de donnée, le cache se situe souvent plus proche de l’application. Ehcache en l’occurence est un cache applicatif, qui, parcequ’il se situe au sein de l’application Java, et donc dans la même JVM, permet d’accéder aux données de manière extrêmement rapide.

Deux termes sont importants dans la notion de cache: ‘Hit’ et ‘Miss’. Lorsque l’application va chercher la donnée dans le cache et la trouve, c’est un ‘Hit’, lorsqu’elle ne la trouve pas, c’est un ‘Miss’, et il faudra aller chercher la donnée dans la base de donnée.

Le cache est donc la zone de mémoire qui contient les données les plus utilisées par l’application. Il y à ainsi des problématiques de concurrence : Plusieurs opérations peuvent s’effectuer sur la même donnée simultanément. C’est au cache de gérer les problèmes de concurrences, mais ça peut aussi être au développeur, notamment avec l’utilisation de locks.

On peut encore augmenter les performances pour certains cas d’utilisations, avec les caches distribués entre différentes instances d’une application. Chaque instance aura accès aux mêmes données grâce au cache clusteré (clustered cache).

EXERCICE 1 : Cache Aside

On a introduit ici le concept de cache aside. L’algorithme est simple: on va chercher la données, dans le cache et si elle n’y est pas, on va la chercher dans la base de données et en passant on la met dans le cache.

Ainsi la prochaine fois, elle sera disponible dans le cache.

A ne pas oublier qu’un cache a un algorithme d’éviction pour éliminer les données qui ne sont pas utilisées donc on peut y mettre les données et le cache se chargera d’y enlever les données superflues.

EXERCICE 2 : Read through

Ici la pattern introduite est d’utiliser le cache as a System Of Record. C’est à dire qu’on prend la logique pour aller chercher les données dans la base de données (Master System of Record), et on déplace cette logique dans une classe implémentant l’interface CacheEntryFactory, puis on englobe l’instance du Cache dans une instance de type SelfPopulatingCache.

Le code métier peut ainsi appeler cette nouvelle instance avec les méthodes habituelles du cache (get(), put(), remove()). Si la donnée est dans le cache, elle sera renvoyée, mais si elle n’y est pas, le cache ira charger automatiquement la donnée.

EXERCICE 3 : Write through

La pattern de l’exercice 2 permet aux couches métier de l’application d’avoir le cache comme system of record et de lui déléguer la lecture vers la base de données. Pour gérer l’écriture, on va passer par la pattern Write Through.

Pour cela, on implémente l’interface CacheWriter, et on configure le cache pour utiliser ce CacheWriter lors des opérations d’écritures. Dans l’exercice précédent on avait déplacé la logique de lecture, ici nous déplaçcons la logique d’écriture dans le cachewriter.

EXERCICE 4 : Write behind

La pattern write behind est similaire à la pattern write-through : L’application insére des données dans le cache, et le cache écrit dans la base de données. Il existe des cas où pour des raisons de performances, on veut que l’écriture vers la base de données se fasse de manière asynchrone. En effet le cache est beaucoup plus rapide que la base de données, et si il n’est pas primordial d’avoir une cohérence parfaite entre données dans la base et dans le cache, on peut utiliser cette pattern.

On peut ainsi même faire du coalescing, c’est à dire laisser la cache regrouper les opérations de manières intelligente, par exemple la séquence:

cache.put(“key1″, myObject1);

myObject1.setSomething(“something different”);
cache.put(“key1″, myObject1);

insére l’objet 2 fois dans le cache, et seule la dernière valeur est intéressante puisque c’est celle mise a jour, le cache va donc regrouper ces 2 opération en une seule et ne faire qu’une seule insertion dans la base de données, avec la dernière valeur.

EXERCICE 5/6 : Refresh Ahead

Cette pattern continue sur le principe du cache as System Of Record, on va déléguer le chargement depuis la base de données vers le cache via une classe implémentant  l’interface  net.sf.ehcache.loader.CacheLoader

La particularité ici est de définir un interval de temps au delà duquel le cache va lui même charger la donnée, avant même qu’une requête en cache n’est été faite.

Cette pattern est très utile pour parer au problème du ‘Thundering herd’. Ceci apparait lorsque un grand nombre de lecture sont faite dans le cache, simultanément pour la même donnée, pour la première fois, et que puisque la donnée n’est pas encore présente, un grand nombre d’appels simultanés vers la base de données s’exécute, et ralentit l’ensemble du système puisque la base de données doit faire face à un grand nombre d’appels concurrent, et que l’application doit attendre que la base de données réagsse afin de récupérer la donnée.

En définissant le chargement proactivement, on évite ce problème.

Cette pattern est aussi utile dans le cas où on veut éviter d’avoir des données dormantes dans le cache, et qu’on veut un rafraichissement régulier (ScheduleRefresh dans l’exercice 6).

EXERCICE 7 : Search

Le cache est un <Key, Value> Store, pour accéder aux données, on doit utiliser la clef.

Cependant, il existe des fonctionnalités avançées, comme la recherche. Vous pouvez créer des requêtes en java en utilisant un langage dédié (DSL), pour faire des recherches à la manière des requêtes SQL.

Puisque la fonctionnalité Search n’est pas nécessaire pour tout le monde, et afin d’optimiser, par défaut un cache n’est pas Searchable, il faut donc le configurer afin qu’il le soit.

Ensuite il faudra créer la requête pour récupérer les resultats, par exemple,
Query query = cache.createQuery().addCriteria(new EqualTo(“name”, name)).includeValues().includeKeys();
final Results results = query.execute();

final List<Result> all = results.all();
List<Wine> wineList = new ArrayList<Wine>();
for (Result result : all) {
wineList.add((Wine)result.getValue());
}

A noter qu’on peut faire de nombreuses différentes types de Requêtes, à voir la documentation officielle pour approfondir:

http://ehcache.org/documentation/apis/search

EXERCICE 8 : Fast Restartable Store

Les données du cache sont en mémoire, mais il est possible d’activer la persistence (sur le disque) pour qu’en cas de redémarrage, ou de crash de l’application, on puisse la redémarrer et récuperer le cache avec les mêmes données avant le redémarrage.

A ce niveau, le cache se rapproche d’un rôle de In Memory Data Store: On peut y stocker des données, redémarrer le cache en gardant ces mêmes données, et y faire des requêtes.

EXERCICE 9 : Automatic Resource Control

Parmi toutes les solutions de caches existantes, il existe deux manières de configurer la taille d’un cache:

- Par unité (count or unit based) : On définit le nombre d’élements qu’un cache peut contenir.

C’est une manière simple qui peut être utile dans certains cas. Par exemple si on veut mettre en cache la liste des 196 pays dans le monde, on peut configurer un cache ‘Pays’ pour contenir 196 élements.

Cependant, il y a une limitation: On ne sait pas combien de mémoire le cache va prendre, et ceci pourrait entrainer des ralentissements si on commence à utiliser trop de mémoire. C’est le point faible de la JVM, en utilisant trop de mémoire, le Garbage Collector peut créer de longues pauses, et bloquer totalement l’application.

- Par espace mémoire : On définit la taille en mémoire que le cache va allouer.

Par rapport à la configuration par unité, ici on sait combien de place le cache va prendre.

Le seul souci de cette configuration est que dans l’exemple précédent sur les pays, on ne peut pas être certain que tous les élements vont entrer dans la taille du cache. Aussi, on risque d’allouer trop de mémoire au cache, et de la gaspiller.

- La solution Ehcache : Allocation automatique

Comme expliqué dans mon article

http://jsoftbiz.wordpress.com/2011/08/01/ehcache-2-5-goes-beta-explanation-included/

Il est possible d’allouer un espace mémoire global à un ensemble de caches, et laisser Ehcache gérer la taille des caches suivant leur utilisation. Ceci est un bon moyen d’avoir les avantages des deux configurations précédentes… On est toujours sûr d’avoir les caches fortement sollicités utilisant un maximum de mémoire.

EXERCICE 10 : BigMemory

La mémoire Heap de la JVM est celle utilisée pour stocker les objets. Lorsqu’une application utilise plus que  quelques GO de heap, le Garbage collector ralentit celle-ci.

Pour parer à cette limitation, BigMemory utilise la mémoire qui n’est pas la heap, celle-ci est nommé off-heap (=hors heap). Comme indiqué dans cette étude, il est possible d’avoir un cache de 200Mo à 1,8To sans perte de performance

http://terracotta.org/resources/whitepapers/bigmemory-performance-results

EXERCICE 11/12 : Clustering

Augementer la taille du cache, tout comme augmenter la taille d’une application dépend des ressources de la machine. Rajouter de la mémoire, des processeurs ou de l’espace disque pour la rendre plus puissante es tle principe de scalabilité verticale : On fait ‘grandir’ la machine pour avoir une application plus ‘grosse’.

Cependant, il y a une limite du hardware, et il est nécessaire à partir d’une certaine taille de rajouter des machines dans une topologie cluster, c’est ce qu’on appelle la scalabilité horizontale : Plusieurs instances d’une même application tournent sur plusieurs machines.

Configurer un cache en mode clusteré permet de partager ce cache parmi les différentes instances de l’application.

La clustering avec Ehcache se fait en conjonction avec le serveur Terracotta. L’architecture est du type client-serveur : Chaque instance de l’application contient le cache qui est un client et se connecte sur le serveur Terracotta. Ce dernier gère la réplication des données entres les multiples instances du même cache.

Rajouter des serveurs Terracotta permet de scaler de manière horizontale grâce au support d’un nombre important de clients (généralement 1 par JVMs)

EXERCICE 13 : HA (Haute disponibilité)

EXERCICE 14 : Cache partitionné

EXERCICE 15 : Replication WAN





Hibernate 4 and Ehcache higher than 2.4.3

14 03 2013

For those using Hibernate 4, if you want to use Ehcache, you must add a specific dependency: hibernate-ehcache

But there’s a catch, it embeds Ehcache 2.4.3, which is unconvenient as the latest version of Ehcache is 2.7.0

So if you are looking to use Hibernate 4, you should exclude the embeded Ehcache dependency.

In your pom.xml, it will look like this:

<dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-core</artifactId>
 <version>4.1.9.Final</version>
</dependency>

<dependency>
 <groupId>org.hibernate</groupId>
 <artifactId>hibernate-ehcache</artifactId>
 <version>4.1.9.Final</version>
 <exclusions>
 <exclusion>
  <groupId>net.sf.ehcache</groupId>
  <artifactId>ehcache-core</artifactId>
 </exclusion>
</exclusions>

</dependency>

Then according to the version of ehcache, you will need either ehcache or ehcache-core

Up to 2.6.x:

<dependency>
 <groupId>net.sf.ehcache</groupId>
 <artifactId>ehcache-core</artifactId>
 <version>2.5.7</version>
</dependency>

Starting at 2.7.0:

<dependency>
 <groupId>net.sf.ehcache</groupId>
 <artifactId>ehcache</artifactId>
 <version>2.7.0</version>
</dependency>

Changes in your code:

Please note that Ehcache contains classes to support Hibernate 3, but  hibernate-ehcache contains classes for Hibernate 4

Meaning that in your classpath, you’ll end up with two packages:

For Hibernate 3, classes are in the package : net.sf.ehcache.hibernate.*

But for Hibernate 4, classes are in the package : org.hibernate.cache.ehcache.*

So your hibernate configuration will need these properties to be set up:

<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>

Please note that it is: org.hibernate.cache.ehcache.EhCacheRegionFactory while for Hibernate 3, it was net.sf.ehcache.hibernate.EhCacheRegionFactory

So be really careful in your code, you could have

import net.sf.ehcache.hibernate.*;

which will compile but then fail at run time since this is for Hibernate 4. Whatever hibernate class you’re using, you should have:

import org.hibernate.cache.*;

The exception is for the property net.sf.ehcache.configurationResourceName that will contain the path to your ehcache xml config file, just like in Hibernate 3

Similarly, just like for Hibernate 3, you will need:

<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">false</property>

Eventually it would make sense that the Hibernate folks have a <provided> scope dependency on ehcache instead of embedding it in their hibernate-ehcache dependency, that would make things easier.





BigMemory 4.0 technical overview

9 03 2013

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.

A powerful new Statistics API.

Refresh ahead and schedule refresh features to load the data in memory before they are needed rather than when they are needed, thus increasing the speed.

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!





Confused about Map/Reduce?

21 11 2012

I was working on some Hadoop stuff recently, and as a total beginner, I found that the Map/Reduce concept was not easy to understand, despite the huge number of tutorials.
The Wordcount example is the ‘Hello World’ of Hadoop, but when I prepared a small presentation for my team, I realized it was not clear enough to explain Map/Reduce in 5 minutes.

As you may already know, the Map/Reduce pattern is a pattern that is very good for embarrassingly parallel algorithms.

Okayyyy but… What is an embarrassingly parallel algorithm?
Answer: It is an algorithm that is very well fit to be executed multiple times in parallel.

Ok then… what is very well suited for a parallel execution?
Answer: Any algorithm that’s working on data that can be isolated.

When writing an application, if you execute multiple occurrences of it at the same time, and they need to access some common data, there will be some clash, and you will have to handles cases like when one occurrence is changing some data while another other is reading it. You’re doing concurrency.
But if your occurrence is working on some data that no other occurrence will need, then you’re doing parallelism. Obviously you can scale further, since you do not have concurrency issues.

So let’s take an example, let’s say you have a list of cities, and each one has two attributes : the state it belongs to, and its yearly average temperature. E.g. : San Francisco : {CA, 58}
Now you want to calculate the yearly average temperature BY STATE.
Since you can group cities by state, and calculate the average temperature of a state without caring about cities of other states, you have a great embarrassingly parallel algorithm candidate.

If you wanted to do it sequentially, you would start with an empty list of yearly state average temperatures. Then you would iterate through the list of cities, and for each city, look at the state, then update the relevant yearly state average temperature.

Fortunately, it’s very easy to do it in parallel instead.

Let’s have a look at this map:

This is a map of India. There are several states : MP, CG, OR… And several cities, each one having {State, City average temperature} as value.

We want here to calculate the yearly average per state. In order to do that, we should group the city average temperatures by state, then calculate the average of each group.

We don’t really care about the city names, so we will discard those and keep only the state names and cities Temperatures.

Now we have only the data we need, and we can regroup the temperatures values by state. We’re going to get a list of temperatures averages for each state.

At this point, we have the data in good shape to actually do the maths… All we have to do is to calculate the average temperature for each state

That wasn’t hard.

We had some input data. We did a little regrouping, then we did the calculation. And all this could be executed in parallel (One parallel task for each state).

Well… That was Map/Reduce!

Let’s do it again

Map/Reduce has 3 stages : Map/Shuffle/Reduce

The Shuffle part is done automatically by Hadoop, you just need to implement the Map and Reduce parts.

You get input data as <Key,Value>  for the Map part.

In this example, the Key is the City name, and the Value is the set of  attributes : State and City yearly average temperature.

Since you want to regroup your temperatures by state, you’re going to get rid of the city name, and the State will become the Key, while the Temperature will become the Value.

Now, the shuffle task will run on the output of the Map task. It is going to group all the values by Key, and you’ll get a List<Value>

And this is what the Reduce task will get as input : the Key, List<Value> from the Shuffle task.

The Reduce task is the one that does the logic on the data, in our case this is the calculation of the State yearly average temperature.

And that’s what we will get as final output

This is how the data is shaped across Map/Reduce:

Mapper <K1, V1> —> <K2, V2>
Reducer <K2, List<V2>> —><K3, V3>

I hope this helped makes things a bit clearer about Map/Reduce, if you’re interested in explanations about Map Reduce v2/YARN, just leave a comment and I’ll post another entry.

PS: You can find the java code for this example here:

https://github.com/jsoftbiz/mapreduce_1





Configure a nonstop cache programmatically in Ehcache

22 07 2012

Here’s how to configure programmatically a nonstop cache in Ehcache (this one is clustered, connecting to terracotta running on localhost):

import net.sf.ehcache.config.*;

Configuration configuration = new Configuration()
   .terracotta(new TerracottaClientConfiguration().url("localhost:9510"))
   .defaultCache(new CacheConfiguration("defaultCache", 10000))
   .cache(
      new CacheConfiguration("nonstopCache", 10000)
      .terracotta(new TerracottaConfiguration().consistency(TerracottaConfiguration.Consistency.STRONG)
      .nonstop(new NonstopConfiguration().enabled(true).timeoutMillis(4000)
      .timeoutBehavior(new TimeoutBehaviorConfiguration()
      .type(TimeoutBehaviorConfiguration.TimeoutBehaviorType.LOCAL_READS.getTypeName())))
   )
);
CacheManager cacheManager = new CacheManager(configuration);




Install wget on MacOs

3 06 2012

You need to have gcc installed, see my previous post
then

ftp ftp://ftp.gnu.org/gnu/wget/wget-1.13.tar.gz
tar -xvzf wget-1.13.tar.gz && cd wget-1.13
./configure --with-ssl=openssl --prefix=/usr --sysconfdir=/etc --mandir=/usr/share/man --disable-nls --disable-rpath --with-gnu-ld
make
sudo make install







Follow

Get every new post delivered to your Inbox.