Formation BigData – Hadoop – module Développeur

Bonjour,

Le BigData n’est plus réservé aux géants du Web, c’est maintenant l’affaire de tous.
On estime que 80% des données d’une entreprise sont non-structurées et inexploitées… et le volume augmente de plus en plus rapidement. De plus, les infrastructures modernes nous permettent de conserver de plus en plus de données à moindre coût : rien n’est à jeter, tout peut être utile.

FastConnect a le plaisir de vous présenter sa nouvelle formation BigData Hadoop orientée Développeurs.
Ce module de 3 jours, alternant cours théoriques et pratiques, vous offre une introduction sur les enjeux du BigData, ainsi qu’une mise en pratique avec la technologie Hadoop. (télécharger le programme de la formation)

L’objectif de cette formation est de démystifier Hadoop, savoir utiliser les outils principaux autour de son écosystème et traiter les données de diverses manières, dont le Machine Learning, afin de présenter les résultats de manière graphique.
Une prise en charge par votre OPCA est possible (numéro d’agrément 11921636592).

La prochaine session aura lieu du 17 au 19 septembre dans notre centre de formation d’Issy les Moulineaux, au prix réduit de 1 700€ HT par participant au lieu de 1 900€.

Les places sont limitées, si cette formation vous intéresse, n’hésitez pas à nous contacter.

Cordialement,

L’équipe FastConnect Training
+33 (0)1 45 07 81 65
training@fastconnect.fr

Paris JUG Juillet 2012 – Couchbase

Mardi 3 Juillet s’est déroulé le Paris JUG. Cette session était orientée 100% NoSQL.

La première partie fut animée par Raghavan « Rags » N. Srinivas sur une présentation de Couchbase.


Attention : on parle bien de Couchbase, pas de CouchDB !
Je reviendrai sur la différence entre les deux dans quelques lignes…

Avant de parler de Couchbase, Rags nous explique l’intérêt du NoSQL, comme la scalabilité horizontale et donc un coût maitrisé.
Si vous n’êtes pas encore convaincu, je vous suggère de voir leur document « Why NoSQL ? » sur le site de Couchbase : http://www.couchbase.com/why-nosql/nosql-database

Qu’est-ce que Couchbase ?

Maintenant se pose la grande question : qu’est-ce que Couchbase ?
La réponse courte : C’est une base NoSQL, orienté « clé/valeur » mais avec des fonctionnalités orientées « document ».

Avant Couchbase, il y avait Membase : un Memcached survitaminé, avec réplication des caches, persistances, une interface d’admin Web bien sympa, etc.
Membase n’existe plus, Couchbase le remplace et l’intègre.

On peut donc utiliser Couchbase comme un cache mémoire pure, en mode clé/valeur, avec l’API cliente de Memcached.

Mais alors, quel est le rapport entre Couchbase et CouchDB ?
Couchbase intègre CouchDB !
Pour prendre un exemple simple : quand vous sauvegardez un document JSON, ce dernier va être envoyé dans le cache Memcached, puis persisté sur disque avec le moteur de CouchDB (de manière asynchrone).

On peut comparer le processus avec celui de MongoDB, à la différence que MongoDB ne possède pas son module de Caching, mais délègue cette gestion à l’OS à l’aide de « Memory-mapped files », qui va flusher sur disque de temps en temps.

Pour mieux illustrer mes propos, voici l’écran de monitoring lorsque je fais une écriture massive :

On remarque un pique de « ops per second » : ce sont mes écritures massives
Mais la donnée se trouve seulement en mémoire, pas encore sur le disque !
On voit alors que le « disk write queue » augmente d’un coup : c’est la file d’attente avant persistance sur disque.
Quelques secondes plus tard, on voit que cette dernière diminue petit à petit.
En même temps, on voit que la base augmente sur le disque dans « couch disk/data size ».
Et toujours en même temps, on voit des « creates per sec » pendant cette phase de persistance.

Pour comprendre comment fonctionne Couchbase, et comment il intègre CouchDB, vous pouvez lire ceci : http://www.couchbase.com/couchdb

Comment lire/écrite dans Couchbase (en Java) ?

