Mais c’est quoi le NoSQL ? Episode II : Relationnel vs NoSQL

octobre 29, 2013 dans Architecture, NoSQL, Veille technologique par Cédric Millauriaux

Dans mon article précédent, j’ai détaillé les conditions qui ont permis l’émergence des moteurs NoSQL et les événements et acteurs majeurs qui ont amené le NoSQL sur le devant de la scène. Aujourd’hui, je vais détailler les différences fondamentales qui existent entre les moteurs relationnels et la base NoSQL. Ainsi, nous allons commencer à dresser le portrait robot d’une base NoSQL, ses caractéristiques, ce qui nous amènera à regarder ce qui se passe « sous le capot » dans mon prochain article.

Un moteur relationnel c’est…

Je ne vais pas passer en revue toutes les caractéristiques et les fonctionnalités des bases de données relationnelles, je pars du principe que vous connaissez globalement le sujet. Je vais plutôt évoquer les principes qui sont reniés ou non repris par le NoSQL.

Une structure de données

Aussi surprenant que cela puisse paraître, une base de données relationnelle fonctionne majoritairement à base de… relations ! Cela peut paraître trivial (voir même comique…) mais c’est bien la base de ces moteurs et ce qui les opposent principalement aux moteurs NoSQL. Le schéma de données est donc composé de tables, dans lesquelles figurent des colonnes, qui peuvent être liées entre elles par des relations, qui seront résolues par l’intermédiaire de jointures. Il est à noter que les colonnes sont typées, et de longueur fixe. Les données quant à elles, sont représentées par des lignes dans ces tables. Avant de poursuivre, si vous avez quelques questions sur le fonctionnement de base de données relationnelles, vous pouvez aller faire un tour sur cette page.

Des contraintes

Afin de contrôler les données qui sont insérées, modifiées ou supprimées dans la base de données et assurer que l’intégrité des données est en tout temps respectée (au niveau des relations par exemple), les bases relationnelles proposent un système de contraintes. Ces contraintes peuvent concerner la présence obligatoire d’une donnée, son type, sa longueur, etc.

Une méthode de modélisation

Afin de minimiser l’espace disque utilisé et de ne pas dupliquer les données présentes en base de données, il est vivement conseillé de normaliser son modèle de données lors de la modélisation de ce dernier. Ainsi, si un utilisateur possède une donnée « Pays », il ne faut pas qu’une colonne « Pays » soit présente dans la table « Utilisateur », mais il faut créer une table « Pays » et une jointure entre la table « Utilisateur » et « Pays ». Ainsi, on ne crée qu’une ligne « France » dans la table « Pays » et chaque utilisateur français possède une relation vers l’entrée « France ». Les bénéfices sont multiples : l’espace disque utilisé est moins important et lorsqu’il s’agit de changer « France » en « FRANCE », on ne doit toucher qu’une seule ligne dans la base de données.

Un schéma de données

Les bases de données relationnelles imposent de définir un schéma avant d’y insérer des données. Ainsi vous créez tables, jointures et autres restrictions qui vont donner un cadre rigide et structuré à vos futures données. Une fois ce schéma défini, il peut être difficile de le modifier. Même si l’ajout d’une colonne est une opération simple et bien gérée par les moteurs relationnels actuels, pensez au changement de type d’une colonne, à la suppression d’une jointure, etc. C’est donc à la fois une force et une faiblesse des systèmes relationnels : vous êtes assurés que vos données sont correctement structurées, conformément à ce que vous avez spécifié, mais changer cette structure peut s’avérer cauchemardesque.

Une relation avec un modèle objet

Soyons réaliste : le modèle objet est massivement utilisé dans les programmes que nous développons. Il nous permet de structurer nos données sous forme de classes, de lier plusieurs classes entre elles (compositions, agrégations, etc) et finalement de les instancier et de les manipuler sous forme d’objets. Dit comme cela, on remarque beaucoup de similitudes avec la structure relationnelle. Et pourtant ! Il est bien souvent de la responsabilité du développeur d’assurer une correspondance entre le modèle de données relationnel et le modèle de données objet, sous-entendu de s’y adapter. Même si des frameworks existent pour permettre une persistance « transparente » des objets dans une base de données relationnelle (et vice versa), on en vient bien souvent à oublier les concepts puissants et pratiques chers à l’objet : adieu héritage par exemple ! Le modèle objet devient donc un support pour manipuler en mémoire les données stockées dans le modèle relationnel, et non pas un modèle pensé et optimisé pour gérer les données. Le modèle est pensé relationnel et exploité en objet.

Du requêtage

Pour communiquer avec la base de données, toutes les requêtes (qu’elles soient de manipulation du schéma, de manipulation des données ou de recherches) se font à l’aide du langage SQL. C’est un langage déclaratif, créé pour être compréhensible et utilisable par des non spécialistes.

Des transactions

Une des forces des moteurs relationnels est qu’ils garantissent l’acidité des transactions, comprenez par là qu’ils respectent les paradigmes suivants :

  • Atomique : Une transaction est définie comme un ensemble d’opérations qui sont validées intégralement ou annulées intégralement.
  • Cohérente : Pendant la transaction, le système est dans un état instable, à l’issu, il doit soit revenir à l’état initial, soit être dans un nouvel état stable fonctionnellement et techniquement.
  • Isolée : Isoler les données d’une transaction d’une autre, afin que des opérations non validées d’une transaction ne soient pas lisibles par une autre.
  • Durable : Lorsqu’une transaction est validée, le nouvel état stable doit être durablement inscrit dans le système.

Ce qui est sous-entendu derrière cet acronyme « ACID », c’est que lorsque vous effectuez une série d’opérations, elle est encapsulée dans une transaction. Tant que cette transaction n’est pas clause, les opérations n’impactent pas la base de données et ne sont visibles que par la transaction courante. Ainsi, vous pouvez demander le retour à l’état initial ou valider cette transaction, et les opérations seront validées et visibles des autres transactions. Cela garantit qu’une transaction externe ne pourra se retrouver à traiter avec des données partielles ou non validées.

Un moteur NoSQL c’est…

Maintenant que nous avons fait le tour des principales caractéristiques des bases de données relationnelles, passons en revue les caractéristiques des moteurs NoSQL.

Une structure de données

Les données sont également structurées en NoSQL puisqu’elles sont réunies au travers de collections de documents ou de familles de colonnes par exemple. Néanmoins, il ne s’agit pas de structures figées comme on peut l’entendre avec les tables relationnelles : on préférera le terme de conteneur, soit un espace où sont stockées une collection de données ou les données elles-mêmes. Ainsi, si l’on imagine une collection de documents nommée « utilisateur », il est cohérent pour un moteur NoSQL de stocker un document « utilisateur » qui contiendra un identifiant, un nom et un prénom et un autre document qui contiendra un identifiant, un pseudo et une adresse mail.

Les jointures existent mais leur utilisation va à l’encontre de la philosophie NoSQL. Lorsque l’on sélectionne un document, on préfère disposer de toutes les informations qui nous seront nécessaires directement dans ce document. Ainsi, on n’a pas à faire de coûteuses jointures pour faire une restriction ou à résoudre de nombreuses relations pour accéder à une donnée.

Une absence de contraintes

Comme un document ou une famille de colonnes n’a pas de structure fixe, il n’est pas possible ni nécessaire de définir des contraintes. De la même manière, les données ne sont généralement pas typées. Tout cela peut paraître perturbant : comment interagir avec une base de données qui ne nous offre pas de cadre structuré pour organiser nos données et de contraintes pour assurer leur intégrité ? La réponse est simple et constitue l’un des choix fondamentaux du NoSQL : les moteurs NoSQL ne sont pas des bases de données au sens où on l’entend (la gestion et le stockage des données) mais plutôt des entrepôts de données. Une base NoSQL se contente d’entreposer et de retourner les données à la demande d’un programme. La structure des données et les contraintes qui s’y appliquent doivent être assurées par le modèle implémenté dans ces programmes. En clair, on déporte la responsabilité au niveau du programme métier : dans la majorité des cas, c’est le modèle objet de votre application qui va porter toutes ces informations. L’entrepôt de données NoSQL est donc là uniquement pour stocker les informations que vous avez modélisées dans votre modèle objet, par pour en assurer la cohérence ou l’intégrité.

Une méthode de modélisation

Là où le modèle relationnel prêche la normalisation des données, l’utilisation d’une base de données NoSQL va nous pousser à dénormaliser notre modèle. Il est déconseillé (ou parfois il n’est pas possible) de réaliser des jointures entre des éléments stockés dans une base NoSQL, alors on va s’attacher à y inclure toutes les données nécessaires à la restriction et à la sélection, dans un document ou une famille de colonnes. Reprenons notre exemple : si l’on dispose d’un utilisateur qui est attaché à un pays, on va faire porter l’information « Pays » à chaque utilisateur. Ainsi, si deux utilisateurs ont pour pays « France », on va dupliquer cette information pour ces deux utilisateurs. Cela implique que l’espace disque occupé sera plus important, mais il n’y a pas de jointure à faire pour sélectionner tous les utilisateurs dont le pays est « France », ni de relation à parcourir pour afficher le pays de l’utilisateur. C’est la philosophie du NoSQL : dénormaliser donc dupliquer pour assurer la performance. Un autre effet bénéfique est, si l’on dispose de plusieurs nœuds dans notre infrastructure, on est ainsi assuré que la donnée « utilisateur » et « pays » se situera sur le même nœud (puisque dans le même document ou famille de colonnes). Imaginez s’il fallait faire une jointure entre des données présentes sur des nœuds différents, distincts géographiquement : un vrai mélodrame pour les performances !

Un schéma de données… flexible

Les bases de données NoSQL ont la réputation d’être « schema-less », sous-entendu sans réelle notion de schéma. Au vu des paragraphes précédents, vous avez compris que ce n’est pas vraiment le cas : étant donné qu’un document ou une famille de colonnes ne contient pas une « liste » d’attributs déterminés et que ceux-ci ne sont généralement pas typés, on peut dire que le schéma est extrêmement flexible voir inexistant. Cela n’enlève en rien la problématique au niveau de l’intégrité des données : même s’il est techniquement possible d’avoir deux documents d’une même collection qui différent totalement, cela n’a pas de sens une fois ramené à un modèle objet. Les bases NoSQL permettent donc de se passer de schéma et de contraintes, ce qui est un atout pour la facilité de développement et la construction de modèles de données « à la volée » mais n’enlève en rien les problèmes d’intégrité des données et de migration de données en cas de modification sur un jeu de données de production.

Une relation avec un modèle objet

La manière dont un moteur NoSQL gère et stocke ses données colle beaucoup plus près à un modèle objet. En effet, le fait que le schéma soit flexible permet de gérer les problématiques d’héritage. Lorsque les données sont typées, elles le sont d’une manière beaucoup plus proche des langages de programmation. La dénormalisation, qui permet « d’embarquer » les données et non pas de les lier avec d’autres, permet de gérer les notions d’agrégations et de compositions sans être traduites par de complexes jointures. Les bases de données NoSQL ne sont donc pas des bases de données objet à proprement parlé mais leur flexibilité et leurs différents atouts permettent de coller au plus près de ces modèles.

Du requêtage

C’est à la fois une force et une faiblesse des moteurs NoSQL actuels : il n’existe pas à ce jour de langage de requête universel. Nous retrouvons pour certaines bases un langage inspiré du Javascript, pour d’autres, un langage tiré du SQL mais adapté aux problématique NoSQL, etc. Dans tous les cas, une interface est proposée pour pouvoir interroger ou effectuer des opérations sur la base de données. Mais ce n’est pas un point d’entrée unique comme c’est le cas avec le SQL : les moteurs NoSQL sont faits pour être plus près des langages de programmation avec lesquels ils interagissent. C’est pourquoi, la majorité des implémentations de moteurs NoSQL offrent des drivers qui vont permettre de requêter nativement la base de données. Cela offre un gain au niveau des performances et de la compatibilité.

Une absence de transactions et des compromis

Les bases de données NoSQL n’offrent pas de gestion des transactions comme les moteurs relationnels. Cela est dû principalement à l’orientation du NoSQL, qui est tourné vers le clustering et la répartition/duplication des données sur plusieurs nœuds. Dans un moteur NoSQL, la priorité est donnée à la lecture des données. Pour cela, une information peut être dupliquée sur plusieurs nœuds. Ainsi, lorsque l’on met à jour un nœud avec une information, il est à la charge du moteur de contacter ses nœuds voisins afin de leur signifier que l’information a été mise à jour. De cette manière, on propage l’information de nœuds en nœuds. Pour ne pas impacter les performances en lecture (sous-entendu, ne pas bloquer la lecture en attendant que les mises à jour soient propagées sur tous les nœuds), le parti pris est d’admettre que durant le temps de propagation de la mise à jour, le système est dans un état instable : certains nœuds ont la donnée à jour, d’autres ont la donnée obsolète.

En partant de ce constat, il est difficile d’envisager un système de transactions viables : l’acidité ne peut être garantie car les opérations ne sont ni isolées ni cohérentes.

Et c’est en partant de ce principe que le théorème CAP a été écrit. Bien que contesté de nos jours car jugé trop réducteur, il exprime bien les compromis qui doivent être faits lorsque l’on souhaite gérer des données sur un système distribué et réparti. Le théorème CAP décrit trois axiomes :

  • Cohérence : Tous les nœuds voient les mêmes données au même moment.
  • Disponibilité : La garantie que le système soit en mesure de répondre à une requête à tout moment.
  • Résistance au morcellement : chaque nœud doit pouvoir répondre à toutes les sollicitations s’il se trouve déconnecté des autres nœuds.

Si l’on considère un système distribué et réparti (une base de données NoSQL), il est impossible de pouvoir servir plus de deux axiomes du théorème CAP.

Par exemple, on peut envisager un système cohérent et disponible : une donnée est centralisée sur un nœud, tous les autres nœuds doivent donc s’y référer en cas de sollicitation (Cohérence). Il n’est donc pas nécessaire de « bloquer » le système en lecture en attendant que l’information soit propagée (disponibilité). Par contre, si le nœud détenant l’information n’est pas disponible (panne, coupure réseau, …) alors le système ne peut plus servir l’information (résistance au morcellement).

Un autre exemple : on ne bloque pas le système en lecture tant que les données ne sont pas propagées (disponibilité). On duplique l’information sur plusieurs nœuds, pour qu’au cas où un nœud ne soit plus disponible, le système puisse continuer à servir l’information (résistance au morcellement). Néanmoins, on ne peut garantir de servir une donnée « fraîche » à tout instant : le temps de la propagation d’une mise à jour, certains nœuds peuvent renvoyer une donnée obsolète (cohérence).

Et c’est précisément ce dernier choix qu’on fait la majorité des moteurs NoSQL. Au vu de ces éléments, il n’est pas concevable de retrouver un système de transactions ACID comme c’est le cas avec les bases de données relationnelles.

Alors, SQL versus NoSQL ?

Maintenant que nous avons comparé les caractéristiques des bases de données relationnelles et des bases de données NoSQL, pouvons-nous dire qu’elles s’opposent et se renient l’une l’autre ? Il est encore un peu tôt pour répondre à cette question mais on voit une tendance se dessiner : celle des compromis. Les moteurs relationnels sacrifient les performances et l’élasticité sur l’autel de l’intégrité et de la cohérence des données. Les moteurs NoSQL privilégient eux les performances et l’élasticité, quitte à sacrifier le principe des transactions et la cohérence des données en phase de propagation.

Si l’on se dirige vers l’utilisation d’une base de données NoSQL plutôt que vers une base de données relationnelle c’est donc par besoin, non par choix philosophique ou par amour des nouvelles technologies. Ces deux conceptions ne s’opposent pas ou ne cherchent pas à faire mieux que l’autre : elles sont simplement différentes et adaptées à des besoins différents.

Dans mon prochain article, nous allons soulever le capot des moteurs NoSQL et comprendre quels sont les choix technologiques et philosophiques qu’ils embarquent !

Mais c’est quoi le NoSQL ? Episode I : Introduction

octobre 29, 2013 dans Architecture, NoSQL, Veille technologique par Cédric Millauriaux

C’est quoi le NoSQL ? Est une question que beaucoup d’entre vous doivent se poser tellement on en entend parler ces temps-ci. La presse spécialisée, internet, les discussions au café, tout le monde évoque à un moment ou un autre le mot « NoSQL » quand vient le moment de parler des dernières tendances comme le « cloud » ou le « big data ». Je vais donc ici expliquer et démystifier ce qu’est le NoSQL, afin notamment de vous donner le background nécessaire pour pouvoir aborder ma prochaine série d’articles, où nous mettrons en place et utiliserons des BDD NoSQL.

Présentation du NoSQL

Qu’est-ce que c’est le NoSQL ?

Pour commencer, qu’est-ce qui se cache derrière le terme « NoSQL » ? Comme son nom ne l’indique pas, il ne s’agit pas de renier le SQL mais plutôt de tenter quelque chose de différent. Le mouvement NoSQL revendique le fait de prendre en compte les problématiques actuelles quitte à sacrifier quelques notions chères aux base de données relationnelles. On devrait donc traduire le mot « NoSQL » par « Not Only SQL ».

S’intéresser au NoSQL, c’est donc avant tout s’intéresser à une philosophie différente : les bases de données relationnelles sont nées de théorèmes mathématiques, pour répondre au besoin de stocker et traiter des données avec une puissance et un espace disque restreint. Les bases de données NoSQL sont nées de retours d’ingénieurs, de vœux pieux d’administrateurs système à une époque où la puissance comme l’espace disque ne coûtent plus grand chose.

Et surtout, il y a eu un traumatisme dont les bases de données traditionnelles ont été victimes et qui a accéléré la recherche de solutions alternatives : Internet. Depuis la naissance et la démocratisation d’Internet, les données doivent être accessibles partout, par des milliards d’utilisateurs potentiels (pensez au moteur de recherche Google !) et en temps réel. Les SGBDR créés pour les besoins de l’informatique de gestion au sein de l’entreprise, ne proposent pas nativement de répondre à ces nouveaux besoins. La réplication de données est douloureuse, la contrainte de haute disponibilité et de temps réel difficile à maintenir à l’échelle d’une infrastructure mondiale et les moyens mis en place sont archaïques. En un mot, l’évolution du nombre d’utilisateurs d’un système augmente les besoins en ressources, et l’ajout de ces ressources entraîne un coût de mise en place et de maintenance exponentiel, à cause d’outils non adaptés.

La réponse des ingénieurs à toutes ces problématiques : le NoSQL.

Pourquoi le NoSQL ?