Couchbase est donc très orienté performance, puisqu’on va exploiter au mieux la mémoire.
De plus, les opérations de l’API sont de type « fire and forget » : quand on demande de sauvegarder un document, l’API nous rend la main tout de suite sans savoir si la sauvegarde a bien fonctionné !
Pour cela, il va y avoir un mécanisme semblable aux « Future » en Java, ou au « Write Concern » en MongoDB ou Cassandra.
L’API va donc nous renvoyer un objet « OperationFuture », sur lequel on va pouvoir, plus tard, demander d’attendre la fin de la sauvegarde.
Voici un exemple de code, plus parlant je l’espère :)

CouchbaseConnectionFactory factory = new CouchbaseConnectionFactory(
  Arrays.asList(URI.create("http://localhost:8091/pools")),
  "default",
  "");
client = new CouchbaseClient(factory);

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();

// on stocke ici les futures des opérations d'insertion
List<OperationFuture<Boolean>> futures = new ArrayList<OperationFuture<Boolean>>();

for (int cpt = 0; cpt < 80000; cpt++) {

 // création d'un document
 People people = new People();
 people.setFirstname("Mathias");
 people.setLastname("Kluba");

 // j'utilise ici GSON pour construire mon JSON à partir de mon POJO
 String json = gson.toJson(people);

 // on va générer un ID pour chaque item
 UUID uuid = UUID.randomUUID();

 // sauvegarde de l'objet
 OperationFuture<Boolean> setResult = client.set(
 uuid.toString(),
 0,
 json);

 // on conserve le future pour plus tard...
 futures.add(setResult);
}

// maintenant qu'on a balancé les sauvegarde sur le server,
// on attend la fin de chacune d'entre elles,
// et on vérifie que la sauvegarde a réussie
for (OperationFuture<Boolean> f : futures) {
 Assertions.assertThat(f.get()).isTrue();
}

Ce qui est sympa, c’est que même la lecture peut être asynchrone : on balance plein de requête au serveur, et on demande ensuite le résultat en asynchrone à l’aide du Future.

Comme tout fonctionne en mode asynchrone, cela peut poser des problèmes lors de l’écriture : comment gérer les écritures concurrentes ?
En base relationnelle, on va vouloir faire une transaction, pour être sûr que personne ne modifie la même donnée.
Mais Couchbase ne supporte pas les transactions !
Ceci dit, il y a moyen de gérer la concurrence de manière « Optimiste » : on va admettre que tout va bien dans la plupart des cas, et s’il y a un problème de concurrence, alors on va gérer l’erreur au niveau de l’application.

Pour ça, il y a le mécanisme de CAS (Check and Set).
Le CAS va se servir d’une sorte de Checksum qui va nous permettre de vérifier si quelqu’un n’a pas modifié le même objet entre temps.
Ex :

  • Je récupère un objet avec son CAS
  • Je le modifie en mémoire
  • Quelqu’un d’autre le récupère aussi, le modifie et le sauvegarde en base
  • Lorsque je le sauvegarde, je précise la valeur du CAS que j’ai obtenu
    • ERROR : la valeur du CAS fournie n’est pas le même en base : quelqu’un a modifié le même objet entre temps : la sauvegarde échoue

Comme Linus Torvalds disait : TALK IS CHEAP. SHOW ME THE CODE !

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();

// création d'un document
People people = new People();
people.setFirstname("Mathias");
people.setLastname("Kluba");

// j'utilise ici GSON pour construire mon JSON à partir de mon POJO
String json = gson.toJson(people);

// on va générer un ID pour chaque item
UUID uuid = UUID.randomUUID();

// sauvegarde de l'objet
OperationFuture<Boolean> future = client.set(
 uuid.toString(),
 0,
 json);

Assertions.assertThat(future.get()).isTrue();
System.out.println(future.getStatus());

// obtient l'objet avec son CAS
CASValue<Object> withCas = client.gets(uuid.toString());

people = gson.fromJson((String)withCas.getValue(), People.class);
people.setFirstname("Roi Mathias 1er");

json = gson.toJson(people);

// tente de mettre à jour l'objet avec son CAS
CASResponse response = client.cas(uuid.toString(), withCas.getCas(), people);

Assertions.assertThat(response).isEqualTo(CASResponse.OK);

// tente de mettre à jour une seconde fois:
// mais qui ne va pas marché car on n'a pas le bon CAS

response = client.cas(uuid.toString(), withCas.getCas(), people);

Assertions.assertThat(response).isEqualTo(CASResponse.EXISTS);

Un autre truc sympa, hérité de Memcached, c’est la notion de TTL (Time To Live).
Si je reprends le code de la sauvegarde, on remarque un 2 ème argument de type Integer :


// sauvegarde de l'objet
OperationFuture<Boolean> setResult = client.set(
 uuid.toString(),
 0,
 json);

C’est en fait le TTL en seconde : je peux ainsi dire « sauvegarde moi cette donnée, mais elle expire dans 60sec ».
Ici, cas particulier, je ne veux pas d’expiration, la valeur du TTL est donc 0.

Bon, faire un « set/get » en mode clé/valeur, c’est bien mais parfois ça peut être limitant…
Et si je veux maintenant requêter sur le « lastname » ?

C’est là que l’approche « orienté document » de Couchbase est intéressante :
Ils prennent pour postula que la majorité de vos requêtes seront de type « clé/valeur ».
Tout d’abord, quand vous sauvegardez une valeur au format JSON, cette valeur sera traitée de manière très spéciale par Couchbase.
Mais par défaut, on ne peut donc pas requêter sur les champs de votre JSON. Pour ce faire, il faut créer une sorte d’index sur les champs que vous avez besoin de requêter.

Je dis bien « une sorte d’index », car en Couchbase on appelle ça une « Vue » (comme les Vue SQL), mais le plus fun c’est qu’on code cette vue avec une fonction de Map-Reduce (ou Map seulement) ;)

En résumé : les Vues sont des « Map-Reduce » à la demande.

Quand on interroge une vue, on peut demander le résultat déjà calculé au préalable, ou re-indexer la base en re-exécutant la fonction de Map-Reduce.
Voici ce qui se passe si j’interroge une vue en forçant la re-indexation :

Voici un exemple de Vue et son utilisation en Java :


Query query = new Query();

query.setReduce(false);
query.setIncludeDocs(false);
query.setStale(Stale.FALSE);

View view = client.getView("people", "bylastname");

Paginator paginator = client.paginatedQuery(view, query, 500);

while (paginator.hasNext()) {
 ViewRow row = paginator.next();
 System.out.println(
  "ID: " + row.getId() +
  " Key: " + row.getKey()  +
  " Value: " + row.getValue());
}

Et voilà à quoi ça ressemble coté Couchbase :

Petit détail : si vous forcer la re-indexation, ça ne s’applique bien sûr qu’aux nouvelles données ou aux données changées… donc si vous avez déjà 80000 items, que le Map-Reduce est terminé, et que vous ajoutez 80 items, le Map-Reduce sera plus rapide :)

Pour conclure sur les aspects requêtages, Couchbase, offre une API Memcached (pour de la haute performance) mais offre aussi une API REST, beaucoup plus « Web friendly ».
Les applications Web peuvent alors récupérer le JSON avec une URL REST qui ressemble à cela :
http://localhost:8091/couchBase/default/00006e0b-4b58-465d-b045-e2a485baaa51

Pour obtenir le résultat d’une vue, cela ressemble à cela :
http://localhost:8091/couchBase/default/_design/dev_people/_view/bylastname?limit=10&skip=0

La présentation de Couchbase s’arrête à peu près là. On voit alors que Couchbase est orienté Web, Performance, Scalabilité Horizontale, et que son installation et utilisation est très simple.

Couchbase et Cluster

Mais je souhaite aller plus loin,  j’ai voulu savoir comment fonctionne les aspects « scalabilité horizontale » de Couchbase.
Premièrement : tout comme Cassandra, chaque nœud Couchbase fonctionnent de la même manière, aucun n’est spécialisé.

Couchbase utilise Memcached, donc exploite le même mécanisme de répartition de charge grâce au « Consistent Hashing » : les données sont uniformément réparties sur tous les nœuds disponibles.
Et si j’ajoute un nœud ?
Et bien il n’est pas exploité tout de suite : il est en attente de Re-Balancing.
Cette opération vous permet donc de re-balancer les données sur plusieurs nœuds à la fois, si vous en ajoutez plusieurs :

Attention : c’est une opération bloquante et elle peut prendre du temps, ce qui rend donc votre serveur indisponible. Il faut alors choisir le moment de son exécution judicieusement…. mais au moins, ce n’est pas automatique, et ça ne va pas planter votre prod lors d’une forte charge !

Le même mécanisme fonctionne quand on supprime un nœud :