Alors pourquoi le NoSQL ? J’ai déjà partiellement répondu à cette question dans le paragraphe précédent : nous sommes entrés dans une époque où les données que vous exposez doivent être disponibles partout et en temps réel, ce qui implique de mettre en place des ressources toujours plus importantes. Si l’on prend le cas de Google par exemple, ils doivent indexer un nombre de sites toujours plus important, répondre aux requêtes d’un nombre croissant d’utilisateurs mais toujours dans un temps inférieur à quelques millisecondes, quel que soit l’emplacement géographique de l’utilisateur. Derrière cette (longue) phrase, se cachent tous les constats qui ont mené à imaginer et implémenter les bases de données NoSQL.

Avant d’aller plus loin, un petit rappel de vocabulaire : dans une architecture distribuée (les ressources que sont la puissance de calcul et le stockage des données sont reparties sur plusieurs machines) on nomme « cluster » un ensemble de serveurs qui forme une seule et même unité. Les serveurs qui composent ce cluster sont appelés « nœuds ».

Gérer un grand nombre de données sous-entend ne pas pouvoir les stocker au même endroit et donc devoir les repartir intelligemment sur plusieurs nœuds de l’infrastructure. Mais ce n’est pas si simple, car il s’agit de redonder les données entre les différents nœuds au cas où l’un d’eux viendrait à défaillir (pensez par exemple à la technologie RAID 5). Il s’agit aussi de savoir où retrouver une donnée précise sans avoir à parcourir l’intégralité des nœuds et de leurs données propres. Enfin, au delà de l’espace disque, il faut pouvoir mettre en place de la puissance processeur pour pouvoir gérer ces données (insertion, lecture, requêtes, …), qui sera plus ou moins importante en fonction de la sollicitation du système. Il faut donc pouvoir disposer d’une infrastructure élastique, capable de s’adapter à des données et des sollicitations importantes, en repartissant cette charge sur plusieurs nœuds.

Cependant, ces notions peuvent être mises en place avec des SGDB relationnels, Facebook l’a prouvé ! Oui, mais ce n’est pas sans douleurs ! Les SGBDR n’ont pas été conçus dans cette optique, c’est donc à grands coups de développements spécifiques, d’adaptations, de tuning système, que l’on tente d’y parvenir. L’un des fondements des bases de données NoSQL est de pouvoir répondre nativement à ce besoin : permettre de mettre en place une architecture élastique, distribuée et répartie pour gérer ses données.

Une deuxième raison qui a mené à l’avènement du NoSQL est que cette technologie a été imaginée par les ingénieurs systèmes et développeurs, pour les ingénieurs systèmes et développeurs ! Là où les bases de données relationnelles ont été imaginées et conçues par des mathématiciens autour de la théorie des graphes, les bases de données NoSQL ont été imaginées par des techniciens conscients des problèmes auxquels ils devaient faire face au jour le jour et adaptées à leur manière de développer. Ces derniers travaillent majoritairement avec des modèles objets, qu’ils sont obligés d’adapter pour calquer avec le modèle relationnel de la BDD. Ils souffrent lorsque ce modèle évolue, car il faut migrer les données, changer la manière dont on interagit avec les données dans le programme métier comme dans la base de données, etc. C’est une idée de base du NoSQL : faire porter la structure des données par le modèle objet, implémenté dans le programme métier, et proposer une base de données qui se contente d’entreposer ces données. Les contraintes et éléments de structures sont ainsi directement gérés par le programme implémenté par le développeur, et non « en doublon » comme on le voit souvent.

C’est ainsi que je résumerais la réponse à la question « comment en est-on arrivé au NoSQL ? » : car l’on a besoin d’une infrastructure élastique, d’outils adaptés pour le développement, que l’on a conscience qu’un modèle de données va évoluer et enfin, que l’on vit dans une époque où la puissance de calcul et l’espace disque ne coûtent plus grand chose.

Un peu d’histoire…

Nous avons vu que les conditions étaient réunies pour que le monde de l’informatique se penche sur une solution alternative aux bases de données relationnelles, plus adaptée aux nouveaux besoins. Nous allons maintenons voir quels sont les dates et faits marquants qui ont permis l’avènement des bases de données NoSQL.

Il faut remonter dans les années 60/70 pour trouver les premières traces de base de données non relationnelles. Normal, elles n’avaient pas encore été inventées ! [ENCHAINEMENT DES DEUX PHRASES A REVOIR ?] La problématique était alors de fournir des bases de données performantes pour les moyens de l’époque, qui offraient de faibles temps de réponse en lecture. Il était considéré que sur les applications gros systèmes, on passait beaucoup plus de temps à lire des données qu’à les écrire. Les bases de données hiérarchiques étaient nées et répondaient à de telles contraintes. Les cobolistes qui nous suivent doivent se rappeler des souvenirs lorsque on évoque les noms de « DBM » et de « IMS ».

C’est en 1998 qu’on entend pour la première fois le néologisme « NoSQL » de la bouche de Carlo Strozzi . L’auteur de ce terme a voulu marquer la scission avec le monde relationnel, sans pour autant le renier totalement. C’est pourquoi, la traduction courante est « Not Only SQL », ce qui ne concerne pas directement le « SQL » en tant que langage, mais les SGBDR. Un terme comme « NoREL » aurait été moins sexy :)

Il faut ensuite attendre les années 2000 pour voir émerger les moteurs NoSQL actuels, motivés par l’arrivée au premier plan des besoins d’élasticité et de performances. Et c’est sous l’impulsion de Google et de son fameux « BigTable », dont le développement a débuté en 2004, que le mouvement a connu un véritable essor. En effet, en 2006 Google publie le résultat de ses recherches et va mettre la scène NoSQL au premier plan. Le n°1 de la recherche a une influence considérable dans le domaine de l’informatique et de nombreux projets s’inspirant de leurs recherches vont alors naître. Il est à noter que des acteurs de premiers plans du mouvement NoSQL (neo4j, mongodb, memcached) ont débuté leur développement avant la sortie de ce papier.

C’est donc à partir de 2006 que tout s’accélère : Amazon rejoint la course à l’armement en 2007, en publiant également ses recherches. Linked démarre le développement du « projet Voldemort » en 2008, Facebook ouvre les sources de son projet « Cassandra » la même année.

La convention de 2009 de San Francisco sur le NoSQL a initié le mouvement et a inauguré la communauté de développeurs de moteur NoSQL. Leur philosophie : proposer uniquement ce dont’on a besoin, là ou les moteurs relationnels en proposent trop, et sont par conséquent trop lourds.

Actuellement, le mouvement se poursuit et des tentatives d’uniformisation autour d’un même langage (à l’instar du SQL pour les bases relationnelles) voient le jour. Nous ne sommes qu’au début de cette nouvelle ère et de premières applications industrielles (sous-entendu, l’utilisation par des sociétés classiques qui ne sont pas à l’origine de ces mouvements) commencent à émerger.

Et après ?

Dans mon prochain article, je vais détailler les différences fondamentales entre les moteurs relationnels que nous connaissons bien et les bases de données NoSQL. Nous verrons alors les premières limites de ce nouveau modèle et constaterons qu’embrasser cette nouvelle technologie n’est pas forcément une nécessité, et que dans certains cas, il serait suicidaire de s’y aventurer.

Mais c’est quoi le NoSQL ? Episode V : Pour qui ? Pour quoi ?

octobre 29, 2013 dans Architecture, NoSQL, Veille technologique par Cédric Millauriaux

Nous arrivons à la conclusion de cette série d’articles sur le NoSQL. En considérant tout ce que l’on a vu jusqu’à présent : la philosophie NoSQL, les différences avec les systèmes relationnels, les partis pris des moteurs NoSQL et les différents types de structures offertes, on est en droit de se poser la question : quand est-ce que je dois me tourner vers une base de données NoSQL ? C’est la question à laquelle je vais répondre dans cet article.

Ne pas céder à la tentation…

Il est avant tout important de ne pas céder à la tentation : ce n’est pas parce qu’utiliser une base de données NoSQL est « tendance » et aussi parce que « c’est l’avenir » qu’il faut absolument sauter le pas. Si vous en arrivez à utiliser une base de données NoSQL c’est parceque vous en avez le besoin ! Nous ne sommes pas dans la bataille « Emacs vs VI » ou « Debian vs Red Hat » car, comme nous l’avons vu, relationnel et NoSQL ne s’opposent pas, ils couvrent simplement un besoin différent. Maintenant voyons quels sont les critères qui doivent nous pousser à adopter une base NoSQL.