Tout ça, c’est pour répartir la charge, et donc :

  • Exploiter le disque + mémoire de plusieurs machines pour accélérer les requêtes de lecture/écriture
  • Exploiter le CPU de plusieurs machines pour accélérer le Map-Reduce des Vues

Mais qu’en est-il de la résilience ?
Elle est assuré grâce à la réplication, et on configure ça au niveau d’un « Bucket ».

Un « Bucket » c’est l’équivalent d’une base en SQL.
Il n’y a pas de notion de « table » (ou « collection » comme en Mongo), si vous voulez séparer des données alors il faut créer un autre Bucket.
Ce dernier possède un quota en mémoire, et un nombre de réplica.
Si le nombre de réplica est 1, alors la donnée sera écrite sur 2 nœuds.

Conclusion

En conclusion, j’ai été agréablement surpris.
Premièrement, j’ai confondu Couchbase et CouchDB : Couchbase c’est un mixe des meilleurs choses de Memcached et CouchDB, c’est donc pas mal :)
L’approche « Vue avec Map-Reduce » est intéressante : on ne ralentit pas les écritures pour mettre à jour un index, ou construire un « b-tree », alors que finalement on va requêter sur seulement quelques champs du document…
Il y a donc de très bonnes idées, même si, à mon avis, il reste des choses à améliorer.
Couchbase est donc différent des autres solutions NoSQL, avec ses avantages et ses inconvénients.
Vous avez donc une base de données qui vient étoffer votre panel de solutions NoSQL, ce qui vous donne encore plus de choix, mais ce qui rend la tâche encore plus complexe :)

MongoDB Day Paris 2012 – 8 – MongoDB 2.2

La journée s’est conclue par un aperçu des principales fonctionnalités apportées par la version 2.2 de Mongo qui sortira dans le courant de l’été 2012.

  • Nouveau framework d’agrégation de donnée, en complément du map-reduce existant.
  • TTL collections permettant d’avoir des objets effacés automatiquement après un temps donné.
  • Meilleure concurrence, le lock se faisant maintenant au niveau d’une base de donnée au lieu de se faire sur tout un processus mongod
  • Data aware sharding permettant d’ajouter un niveau d’affinité aux données pour aider mongo à placer les chunks sur les différents shards. Particulièrement utile en environnement multi-datacenter pour faire en sorte que les données d’une région restent sur celle-ci.
  • Amélioration des optimisations de requêtes

Le détail des changements peut être trouvé ici

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012:

MongoDB Day Paris 2012 – 7 – Déploiement et Monitoring – Mathias Kluba, Fastconnect

Suite à notre partenariat avec 10gen, et notre engouement autour de MongoDB, nous avons décidé de parler de déploiement et supervision lors du passage en Prod d’un cluster MongoDB.

Cette session a été présentée par notre consultant Mathias Kluba, ainsi que Loic Dachary de eNovance, société spécialisée dans les services Cloud et l’infogérance.
eNovance, de par leur infrastructure Cloud OpenStack, ont une grande expérience autour du déploiement et du monitoring, et la demande de déploiement de cluster MongoDB augmente de jours en jours…
eNovance sont aussi très actif atour de la technologie de déploiement Puppet, et contribuent avec Puppet Labs sur le sujet.
Ça a donc été un grand honneur de pouvoir co-animer cette session avec Loic.

Cette présentation est constituée de 2 axes: le déploiement et le monitoring.

Déploiement

Le déploiement peut s’avérer complexe quand on souhaite déployer un cluster MongoDB avec ReplicatSet et Sharding…
Mais de nombreux outils supportent MongoDB grâce une communauté très active.

Voici des outils OpenSources qui peuvent vous aider à cela:

Lors de cette session, nous avons montré une démo de déploiement MongoDB sur Amazon EC2 avec Cloudify.
Là où Chef et Puppet vont déployer le nécessaire sur une machine en fonction de son rôle, Cloudify s’oriente sur le déploiement d’une application, avec tous les middlewares nécessaires, et s’assure aussi de créer les machines virtuelles si besoin.
Cette démo montre alors le déploiement d’un cluster en mode Sharding à l’aide des Recipes de Cloudify (script Groovy).
A noter que Cloudify peut déléguer le déploiement à Chef ou Puppet, et ainsi re-utiliser vos Recipes existantes.