J’adopte un moteur NoSQL si…

  • Je dois privilégier les performances et la disponibilité à la cohérence des données. C’est peut-être le critère le plus important : si vous devez monter un système de gestion (ressources humaines, stock, …) passez votre chemin ! Comme je l’ai plusieurs fois répété : un moteur NoSQL est fait de compromis afin de privilégier les performances et ne garantit pas notamment l’acidité des transactions. On ne peut concevoir d’avoir un système permettant la gestion des stocks qui ne garantit pas qu’à un instant « t », tous les utilisateurs voient la même quantité disponible. De même, imaginons une application bancaire qui doit réaliser un virement (enlever l’argent d’un compte pour le mettre sur un autre) : si il y a un problème alors que j’ai déjà soustrait la somme du compte débiteur et que je ne peux créditer le compte destinataire, est-ce que je peux imaginer ne pas avoir la garantie de revenir à l’état initial ? La réponse est évidemment non ! A l’inverse, si je dois développer un Facebook-like, est-il vraiment important que deux utilisateurs qui sont chacun à un bout de la planète ne voient pas la publication de mon statut au même moment ? Encore une fois non : je préfère faire le choix que tous les utilisateurs puissent afficher mon site avec une latence minimum, où qu’ils soient, quel que soit l’état de santé de mon système, plutôt que d’afficher absolument des données fraîches à mes utilisateurs.
  • Je pars sur une architecture distribuée. Les bases de données NoSQL sont pensées pour constituer un cluster, où chaque noeud joue un rôle dans la redondance des données, la répartion des charges, etc. S’il n’est pas prévu que vous formiez un cluster de serveurs pour faire fonctionner votre base de données, vous vous embarassez des fameux compromis du NoSQL pour rien. A l’échelle d’un seul noeud, les bases de données NoSQL sont même en moyenne moins performantes que les bases de données relationnelles !
  • Je veux une architecture élastique. Ce critère est à relier au précédent : si vous avez le besoin de pouvoir ajouter de l’espace de stockage/des ressources de calcul dynamiquement dans votre infrastructure (je ne parle pas qu’au niveau de la base de données), il faut considérer sérieusement l’option NoSQL ! Autant il est vite couteux et difficile de maintenir un monolithe superpuissant hebergeant une base Oracle ou PostgreSQL, autant les bases de données NoSQL sont très à l’aise avec l’ajout/suppression de noeuds dynamiquement dans un cluster. Si votre infrastructure est taillée pour servir 1 utilisateur mais que demain cela peut être 10, ou 100, alors le choix du NoSQL est un choix optimal.
  • Je vais gérer une grande quantité de données. C’est souvent l’argument qui revient à la pause café quand certains parlent (en en ignorant tout…) des bases NoSQL : elles ne servent que lorsque l’on doit héberger une quantité phénoménale de données. C’est plus ou moins vrai quand on associe le mot « NoSQL » à « Big Data » mais je dirais que ce n’est pas une généralité. On peut très bien gérer un très gros volume de données avec une base de données classique qui s’appuie sur une baie SAN de plusieurs To. A l’inverse, on peut avoir besoin d’une base NoSQL sans avoir à gérer de gros volumes de données (pensez au bases orientées graphs ou à la souplesse offerte par le « schema-less »). Par contre, si vous estimez que vos données dépasseront très vite le peta octet, alors effectivement, cela devient un argument de poids !
  • Je veux pouvoir servir mes données aux quatre coins du monde. Si vous hébergez une application web (reprenons l’exemple d’un Facebook-like) qui doit être accessible aux quatre coins du monde alors vous aurez certainement besoin de répliquer et de redonder vos données sur les cinq continents. Ainsi, les données seront au plus près de vos utilisateurs, évitant la latence et la concentration de vos données dans un seul datacenter. Pour cela, le NoSQL est parfaitement adapté : la réplication et la répartition des données (qui peut être gérée géographiquement sur certains moteurs !) sont gérées nativement et de manière totalement transparente.
  • Je veux privilégier la souplesse de développement. C’est un argument que l’on entend peu souvent mais qui a un certain poids : donner aux développeurs des outils souples et faciles à prendre en main. Le fait de devoir maintenir un double modèle et des doubles contraintes entre un modèle relationnel et un modèle objet est généralement rebutant et douloureux pour le développeur. Avec le NoSQL, vous leur offrez le moyen de maîtriser le modèle de données dans l’application, à l’aide du modèle objet qu’ils manient très bien ! De même, fini les problématiques des coûteuses et douloureuses migrations de données ! Rappelez-vous : le NoSQL a été créé par des ingénieurs pour des ingénieurs !

NOSQL + relationnel ?

Avant de conclure, je me dois de rajouter un argument en faveur des deux mondes : j’ai tenté de vous démontrer au fur et à mesure de notre découverte du NoSQL qu’il n’était pas question de renier le monde du relationnel ou de le concurrencer, mais plutôt de palier des lacunes de ce dernier ou de faire des compromis pour privilégier l’aspect performance. Alors pourquoi ne pas voir une association du relationnel et du NoSQL dans nos applications ?

Si l’on a besoin d’un cadre structuré pour nos données, de transactions ACID et que l’on a pas l’intention de monter un cluster pour héberger nos données alors il est évident que nous allons utiliser un moteur relationnel. Mais pour un besoin particulier (pensez à un mécanisme de recommandations qui va vous afficher les amis de vos amis par exemple !) dans votre application, vous pouvez utiliser une base NoSQL, à côté de la base relationnelle, pour répondre à ce besoin particulier. Rien ne vous empêche d’intégrer une base NoSQL au milieu des bases relationnelles de votre SI, et cela peut être au contraire un moyen de tester ces bases de données particulières dans un contexte de production, d’en comprendre les tenants et les aboutissants, avant de généraliser leur utilisation dans vos applications. Un exemple : vous gérez un ensemble d’applications traditionnelles (bases relationnelles, client léger accessible par les utilisateurs de l’entreprise) qui traitent d’un même domaine métier et on vous demande de créer un système qui centraliserait les traces applicatives pour pouvoir déceler des anomalies (fraude d’un client par exemple). Alors pensez au NoSQL ! Là où l’emploi de bases relationnelles est totalement justifié pour chacune de ces applications, le développement d’un système de centralisation et de surveillance des traces applicatives peut faire appel à une base NoSQL : ainsi, votre architecture sera élastique (imaginez qu’on rajoute les données de dix nouvelles applications dans votre nouveau système !), performante afin de traiter ces nombreuses données en temps réel, et le manque d’acidité des transactions n’est plus un problème.

Si votre besoin ne justifie pas de passer totalement au NoSQL, gardez toutes ces notions dans un coin de votre tête, elles pourraient bien ressortir pour traiter un besoin particulier qu’il sera difficile de traiter avec une base relationnelle classique.

Conclusion ?

Difficile de conclure une telle série d’articles ! Je dirais pour commencer que si l’on entend tant parler de NoSQL en ce moment c’est parce qu’on voit émerger plusieurs structures qui se doivent de servir des millions d’utilisateurs répartis au quatre coins du monde, qui demandent un vaste espace de stockage et que cela était impensable il y a une dizaine d’années. Les outils se sont adaptés et il est légitime pour une structure de se poser la question « Et demain, si j’avais à gérer une telle infrastructure, comment je ferais ? » et la réponse contient forcément le mot « NoSQL ».

Néanmoins, nous l’avons vu : l’adoption du NoSQL n’est pas pour tous et ne permet pas de répondre à toutes les problématiques. Au contraire ! Le confort et l’assurance des transactions ACID chères aux systèmes relationnels n’ont plus court, hérésie pour un système de gestion tel que l’on le connait. Si l’on se dirige vers le NoSQL, c’est qu’on a besoin de lui, et non par effet de mode ou par prétention philosophique. Et pour ceux justement qui ont des besoins en terme de redondance des données, de performance, de disponibilité, ils y trouvent enfin leur compte ! Fini les compromis, les frustrations et les coûts exponentielles qui viennent avec la montée en puissance d’une base de données relationnelle à mesure que la demande en ressources et en espace de stockage augmentent. Fini le casse tête du développeur qui doit pour la énième fois prévoir une modification du modèle de données. Si des sociétés comme Google et Amazon s’y sont engouffrées, c’est pour répondre avant tout à leur besoin : disposer d’un outil performant, peu coûteux, qui leur permette de répondre aux millions de requêtes journalières, de leurs millions d’utilisateurs qui les sollicitent sur tout le globe.

Je vais conclure en m’adressant aux techniciens dans l’âme : même si vous n’en rencontrerez peut-être jamais le besoin, essayez-les ! Documentez-vous sur leur fonctionnement, les principes que sont le sharding ou la répartition des données sont des domaines passionnants qu’il convient d’étudier. Et puis, n’est-il pas satisfaisant de toucher du doigt ce qui se fait chez Google ou Amazon, d’utiliser leur concept ? Allez dites-le, je suis sûr que vous rêvez de vous jeter dans la piscine à balles de Montain View sous l’œil vigilant du T-Rex qui trône dans le parc, alors lâchez-vous :)

Mais c’est quoi le NoSQL ? Epsiode IV : NoSQL et… NoSQL, quelle différence ?

octobre 29, 2013 dans Architecture, NoSQL, Veille technologique par Cédric Millauriaux

Dans mon article précédent, j’ai détaillé les grands concepts qui sont mis en place dans les moteurs NoSQL. J’en parle beaucoup de ces « moteurs NoSQL » dans cette série d’articles : et si j’utilise ce terme vague, c’est volontaire. En effet, le terme « NoSQL » regroupe des concepts et des implémentations réunis autour d’une philosophie commune mais qui présentent des différences tant dans leur fonctionnement que dans leur cible. Je vais donc, dans cet article, passer en revue les quatre grandes familles de base de données NoSQL, expliquer brièvement leur fonctionnement et donner quelques exemples d’utilisations.

Bases Clés/Valeurs

Les bases clés/valeurs sont les plus simples à comprendre dans leur fonctionnement. Elles sont des descendantes d’un programme nommé « memcached » qui fonctionne à l’image des collections « Map » en Java ou des « Dictionary » en C# : une clé, unique, référence une valeur quelle qu’elle soit. Afin d’accéder à cette donnée, on doit obligatoirement fournir sa clé, point d’entrée unique d’une base clé/valeur. La valeur peut être de n’importe quel type : une chaîne de caractères, une image, un objet complexe, etc. C’est là la force des bases clés/valeurs : elles permettent de stocker n’importe quelle donnée, quelle que soit sa structure. Pour le reste, on retrouve les concepts chers au NoSQL : les performances, la répartition des données sur une architecture distribuée, etc.

Alors quelle utilisation pour ce type de base de données NoSQL ? C’est pour des besoins basiques que les bases clés/valeurs vont être majoritairement utilisées : stockage de préférences utilisateurs (la clé : l’identifiant de l’utilisateur, la valeur : la liste des préférences), système de vote (la clé : l’identifiant du commentaire, concaténé avec ‘positif’ ou ‘negatif’, la valeur : le nombre de votes), etc.

En résumé, lorsque vous avez besoin de stocker et de requêter un grand nombre d’informations (l’ensemble de vos utilisateurs par exemple), et que vous n’avez aucune requête « complexe » à effectuer (sous-entendu, qui ferait appel à aucune autre donnée que la clé), les bases de données clés/valeurs sont très simples à mettre en place et répondent parfaitement à ce besoin.

Qui utilise des bases clés/valeurs : Twitter, Instagram, FlickR, qui rentrent exactement dans ce cas.

Bases orientées colonnes

Les bases orientées colonnes se rapprochent de ce que l’on connait dans les bases relationnelles : une structure nommée « famille de colonnes » associe à une clé une liste de colonnes. La différence notable est que les colonnes d’une famille de colonnes ne sont pas définies à l’avance et ne sont pas forcément les mêmes d’une ligne à l’autre. Un exemple pour fixer les idées : imaginons une famille de colonnes « relations » qui définit les relations entre plusieurs utilisateurs (la liste d’amis de Facebook par exemple). La clé est donc l’identifiant de l’utilisateur et on utilise une colonne par utilisateur « ami ». On peut donc avoir une ligne avec pour clé « ID_utilisateur » suivie des colonnes « ID_Ami_1″ et « ID_Ami_2″ et une autre ligne ayant toujours pour clé « ID_utilisateur » et pour colonnes « ID_Ami_1″, « ID_Ami_2″, « ID_Ami_3″ et « ID_Ami_4″.

Quelle utilisation pour des bases de données orientées colonnes ? Lorsque les données que vous traitez présentent une structure commune (par exemple, si l’on stocke des informations à propos de livres, un numéro ISBN, une année de parution) mais présentent des différences (par exemple, l’édition et le résumé, qui ne sont pas systématiquement renseignés). Mais quelle différence avec des colonnes où l’on mettrait « NULL » ? Et bien justement, il n’est pas nécessaire de matérialiser, de prévoir à l’avance ces colonnes et surtout il n’est pas nécessaire de stocker cette information inutile qu’est le « NULL ». L’avantage de ces bases de données réside dans le fait que le nombre de colonnes d’une famille de colonnes est potentiellement illimité. Difficile de concevoir une table de 1000 colonnes dans une base relationnelle. Et bien avec les bases orientées colonnes, c’est possible ! Et avec l’avantage de l’absence de schémas propres aux bases NoSQL : il n’est pas nécessaire de définir les colonnes à l’avance et le jour où l’on décide de rajouter une nouvelle colonne, on ne touche à rien : ni aux anciennes données, ni à la structure de la famille de colonnes.

Qui sont les utilisateurs des bases de données orientées colonnes ? Les structures qui manipulent un grand volume de données à la structure changeante et pour qui il existe un grand nombre d’attributs. C’est typiquement ce que l’on nomme « Big Data ».

Bases orientées documents

Les bases orientées documents proposent le modèle le plus souple des moteurs NoSQL. Des collections de documents contiennent des documents, qui sont un ensemble d’attributs, traditionnellement du texte ou des données simples. On peut voir ce système de documents comme un véritable document « papier » : une clé (par exemple le numéro ISBN d’un livre) permet de l’identifier et ensuite on stocke diverses informations dans ce document. A l’image d’un livre, deux documents peuvent appartenir à la même collection mais contenir des données totalement différentes. Alors quelle différence entre un entrepôt de données clé/valeur et une base orientée document ? La base clé/valeur propose d’associer une clé à une valeur binaire, qui peut être tout et n’importe quoi, sous-entendu non lisible et compréhensible par le moteur NoSQL. A l’inverse, les documents sont structurés et lisibles par le moteur NoSQL (on peut donc parcourir ces documents pour satisfaire une requête, utiliser une propriété d’un document pour en faire un index secondaire, …). C’est souvent le langage JSON qui est retenu pour représenter le corps d’un document. Pour fixer les idées, on peut voir un document comme un fichier JSON ou HTML, que le moteur NoSQL peut parcourir, et identifié par une clé unique (le nom du fichier dans l’exemple). Il est à noter que la force des bases orientées documents réside dans le versionning des documents : chaque modification est enregistrée et il est possible d’obtenir l’historique du document. Si vous avez à modifier la structure de vos documents, c’est un sacré atout : vous pouvez faire cohabiter des documents qui présentent l’ancienne structure et la nouvelle en vous appuyant simplement sur le numéro de version !

Quelle utilisation pour les bases de données orientées documents ? Par exemple lorsque vous voulez gérer des… documents (papier cette fois) : imaginez vouloir référencer des documents scannés, ils disposent alors de méta données (date du scan, nombre de pages, …) qui leur sont propres et qui sont susceptibles de fortement varier. Tous les documents ne devront pas nécessairement stocker toutes les meta données (on évite de stocker des valeurs nulles) et au cours de la vie du système, on sera potentiellement amené à ajouter de nouvelles meta données. Il sera donc difficile d’établir la liste des meta données à l’avance, les documents ne les renseigneront pas tous et il y a de forte chance qu’on soit amené à ajouter de nouvelles meta données au fur et à mesure. On reconnait donc là les avantages des bases de données NoSQL : leur souplesse et l’aspect « schema less ».

Qui sont les utilisateurs des bases de données orientées documents ? SAP, SourceForge, Forbes, entre autres ! Car ils rentrent parfaitement dans le cadre décrit plus haut : ils ont besoin de gérer des données hétérogènes, qui sont amenées à évoluer et en grande quantité.

Bases orientées graphs

Le dernier type de bases de données NoSQL que j’ai décidé de recenser est le plus atypique : les bases orientées graphs. Il s’agit d’appliquer la théorie des graphs (au sens le plus strict) : des noeuds (qui représentent les données) qui ont des relations vers d’autres noeuds. Un exemple ? Le noeud « Utilisateur » qui a des relations « est ami » avec d’autres noeuds utilisateurs. Vous allez me dire : « C’est ce que fait une base relationnelle non ? » et je vous réponds « oui, dans le principe, mais il y a plusieurs atouts ! » Lesquels ? Ceux des performances dans un premier temps : imaginez la complexité d’une requête et son temps d’exécution si vous aviez à trouver « les amis, des amis de mes amis » dans un système relationnel. Et bien avec une base orientée graph c’est très simple ! Il suffit d’écrire une requête telle que je l’ai formulée : « Donne-moi les noeuds qui ont une relation « est ami », avec les noeuds qui ont une relation « est ami » avec « moi-même »". Et c’est terminé ! Deuxième atout : encore une fois la souplesse. En effet, il est très simple de créer une nouvelle relation (pas de table de jointure à créer ou autre) : on recense une nouvelle liaison, on la nomme et on commence à lier les noeuds entre eux.

Quelle utilisation pour une base orientée graphs ? C’est beaucoup plus restreint que pour les autres types de bases de données NoSQL car cela va principalement tourner autour des relations entre utilisateurs (à la LinkedIn ou Facebook) ou de la gestion des réseaux telecom et/ou informatiques.

Et après ?

Nous arrivons à la conclusion de cette série d’articles ! Nous avons vu les grands concepts des bases NoSQL, en quoi elles diffèrent des bases relationnelles, et nous avons jeté un oeil sous le capot pour entrevoir à quel point elles étaient adaptées à un environnement distribué et reparti. Et maintenant ? Et bien je vais répondre à une question fondamentale : quand est-ce que je dois me diriger vers une base NoSQL ?! La suite au prochain épisode ;)

Mais c’est quoi le NoSQL ? Episode III : Sous le capot !

octobre 29, 2013 dans Architecture, NoSQL, Veille technologique par Cédric Millauriaux

Dans mon article précédent, j’ai opposé les caractéristiques des bases de données relationnelles à celles des bases de données NoSQL. J’ai alors conclu qu’il ne s’agissait pas tant d’un choix philisophique que d’un choix guidé par des besoins. Je vais maintenant vous montrer ce qui se cache sous le capot d’une base de données NoSQL, afin de vous préparer à l’ultime étape : « Est-ce que je dois ou non utiliser du NoSQL sur mon projet ? ».

Principes de base

Les principes de bases du NoSQL sont peu éloignés de ce que l’on connaît avec les bases relationnelles. Une structure hiérarchique décrit une organisation tout d’abord en « base de données », sous-entendu un ensemble de nœuds, formant un cluster, qui forme une seule et unique base de données, accessible via un port dédié. C’est donc une vision technique de la chose : un serveur de données offrant une interface de connexion. Au sein de cette base de données, évoluent des instances, qui forment un ensemble de données isolées des autres instances. Enfin, viennent les éléments atomiques de cette hiérarchie : les collections de documents ou familles de colonnes ou clés valeurs, qui posent un cadre pour pouvoir y entreposer des données. Jusque-là, il n’y a rien de surprenant et de nouveau par rapport à ce que vous connaissez.