Lors de cette démo on voit aussi la possibilité de définir des « Custom Commands » dans Cloudify, ce qui nous a permis d’exécuter un « mongodump » sur tous les nœuds du cluster à l’aide d’une seul commande (dump ensuite déposé sur Amazon S3).
Vous pouvez alors automatiser de nombreuses tâches de support par ce biais.

Monitoring

La seconde partie de la session s’oriente sur le monitoring d’un cluster MongoDB.
Si MongoDB vient avec quelques outils de monitoring, ces derniers ne seront pas suffisant en condition réel de production.

Si vous n’avez pas une infrastructure de monitoring déjà existante, et que vous ne voulez pas payer le coût d’installation/maintenance, vous avez la possibilité d’utiliser des services de Monitoring (Monitoring as a service) comme:

  • MMS: le service de monitoring de 10gen, spécialisé MongoDB, complétement gratuit et pouvant aider le support 10gen à diagnostiquer vos problèmes
  • Server Density: un service de monitoring générique mais avec une très bonne intégration MongoDB out-of-the-box.

Par contre, si vous voulez intégrer le monitoring de MongoDB à vos outils de monitoring existants, tout comme pour le déploiement, de nombreux outils OpenSources supportent MongoDB grâce à la communauté: Munin, Nagios, Cacti, etc.

Mais ces outils ont généralement une vision « machine »: vous sélectionner votre serveur, et vous avez les statistiques du nœud qui y est installé.
Cloudify gère aussi le monitoring mais du point de vue d’une application: on a l’état de santé de l’application en agrégeant les informations des différents middlewares, ou des différents nœuds du cluster MongoDB.
La session s’achève alors avec une démo de la partie monitoring de Cloudify, avec un cluster MongoDB en Sharding soumis à une charge simulée par une application JMeter.

En conclusion, on remarque que les efforts des communautés OpenSources rend possible l’automatisation des déploiements et le monitoring de MongoDB.
Mais vous pouvez aussi être acteurs dans ces communautés, il en revient donc à vous la responsabilité d’adopter ces outils, remonter les bugs existants, ou les faire évoluer, plutôt que de re-inventer des scripts de votre coté…

Vous pouvez voir la démo de déploiement et monitoring de MongoDB sur Amazon EC2 avec Cloudify sur notre chaine Youtube:

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012:

MongoDB Day Paris 2012 – 6 – The New Aggregation Framework – Ross Lawley, 10gen

Ross Lawley a présenté pour la dernière conférence de la journée le nouveau framework d’agrégation de données qui va bientôt être disponible avec la prochaine version 2.2 de Mongo.

Le but annoncé de cette nouvelle fonctionnalité est d’apporter un outil complémentaire au map-reduce. La construction de nombre de tâches simples telle que faire une somme, une moyenne ou trouver un minimum/maximum a été grandement simplifié. De plus les performances sont bien meilleures puisque tout est écrit directement en C++ ce qui évite l’overhead de la transcription du javascript utilisé par map-reduce.

Le principe est de décrire une chaîne d’opérations à appliquer, voilà un petit aperçu de la syntaxe :

  • $math : requête, équivalent du find
  • $project : met en forme les résultats, notamment en enlevant/ajoutant des champs
  • $unwind : permet de faire du streaming de tableau, chaque élément du tableau sera traité comme un document
  • $group : agrège les données
  • $sort : fonctionnalités de trie
  • $limit : limite le nombre de documents renvoyés
  • $skip : exclue certains documents du résultat

La syntaxe donne une idée des possibilités du framework, Ross a montré un bon nombre d’exemples pendant la conférence pour illustrer cela. A noter que le sharding est supporté, dans ce cas c’est le mongos qui se charge d’invoquer la chaîne d’opérations.

N’hésitez pas à consulter la documentation officielle pour plus de détails et d’exemples.

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012:

MongoDB Day Paris 2012 – 5 – How and When to Scale MongoDB with Sharding – Daniel Roberts, 10gen

Comment et quand utiliser le sharding de MongoDB pour scaler horizontalement son application? Tel était le sujet de la conférence qui était principalement dédié aux nouveaux utilisateurs découvrant le sharding.

Comme on le sait le sharding sert à scaler horizontalement l’application, cependant si c’est le débit en lecture que l’on veux augmenter alors il peut être plus judicieux d’agrandir la taille du réplica set tout en autorisant la lecture sur les secondaires, à condition d’accepter des lectures éventuellement inconsistantes.