C’est dans leur gestion des données que les bases NoSQL commencent à se distinguer. Notamment dans l’importance qu’elles donnent aux clés des données que vous désirez y entreposer. Chaque donnée doit être associée à une clé unique, représentée sous une forme primitive : il ne s’agit pas de gérer des clés composites ou autre. Cette clé a plusieurs vertues : elle permet d’identifier formellement une ligne ou un document et est indexée en mémoire. Ainsi, lors de la recherche d’un document ou d’une ligne, le moteur NoSQL doit seulement chercher dans sa mémoire vive la clé que vous lui avez fourni et il trouvera la référence où est stockée physiquement la donnée.

Cette manière de fonctionner est fondamentale dans l’approche qui doit être faite des moteurs NoSQL : il ne s’agit pas de modéliser ses données, puis d’imaginer les requêtes qu’on va pouvoir faire sur ce modèle. Il faut penser aux requêtes que l’on va effectuer et en déduire le modèle ! Si le but d’une famille de colonnes est de stocker la liste des amis d’un utilisateur, il ne s’agit pas de déterminer une clé arbitraire (comme ce que l’on peut voir avec les séquences des bases relationnelles), de stocker l’identifiant de l’utilisateur dans une colonne, l’identifiant de l’ami dans une autre et de penser ensuite à faire une requête du type « Retourne moi toutes les lignes ou la colonne « utilisateur » est égale à l’utilisateur passé en paramètre ». Hérésie ! L’identifiant de l’utilisateur devient la clé de la ligne et chaque ami est stocké dans une colonne. Ainsi on retourne directement la ligne dont l’identifiant est celle de l’utilisateur concerné, et c’est terminé.

Bien sûr, la plupart des systèmes NoSQL proposent de recourir à des index secondaires, qui vont permettre de référencer en mémoire d’autres attributs que la clé. Néanmoins, il faut utiliser ces index secondaires avec parcimonie : plus ils seront nombreux, plus ils surchargeront le système et moins les performances seront bonnes.

S’il y a une chose à retenir de cet article c’est bien cela : un moteur NoSQL gère ses données à l’aide d’une clé. Celle-ci doit être choisie avec attention et pensée pour répondre aux besoins des requêtes : c’est donc votre point d’entrée pour une base performante.

Architecture distribuée

L’un des atouts le plus important d’une base de données NoSQL, c’est sa conception qui est tournée vers les environnements distribués. La majorité des choix et des compromis propres aux moteurs NoSQL ont été faits pour favoriser ce fonctionnement. Comme nous l’avons vu avec le théorème CAP, le fonctionnement d’une architecture distribuée n’est pas sans inconvénient et à demandé aux concepteurs de bases NoSQL de réfléchir et de mettre en place des solutions pour palier les problématiques que l’on rencontre typiquement dans une architecture distribuée.

Maître/esclave vs sans maître

Dans une architecture distribuée, il faut faire un premier choix : identifier un maître ou prendre le parti de ne pas avoir de maître. Le principe maître/esclave est le plus facile à mettre en oeuvre : un maître joue le rôle de chef d’orchestres et les esclaves sont là pour le servir. Dans le monde NoSQL, cela se traduit par un maître qui fait office de point d’entrée pour toute opération et qui redirige ensuite la requête vers l’esclave le plus à même de traiter l’opération. Par exemple, le maître reçoit une demande d’ajout d’un utilisateur « Tux », il sait qu’un de ses esclaves est en charge de la gestion de la collection de documents « utilisateurs », il va alors lui pousser la requête et lui demander de la réaliser. Idem pour les problématiques de réplication ou de distribution de données. C’est ce mode de fonctionnement qui est le plus utilisé par les moteurs NoSQL actuels.

Avantage d’un système centralisé avec un maître ? Le maître reçoit les requêtes, connait ses esclaves et peut donc aiguiller les requêtes. Inconvénient ? Si le maître présente une défaillance, c’est tout le système qui est mis à mal ! Un paradoxe pour une architecture voulue comme distribuée.

Les systèmes sans maître présentent l’avantage de ne pas avoir de SPOF (Single Point of Failure) comme les systèmes centralisés mais rencontrent de nouvelles problématiques. Comment savoir vers quel nœud rediriger une requête ? Comment un nœud peut découvrir un autre nœud, étant donné qu’il ne s’enregistre pas auprès d’un maitre ?

Plusieurs solutions ont été imaginées et mises en places, par exemple le protocole de bavardage, qui permet de répandre une information de manière virale : chaque nœud communique l’information à ses voisins, qui font de même avec leurs voisins. De cette manière, si un nouveau nœud doit rejoindre le cluster, il communique sa présence à un nœud choisit aléatoirement, ce nœud va en informer ses voisins, etc. Au bout d’un certain temps, tous les nœuds connaîtront le nouvel arrivant. Idem pour la répartition des données : chaque nœud sait ce qu’il gère et le communique aux autres nœuds. Dans notre exemple précédent, le nœud qui gère les documents « utilisateurs » le communique par bavardage et de cette manière, si n’importe quel nœud reçoit une requête sur un utilisateur, il saura le rediriger vers le bon nœud.

Inconvénient de ce système ? Le bavardage prend du temps et ne permet pas de garantir qu’une information sera propagée rapidement à tous les nœuds.

Réplication

Afin de respecter la contrainte de résistance au morcellement, il est nécessaire de dupliquer les données d’un nœud vers d’autres nœuds. De manière à ne pas avoir besoin d’un espace considérable pour stocker ces sauvegardes, il est d’usage de ne recopier qu’une partie des données sur chaque nœud de sauvegarde. De cette manière, si un nœud qui détient des données vient à défaillir et n’est plus accessible, on peut reconstituer ses données en faisant appel aux sauvegardes partielles dont les autres nœuds disposent. En mettant en commun ces sauvegardes partielles, le système est capable de reconstituer l’intégralité des données qui étaient gérées par le nœud désormais inaccessible.

Sharding

Le sharding permet de partitionner les données. En effet, en tant que cluster, il s’agit d’éclater intelligemment les données et des les répartir sur les différents nœuds afin de tirer parti de tous les nœuds du cluster pour la gestion et le stockage des données. Le principe de sharding est un des fondements des moteurs NoSQL, mais est également connu et appliqué dans le monde relationnel. La différence est que pour l’utilisateur d’une base de données NoSQL, le partitionnement des données est automatique et transparent.

Répartition des données

Pour assurer une répartition intelligente des données à l’aide du processus du sharding, il est nécessaire de définir une stratégie. En effet, il faut pouvoir déterminer quel nœud doit stocker une donnée et quel nœud interroger pour la récupérer sans avoir besoin d’interroger tous les nœuds ou pire : de tous les parcourir ! Plusieurs algorithmes existent pour permettre de déterminer « mathématiquement » quel nœud a la charge d’une donnée en particulier.

La problématique de répartition est double : assurer que les données sont uniformément réparties sur tous les nœuds afin qu’un nœud ne soit pas surchargé par rapport aux autres, et assurer lors de l’insertion d’une nouvelle donnée que celle-ci ne remette pas en cause cette homogénité de répartition. Prenons un exemple trivial pour illustrer ce dernier propos : je choisis de répartir sur un noeud toutes les données, dont la clé, qui est le nom de l’utilisateur. Un noeud est en charge de stocker les données des utilisateurs dont le nom commence par « A ». Imaginons maintenant que je doive insérer un nombre important d’utilisateurs dans le nom commence par « A » : je vais déséquilibrer mon cluster car un noeud aura beaucoup plus de données à gérer que les autres. Si je veux rééquilibrer la répartition de mes données, je vais devoir faire quelque chose de dramatique pour les performances : déplacer toute une partie des données vers un autre noeud. C’est à tout prix ce que l’on veut éviter et c’est pourquoi les algorithmes sont pensés pour assurer une répartition uniforme et qui ne sera pas remise en question suite à un afflux massif de données.

Un des algorithmes « simple » pour palier ce problème est par exemple, de faire un « hash » de la clé des données, ce qui nous retournera un nombre sur 32bits. Le système effectue alors un modulo sur ce hash et le nombre de noeuds, ce qui nous donnera le noeud sur lequel stocker/requêter la donnée. De cette manière, on assure une répartition uniforme des données et on se prémunit contre le phénomène décrit précédemment.

Cohérence des données

Nous avons vu dans l’article précédent que les bases de données NoSQL n’assuraient pas l’ACIDité des transactions. Il y a donc un risque de trouver notre système dans un état où les données ne sont pas cohérentes. De plus, le choix fait par un moteur NoSQL d’implémenter uniquement deux des trois composantes du théorème CAP, fait que le système se retrouve forcément pendant un cours laps de temps dans un état instable. La problématique se situe donc au niveau du nœud, qui va recevoir au fur et à mesure des événements en provenance du maître (ou d’un autre nœud dans un système sans maître). Mais dans un système décentralisé, que faire quand un nœud reçoit plusieurs demandes de mises à jour de la même donnée simultanément de la part de plusieurs nœuds ? Un système qui se base sur une architecture sans maître va donc implémenter un mécanisme (horodatage, numéro de version) qui va permettre de déterminer quelle est la donnée la plus récente et donc laquelle prendre en compte.

Et après ?

Nous avons vu dans cet article que le fonctionnement des bases de données NoSQL est surtout organisé autour de la mise en cluster et des problématiques qui en découlent. La compréhension de ces problématiques permet de mieux comprendre comment manipuler ces bases de données particulières, la réflexion à avoir lors de la conception du modèle de données et enfin les limites des moteurs NoSQL.

Dans mon prochain article, nous allons aborder les différents types de bases de données NoSQL, leurs caractéristiques et pour quels usages les utiliser.

Spring Data et MongoDB : Présentation

octobre 22, 2013 dans Java, MongoDB, NoSQL, Spring, Spring Data par Cédric Millauriaux

Cet article initialise une nouvelle série sur le thème « Spring Data et MongoDB ». Je vais tenter de vous faire comprendre les avantages de l’utilisation d’une base de données NoSQL orientée documents, mais aussi de vous démontrer qu’il est très simple de travailler avec une telle base, à partir du moment où l’on dispose des bons outils. Enjoy !

Avant toute chose, je vous recommande la lecture de mon article « Mais c’est quoi le NoSQL ? » pour comprendre ce qui se cache derrière ce terme que l’on entend souvent ces derniers temps.

MongoDB

MongoDB est la base de données NoSQL orientée documents la plus populaire ces temps-ci (si on suit le classement de http://db-engines.com/en/ranking, elle est classée 6ème BDD la plus utilisée, tout type confondu et la plus utilisée des BDD NoSQL). C’est aussi une des plus anciennes (sa genèse date de 2007) de ce type et elle est forte d’une communauté très active.

MongoDB permet de stocker des données dans des documents, c’est-à-dire une liste de clés/valeurs dont la structure n’est pas nécessairement la même d’un document à l’autre, au format BSON (du JSON binaire). Par exemple, si l’on prend une collection de documents « utilisateurs », on peut retrouver dans le document « Utilisateur 1 » un pseudo, un nom et un prénom et pour le document « Utilisateur 2 » un pseudo, une adresse mail, un numéro de téléphone et une adresse. Avantages : c’est très souple et ça ne demande pas de lourdes migrations de la BDD quand on désire changer la structure de nos données. Une seule contrainte : il faut nécessairement à MongoDB un identifiant unique pour pouvoir différencier un document d’un autre.

Au niveau des requêtes, MongoDB utilise nativement le javascript. Bien sûr, des drivers existent pour tous les langages populaires (C, C++, Java, etc.) afin de permettre une communication native. Par exemple, pour retourner tous les documents de la collection « utilisateurs », on lance la commande « db.utilisateurs.find(); » dans l’interpreteur de commande de mongodb.

Enfin, je rebondis sur mon article sur le NoSQL en ventant l’architecture de ces bases de données : rien de plus simple que de monter un cluster permettant d’absorber une charge et un volume de données de plus en plus importants (l’elasticité est votre allié !). MongoDB ne déroge pas à la règle et propose de pouvoir monter rapidement et simplement un cluster où les données seront redondées et servies dans un temps record.

Alors pourquoi MongoDB ? C’est vrai il en existe d’autres dont la qualité et la popularité ne sont pas à démontrer : CouchDB et CouchBase pour ne pas les nommer. Et bien parce que c’est une BDD NoSQL orientée documents très mure, bien documentée et supportée par des projets tels que Spring Data. Et c’est ce qui va nous intéresser ici.

Spring Data

Spring Data est un framework qui permet la communication et l’échange avec une base de données en abstrayant un certain nombre de notions et surtout, en permettant une conversion de votre modèle objet vers le modèle de la base de données (relationnelle ou documents par exemple) et vice versa. C’est ce que l’on appelle vulgairement un ORM (Object Relational Mapper) dans le monde du relationnel (oui, comme Hibernate).

Spring Data va également permettre d’abstraire le requêtage de la BDD par l’utilisation d’API objets : plus question d’écrire les requêtes (SQL/HQL/JS) dans des chaînes de caractères, on va ici pouvoir utiliser des factory permettant d’ajouter des opérations de restriction, de sélection, etc.

Enfin, Spring Data permet de communiquer avec des bases de données relationnelles, des bases de données NoSQL orientées documents, orientées colonnes, des entrepôts clés/valeurs, etc. Dernier argument : le framework est parfaitement intégré à l’écosystème Spring, massivement utilisé dans nos applications Java et dont l’utilité n’est plus à démontrer.

Et maintenant ?

Le but de cette série d’articles est d’écrire un programme java, capable d’entreposer et de récupérer des données issues d’un modèle objet dans MongoDB. Mais en gardant un code compact et en faisant appel à des outils simples d’utilisation. Vous allez comprendre que travailler avec une base de données NoSQL n’est pas plus compliqué que de travailler avec un bon vieil Oracle ou Postgres.

Un GitHub pour le blog IcySoft

octobre 18, 2013 dans Vie du site par Cédric Millauriaux

Et hop, on se met dans la tendance ! L’équipe du blog vient d’ouvrir un GitHub pour son site. Vous y retrouverez tous les exemples issus des articles que nous publions. Le but ? Vous proposer des projets complets que vous pouvez lancer depuis votre IDE préféré afin de comprendre au mieux nos articles. Avis aux contributeurs : vous avez des corrections, des suggestions à apporter ? Alors faites vous plaisir : tous nos exemples sont sous licence Apache et peuvent librement être forkés, modifiés, redistribués etc. Une seule contrainte : on indique que ça vient de chez nous ;)

 

Pour visiter le GitHub du blog Icysoft, une seule adresse : https://github.com/icysoft/blog-examples

Jersey par la pratique : WebServices REST en Java – Création d’un service Jersey

mai 4, 2013 dans Java, Jersey, Jetty par Cédric Millauriaux

Dans l’article précédent, nous avons vu comment créer et préparer un projet Java pour y exposer des services web REST grâce à Jersey.

Ici, nous allons mettre en place notre premier service et découvrir les fonctionnalités offertes par l’API Jersey.

Créer une classe de services

Dans un premier temps, nous créons une classe « TestService ». Nous allons ensuite décorer la classe avec l’annotation « @Path », qui va permettre de définir une partie de l’URI qui permettra aux clients de contacter le webservice. C’est la seule annotation requise pour permettre à Jersey de considérer une classe comme étant un service.

@Path("test")
  public class TestService {
}

Créer un service

Nous allons maintenant créer une première méthode « sayHello » qui ne prendra aucun paramètre et se contentera de renvoyer une chaîne de caractères « Hello ».

Voici le prototype de la méthode ainsi que son implémentation. Vous remarquez qu’il n’y a aucune différence avec une méthode classique, que vous pourriez appeler dans n’importe quelle classe Java.

public String sayHello() {
  return "ok";
}

Nous allons maintenant décorer cette méthode pour permettre à Jersey de lui associer une URI et de définir quelle méthode (au sens commande HTTP) utiliser pour traiter la requête et la réponse du client.

  • « @Path » qui comme pour la classe, permet de définir une partie de l’URI (ici le dernier élément) qui sera exposée aux clients
  • « @GET » ou « @POST » qui définit la méthode HTTP utilisée. Cette annotation est capitale car elle va conditionner la façon dont les clients vont communiquer avec votre webservice. Si l’on respecte la RFC2616 (qui définit le protocole HTTP), on doit utiliser la méthode « GET » lorsqu’une requête ne modifie pas l’état du système (on interroge uniquement le système), alors que la méthode « POST » ne renvoie pas de données métier mais va modifier l’état du système. Il existe d’autres méthodes HTTP qui nous permettraient de coller au plus près au standard, mais nous nous contenterons ici d’utiliser ces deux méthodes.
  • « @Produces »/ »@Consumes » qui définit le format d’échange qui sera utilisé pour communiquer avec le client. Vous pouvez vous rendre sur cette page pour connaitre l’ensemble des formats proposés. Nous retiendrons ici deux formats : « TEXT_PLAIN » et « APPLICATION_JSON ».

Pour notre méthode « SayHello », nous désirons être interrogé par la méthode « GET » , produire du texte simple et ne prendre aucun argument en paramètre. La méthode se présente alors sous la forme suivante :

@Path("keepalive")
public class TestService {
  @GET
  @Path("/sayHello")
  @Produces(MediaType.TEXT_PLAIN)
  public String sayHello() {
    return "Hello";
  }
}

Configurer le serveur d’applications

Avant de pouvoir tester notre webservice, il faut configurer celui-ci, par l’intermédiaire du fichier « web.xml », afin d’y enregistrer la servlet Jersey et de mapper cette servlet vers une URI.

Ouvrez le fichier « web.xml » présent dans le répertoire  »src/main/webapp/WEB-INF/ » et ajoutez le code suivant entre les balises « <web-app> » et « </web-app> » :

<servlet>
  <!-- Nom de la servlet qui traitera les appels aux webservices -->
  <servlet-name>rest.service</servlet-name>
  <!-- Classe de la servlet Jersey -->
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <!-- Package racine ou se trouve les services, la servlet va découvrir toutes les classes annotées avec l'annotation "@Path" présents dans ce package et ses enfants -->
    <param-value>fr.icysoft.blog.exemple.jersey.services</param-value>
 </init-param> 
 <load-on-startup>1</load-on-startup> 
</servlet>

Il faut ensuite ajouter les lignes suivantes afin de mapper la servlet avec une URI racine. Cette URI, concaténée avec les URI qui décorent la classe, puis celles qui décorent chaque méthode, permet de définir l’adresse exposée aux clients.