Pour pouvoir utiliser le sharding deux composants sont nécessaires en plus des mongod. Les mongos sont le point d’entrée de la base de donnée et servent de routeur, les mongoConfig possèdent les méta-données des collections, notamment quelle donnée se trouve sur quel shard. Les données d’une collection sont découpées en chunks, lorsqu’un chunk dépasse une certaine taille il est alors coupé en deux et l’un des chunks peut alors migrer vers un nouveau shard. La migration se fait par copie, lors de la migration les données sont toujours disponibles à la lecture et à l’écriture sur le shard initial, une fois la migration finie les mongoConfig sont reconfigurés.

Si l’on décide de «sharder» une collection alors il faut faire très attention au choix de la clé de sharding. En effet le partitionnement se fait par plage de données. Cela implique que si la clé est incrémentale alors les données insérées iront toutes vers le même shard qui stocke la plage la plus élevée. Si la clé est aléatoire alors tous les shards serons mis à contribution, cela veux dire aussi que l’ensemble des index de la collection doivent être gardé en ram. On peux aussi créer une clé semi-aléatoire, par exemple une combinaison du mois et d’une fonction aléatoire, ceci afin de ne mobiliser qu’une fraction des shards.

Un cas possible de mauvais design du modèle arrive lorsqu’un document a plusieurs identités, par exemple un utilisateur possédant une adresse mail, facebook, twitter… Si l’on choisit comme clé de sharding un de ces champs, l’adresse mail par exemple, alors les requêtes basées sur les autres identités ne connaîtront pas le routage de l’objet, elles seront donc obligées de broadcaster la requête sur l’ensemble des shards ce qui peut entraîner de piètres performances. Si plusieurs de ces champs sont utilisés comme identité lors des requêtes alors il vaut parfois mieux découper l’objet en plusieurs documents : un pour chaque identité (dénormalisation). Plusieurs requêtes sont alors nécessaires pour faire la jointure mais ces requêtes aurons l’avantage d’être routées.

Un dernier conseil est de penser le design du schéma en anticipant la possible futur utilisation du sharding. Mais de n’effectuer le sharding que lorsqu’on en a vraiment besoin, lorsqu’on arrive à court de ressources matérielles. À noter que la solution peut aussi être de se passer du sharding et de scaler verticalement en ajoutant de la ram ou du disque.

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012:

MongoDB Day Paris 2012 – 4 – Journaling and the storage engine – Dan Pasette, 10gen

Cette conférence mettait en avant le système de persistance sur disque de Mongo ainsi que la journalisation mise en place pour assurer la reprise sur panne rapide et la consistance des données. Le fonctionnement interne de ces mécanismes était aussi abordé.

Dan Pasette a expliqué le système de pré-allocation agressif de Mongo qui réserve toujours un fichier en avance pour le stockage de chaque base de donnée afin de limiter la fragmentation du fichier et d’être prêt lorsque le précédent est plein. Sachant que la taille de chaque nouveau fichier alloué est le double du précédent jusqu’à atteindre la limite de 2gb, cela implique que pour une petite base de donnée une part importante de sa taille sur le disque n’est pas réellement utilisé. L’overhead sur le disque est donc important ce qui perturbe parfois les nouveaux utilisateurs.

Un autre élément qui rend parfois les utilisateurs confus est le mapping de tous les objets Mongo dans un segment de mémoire virtuelle. Il est important de comprendre qu’un segment ne correspond par forcément à de la ram, une partie de ses pages peuvent être sur disque.

Autre élément souvent méconnu : un coefficient de padding compris entre 0 et 2 existe pour chaque collection. Pour chaque nouveau document créé Mongo alloue en plus de sa taille réelle une fraction supplémentaire. Ceci permet d’éviter de devoir déplacer l’objet plus tard s’il grossit lors de l’ajout de nouvelles données. Il faut noter que ce coefficient est calculé automatiquement par Mongo ; il n’est pas configurable.

Le journal écrit par défaut toutes les 100ms sur le disque (contre 60s pour le FSYNC des collections) ou tous les 100mb d’écriture. Mais aussi chaque fois que le « write concern » l’exige, le « write conccern » étant la contrainte de durabilité exigé par le client pour les écritures. À noter que le journal est un fichier circulaire de taille fixe mais paramétrable et qu’il est recommandé pour de meilleures performances de le placer sur un disque séparé.

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012:

MongoDB Day Paris 2012 – 3 – Hadoop et MongoDB – Pablo Lopez, Xebia

Comment analyser chaque jour des téraoctets de logs générés par plus de 600 JVMs en production, sans impacter leur fonctionnement ?

Cette conférence présentait une solution Big Data 100% Open Source mise en place chez l’un des plus grands sites du web européen avec une architecture basée sur syslog-ng, Flume, Hadoop, MongoDb et Play!

Près de 600 JVM, jusqu’à 13 niveau d’indirection par load balancing, 5 à 10 fichiers de log par jvm et 7go par serveur et par jour de logs générés. Voilà pour l’état des lieux.

Avant de mettre en place la solution présentée ci-dessous la procédure de récupération et analyse de logs était si lente et contraignante que les logs étaient pratiquement inutilisés, grâce à la nouvelle solution le temps a été divisé par 20. Les besoins de cette procédure étaient la centralisation des logs, leur sécurisation puis leur analyse, avec la capacité d’informer et d’archiver, tout cela en temps réel.

Après tâtonnement la solution adoptée utilise pour les logs applicatifs un syslog-ng local sur chaque serveur qui récupère les données de log4j (via udp pour ne pas attendre d’ack) et les transmets à un syslog-ng centralisé (via tcp). Les logs d’Apache sont récupérés par Flume. Tous ces logs sont ensuite stockés sur un hdfs (hadoop distributed file system), voilà pour la procédure de récupération et stockage.

L’analyse se fait ensuite de manière performante grâces aux possibilités de map-reduces offertes par hadoop, les résultats de ces analyses sont stockés dans une base Mongo distribuée sur 5 serveurs, avec réplica et sharding. Enfin Play récupère ces résultats à la demande dans Mongo et les affiche sous forme graphique.

Pourquoi avoir choisi MongoDB plutôt qu’un MySql ?

Avant tout pour la flexibilité dans le design du modèle qui permet de facilement rajouter de nouvelles fonctionnalités, mais aussi pour les possibilités de scalabilité horizontale offertes avec la réplication et le sharding ainsi que sa facilité de déploiement et de configuration. De plus Mongo est plus simple car le résultat au format JSON est renvoyé directement à des Widgets.

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012:

MongoDB Day Paris 2012 – 2 – Deployment Preparedness – Dan Pasette, 10gen

Quels sont les éléments d’un déploiement de mongoDB réussi ? Voila l’objet de cette conférence.
Beaucoup des conseils et recommandations cités lors de cette conférence sont valables pour bon nombre de projets, qu’ils utilisent Mongo ou non. Ils ont aussi été entendus un bon nombre de fois par l’ensemble d’entre nous, une piqûre de rappel est cependant toujours utile.

Tout le monde est d’accord sur l’importance de chacune de ces étapes mais dans la réalité très souvent une partie de ces phases sont négligées dans le développement des projets.

Prototype

Comme cela a été abordé donc la conférence précédente il faut faire bien attention au design du modèle, schéma libre ne signifie pas « liberté totale ».
De même il faut attacher une grande importance à la création des bons index et garder en tête qu’un seul index peut être utilisé pour une requête donnée. L’outil « explain » est très utile dans ce but, appelé après une requête db.<collection>.find(<query>).explain() il donne des statistiques sur cette requête comme le temps total, le nombre d’objets scannés et l’index utilisé…
Si l’on pense que l’on va utiliser le sharding dans le futur, designer ses schémas en conséquence.

Test

Plutôt que de passer beaucoup de temps en phase de prototypage à développer plein de fonctionnalités il vaut souvent mieux investir du temps dans tests car le temps opérationnel d’une application est la meilleure des fonctionnalités.

Il faut faire des tests de montée en charge mais aussi penser à faire des stress tests. Les tests permettent de réduire l’éventail des inconnus.

Monitoring

Ou comment « étudier le passé pour mieux prédire le futur ».
Il faut à la fois monitorer à un niveau microscopique et macroscopique.
Des outils Mongo sont nativement disponibles pour le monitoring, comme mongostats, iostats, mongoTop, currentOp, explain… 10gen a aussi développé un outil gratuit et opensource : MMS (Mongo Monitoring Service). C’est un SaaS qui permet de monitorer Mongo et aussi de générer des alertes.

Capacité de montée en charge