<servlet-mapping>
  <servlet-name>rest.service</servlet-name>
  <!-- Renseigner ici l'URI racine désirée -->
  <url-pattern>/service/*</url-pattern>
</servlet-mapping>

Tester le service

Lancez l’application en exécutant le build Maven avec pour cible « jetty:run ». Si la ligne « [INFO] Started Jetty Server » s’affiche dans la console et qu’aucune trace d’erreur n’est présente, le serveur est correctement démarré. Dans le cas contraire, n’hésitez pas à nous faire part de votre problème dans les commentaires, nous y répondrons au plus vite ;)

Dans un navigateur, saisissez l’adresse suivante : « localhost:8080/jersey/service/test/sayHello ». Le texte « Hello » devrait alors s’afficher.

jersey - hello

 

Nous avons vu dans cet article comment mettre en place un webservice simple avec Jersey. Nous verrons dans un prochain article comment passer des paramètres à nos services et comment convertir des objets Java en objets JSON et vice versa.

Jersey par la pratique : WebServices REST en Java – Création d’un projet et configuration

mai 1, 2013 dans Java, Jersey, maven par Cédric Millauriaux

Suite au précédent article présentant l’API Jersey, passons à la pratique !

Nous allons ici créer un projet Java, qui utilise l’API Jersey afin d’exposer des WebServices REST, fournissant des messages JSON. Nous utiliserons l’IDE Eclipse Juno ainsi que Apache Maven pour la gestion des dépendances. Le serveur d’applications Jetty nous servira à déployer notre application et exposer nos services web.

Initialisation du projet avec Maven

Dans Eclipse, créez un nouveau projet Maven (File -> New -> Maven Project). Sélectionnez l’archetype « maven-archetype-webapp » (org.apache.maven.archetypes) afin de créer la structure d’une application web. Renseignez ensuite les paramètres de l’archetype pour générer la structure de votre projet.

jersey - archteype

Une fois le projet généré, il est nécessaire d’ajouter un répertoire de source « src/main/java » afin d’y placer les futurs services (Clic droit sur le projet -> New -> Source Folder -> Folder name = src.main.java).

Ajout des dépendances

Notre projet est maintenant prêt à recevoir l’API Jersey. Nous allons ajouter les dépendances requises dans le fichier pom.xml, présent à la racine du projet.

Ajoutez les dépendances suivantes entre les balises « <dependencies> » et « </dependencies> » :

 <!-- Jersey (JAX-RS) -->
  <dependency>
   <groupId>com.sun.jersey</groupId>
   <artifactId>jersey-server</artifactId>
   <version>1.17.1</version>
  </dependency>
  <dependency>
   <groupId>com.sun.jersey.contribs</groupId>
   <artifactId>jersey-spring</artifactId>
   <version>1.17.1</version>
  </dependency>
  <dependency>
   <groupId>javax.ws.rs</groupId>
   <artifactId>jsr311-api</artifactId>
   <version>1.1.1</version>
  </dependency>
  <dependency>
   <groupId>com.sun.grizzly</groupId>
   <artifactId>grizzly-servlet-webserver</artifactId>
   <version>1.9.56</version>
  </dependency>

Le fichier pom.xml complet est disponible ici.

Nous allons également ajouter le plugin Jetty afin de pouvoir lancer notre application directement en saisissant la cible « jetty:run ». Ajoutez le plugin suivant entre les balises « <build> » et « </build> » :

<plugins>
  <plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
  </plugin>
</plugins>

Tester la configuration

La configuration de notre projet est maintenant terminée ! Un petit test afin de vérifier son fonctionnement. Cliquez droit sur le projet et selectionnez le sous-menu « Run As » puis « Maven Build… ». Dans le champ « Goal », saisissez « jetty:run ».

Vous devriez voir alors des logs défiler dans la console. Si vous obtenez la ligne « [INFO] Starting jetty 6.1.26 … » puis « [INFO] Started Jetty Server », c’est gagné ! Si cela ne fonctionne pas, vous pouvez bien sûr nous laisser un commentaire, nous répondrons à toute demande :)

jersey - console

Enfin, dans un navigateur, tapez l’adresse « http://localhost:8080/jersey » et vous obtiendrez le fameux Hello World !

La suite ?

Dans notre prochain article, nous verrons comment configurer Jersey et nous créerons notre premier service !

Jersey par la pratique : WebServices REST en Java – Présentation

mai 1, 2013 dans Java, Jersey par Cédric Millauriaux

Comme nous l’avons vu dans l’article précédent, REST est une architecture et non un protocole d’échange. L’amalgame est souvent fait entre WebServices et le protocole d’échange SOAP, mais il faut garder à l’esprit qu’un service web peut s’appuyer sur un grand nombre de formats.

Dans notre cas, nous souhaitons faire appel aux services via des pages web composées de JavaScript, des applications mobiles, ou même pour de la communication entre serveurs d’applications. Pour certaines de ces plateformes, il peut s’avérer complexe d’écrire ou de lire des flux XML. Nous décidons donc de nous tourner vers le format JSON, bien connu des développeurs JavaScript. La difficulté devient alors de faire communiquer nos services, écrits en langage Java, en JSON. Nous pourrions imaginer des convertisseurs manuels, mais la fiabilité et le temps nécessaire pour développer ces outils seraient trop importants. De même, si le besoin de communiquer dans un autre format apparaît, il serait alors nécessaire de réécrire l’ensemble de ces outils.

C’est ici qu’intervient l’API Java Jersey. Celle-ci propose une implémentation de JAX-RS, permettant la création de WebServices REST codés en Java par l’utilisation d’annotations.

Un des avantages de Jersey est que l’API est capable de communiquer avec de nombreux formats d’échange (XML, plain text, …) et notamment le format JSON qui nous intéresse ici.

Voici un exemple de service REST permettant l’ajout et la suppression d’un article (pour un blog par exemple) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Path("/articles")
public class UserServiceImpl extends IJerseyService {
  @GET
  @Path("/getArticle")
  @Produces(MediaType.APPLICATION_JSON)
     public Article getArticle(@QueryParam("id") long id) {
     return this.articleDataStore.getAnecdote(id);
  }
  @POST
  @Path("/addArticle")
  @Consumes(MediaType.APPLICATION_JSON)
  public synchronized Response ajouterArticle(Article art) {
    this.articleDataStore.ajouterArticle(art);
    return Response.ok().build();
  }
}

Nous reviendrons plus précisément sur l’écriture de WebServices avec Jersey dans un prochain article. Voici ce qu’il faut retenir de l’exemple précédent, et qui montre le potentiel de Jersey :

  • La classe Java est précédée par l’annotation « @Path » qui permet de renseigner l’URI par laquelle seront mappés les différents services. Cette URI sera complétée par la valeur de l’annotation « @Path » qui précède chaque méthode de la classe
  • Chaque méthode est précédée par l’annotation « @GET » ou « @POST », cela permet de renseigner la méthode (au sens transport) qui sera utilisée par la requête et la réponse
  • Les paramètres passés dans une requête sont mappés avec les paramètres de la méthode cible grâce à l’annotation « @QueryParam(ID_PARAMETRE) »
  • Lorsqu’un objet Java est retourné, Jersey le convertit automatiquement en objet JSON. Pour cela, la classe de l’objet renvoyé doit être décorée de l’annotation « @XmlRootElement »
  • Un objet Response peut être renvoyé afin de gérer les codes définis par la norme HTTP (403, 404, etc.)

Pour conclure, l’utilisation de Jersey est simple, par l’utilisation d’annotations et n’alourdit pas le code. De plus, l’API répond parfaitement au besoin en permettant de communiquer avec les clients dans un grand nombre de formats.

Pourquoi utiliser des WebServices REST ?

mai 1, 2013 dans Architecture par Cédric Millauriaux

Cet article est né pour répondre à une question simple, qui se pose régulièrement en amont d’un projet : Comment écrire des interfaces client, codées dans des langages hétérogènes, qui se basent sur des appels asynchrones à un serveur codé en Java ?

Nous voyons se multiplier depuis quelques années les projets se basant sur une architecture de type REST. Cette architecture permet la communication entre un client et un serveur, de manière déconnectée et en séparant l’interface utilisateur du moteur de l’application. Ce style d’architecture s’inscrit parfaitement dans notre démarche de pouvoir écrire des applications possédant une interface client riche, tout en maintenant une corrélation minimale entre le client et le serveur et en ne disposant que d’un seul protocole de communication pour tous les clients.

Comment fonctionne un service web REST ? Tout repose sur le protocole HTTP : le serveur expose des URI, mappées sur un traitement. L’appel à l’une de ces URI déclenche l’exécution du traitement et renvoie une réponse au client. Chaque requête est indépendante des autres, il n’y a donc pas de notion d’état en architecture REST. Le choix de cette architecture prend tout son sens lorsqu’il s’agit de développer des applications web riches et/ou mobiles, qui doivent communiquer à travers le réseau Internet avec le serveur, qui sont écrites dans des langages différents et qui ne font pas appel à des notions telles que les sessions « Stateful ».

Les avantages de cette architecture sont nombreux :

  • S’appuie sur le protocole HTTP
  • Adapté aux environnements distribués
  • Interoperabilité
  • Léger
  • Facile à implémenter
  • Produit des résultats lisibles par un humain
  • Une URI représente un service

L’architecture REST répond donc parfaitement à notre besoin de disposer de services interopérables hébergés sur des environnements distribués et faciles à implémenter.

par IcySoft

Bienvenue !

mai 1, 2013 dans Vie du site par IcySoft

Bienvenue sur le site d’IcySoft.

Nous sommes une équipe de développement amateur, composée de professionnels de l’informatique, réunis autour de leurs passions : les nouvelles technologies et le développement.

Nous souhaitons développer ce site en y ajoutant des tutoriels, des articles et des news sur les technologies utilisées dans nos projets.

Bonne visite !