Identifier s’il faut scaler verticalement (ram, ssd, …) ou horizontalement (sharding, replica).
Avant même de scaler, refaire un tour sur le design du modèle et vérifier qu’il peut pas être optimisé, c’est peut-être ça qui est vraiment nécessaire plutôt que de rajouter du matériel.

Procédures de reprise sur panne

Utiliser les procédures de backup, restore et upgrade offertes par Mongo. Comprendre les « oplogs » de Mongo. Tester les différentes procédures de reprise sur panne avant qu’un problème arrive afin de bien maîtriser et valider ces procédures.

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012:

MongoDB Day Paris 2012 – 1 – Schema design principle and practices – Chris Harris, 10gen

MongoDB et son système de schéma libre apporte une grande liberté dans la modélisation des données.
Il reste que certains designs sont plus adaptés que d’autres selon les données et les contraintes que l’on a.
Il faut aussi garder en tête que les règles qui s’appliquent à la conception de schémas pour les bases de données relationnelles ne sont plus toujours vrai pour MongoDB, d’autant plus que celui-ci possèdes des caractéristiques uniques comme les mises à jour atomiques et les index sur tableaux qui changent les règles du jeu.
Le but de la conférence était donc d’identifier les bonnes pratiques pour modéliser les données dans MongoDB.
Il en ressort que la modélisation est tout d’abord contrainte par les relations existantes entre les données du modèle.

Si la relation entre les données est de l’ordre du OneToMany, un blog et des postes par exemple, alors on peut les découper en deux documents, en mettant une référence vers le blog dans les postes. Cette référence est l’id de l’objet à référencer et est l’équivalent d’une clé étrangère dans le monde relationnel à l’exception qu’ici le savoir est au niveau applicatif et que pour mongo c’est un champ comme un autre (il n’y a pas de contrôle d’intégrité).

Si la relation est ManyToMany, des produits et des catégories de produit par exemple, alors si l’on veut découper les données en deux documents on peut au choix avoir dans chacun des documents un tableau de référence vers l’autre collection (les produits aurait un tableau de catégories et les catégories auraient le tableau de produits).
L’autre solution est qu’une seule collection possède des références vers la seconde, par exemple les produits possèdent un tableau de catégories : les insertions sont alors plus rapides et la base est moins lourde. Par contre certaines requêtes en lecture sont beaucoup plus lentes : ainsi si l’on veut récupérer tous les produits d’une catégorie, il faudra alors parcourir tous les produits et regarder pour chacun s’ils appartiennent à cette catégorie…

Si la relation est de type arbre, par exemple un poste de blog et ses commentaires avec la possibilité de commenter les commentaires, alors les choses se compliquent un peu. Il est possible de faire un document unique mais il risque alors d’avoir une taille conséquente. L’autre problème est qu’il va être difficile à requêter, étant impossible de savoir à l’avance sa profondeur.
La meilleure solution est souvent de dé-normaliser en deux documents (poste et commentaire) et d’ajouter à chaque commentaire un tableau d’ancêtres, une autre possibilité est d’avoir un champ  sous la forme d’un chemin à la xpath, par exemple « com1/com3/com5″ puis de faire des requêtes par expression régulière.

Une solution toujours présente quelque soit le type de relation est de tout mettre dans le même document. Une question récurrente lors de la modélisation des données dans mongo est alors la normalisation ou non des données, c’est à dire leur agrégation ou non au sein d’un même document.

Tout d’abord il faut bien avoir en tête les caractéristiques spécifiques à MongoDB.
Il n’y a pas de transaction dans mongo, cependant les mises à jours d’un document se font de manière atomique. Ainsi le seul moyen d’avoir un équivalent des transactions dans mongo est de mettre toutes les données sous transaction dans un même document.
L’inconvénient de ce système de mise à jour atomique est que si trop de données sont dans le même document alors on risque d’avoir des problèmes liés à la concurrence des accès et au déplacement du document sur le disque (padding).

Il faut aussi savoir que la taille limite d’un document est de 16mo, ce qui peut être un frein à la dénormalisation.
Du côté des performances quand les données sont découpées en deux documents il faudra deux requêtes pour faire une requêtes équivalente à une jointure alors qu’une seule requête suffit lorsque les données sont agrégées.

Voilà quelques considérations qu’il faut avoir en tête quand on modélise les données.
Il n’existe pas de solution unique, la bonne solution dépends des requêtes que l’on effectuera et de leurs contraintes.

Ce billet fait partie de la série sur la journée MongoDB Day Paris 2012: