Archive

Posts Tagged ‘experience’

Utilisation de MongoDB chez Hot Potato

juillet 2, 2010 1 commentaire

[Traduction autorisée de « Hot Potato Infrastructure: MongoDB », publié sur le blog d’Hot Potato par lincolnh le 5 mai 2010.]

Chez Hot Potato, nous utilisons MongoDB depuis 6 mois avec de grands résultats.

J’ai le sentiment que le positionnement de Mongo, parmi les technologies de stockage, est assez unique et correspond bien à ce que nous faisons. Les choses que j’apprécie particulièrement de Mongo sont:

  1. Très bonne documentation et excellent support. L’équipe Mongo soutient réellement la communauté et va jusqu’au bout pour aider les personnes à résoudre leurs problèmes. Voyez par vous même sur le groupe utilisateur ou le channel IRC #mongodb.
  2. La base de données ainsi que les drivers spécifiques à chaque langage sont open source.
  3. Le stockage sans schéma rend les choses simples et flexibles.
  4. Support très complet des requêtes ad hoc (NdT: requêtes assemblées à l’exécution).
  5. Mongo est rapide et supporte un large choix d’opérations atomiques.
  6. Utlisation de Map/Reduce (NdT: principe consistant à d’abord agréger les données à traiter, autrement dit « mapper », puis à les filtrer, soit les « réduire ») pour l’agrégation.
  7. L’administration est vraiment simple et utilise une interface très complète en ligne de commande, avec support natif du JavaScript.
  8. Conçu pour la montée en charge.

Beaucoup d’autres personnes sont également impressionnées par Mongo et ont écrit à ce sujet:

Cependant, personnellement, je ne pense pas que la capacité de Mongo à monter en charge ait suffisamment retenue l’attention. Par montée en charge, j’entends le processus d’optimisation graduelle pour plus de charge au cours du temps, au fur et à mesure que vos schémas et cas d’utilisations sont découverts et évoluent. Les fonctionnalités de Mongo et leurs interactions sont attirantes car souples et capables de s’adapter aux changements, tout en permettant, toujours, une montée en charge simple et efficace, sans prise de tête. C’est particulièrement utile dans les start up, mais certainement applicable à tout projet où les spécifications sont peu claires.

Prenez par exemple quelques étapes typiques qui doivent être suivies pour permettre à une base de données relationnelles (BDR) de monter en charge:

  1. A un certain moment, votre application commence à montrer des signes de faiblesse et la première chose que vous remarquez est que vous êtes écrasé par les lectures. Comme les temps de réponse de votre application ne doivent pas être instantanés, vous ajoutez une couche de cache externe, devant votre BDR – quelque chose comme memcached. Bien que plus compliqué, avec un grand nombre de lectures, vous pouvez aussi opter pour des esclaves en lecture seule.
  2. Bien que généralement les applications web ont un ratio lecture/écriture élevé, après avoir optimisé vos lectures, à un certain point, les opérations d’écriture commencent à poser un problème. En réponse, vous augmentez verticalement votre matériel, en termes de processeurs, mémoire vive et entrées/sorties. Cette étape est souvent couteuse.
  3. Même avec votre cache frontal et/ou vos esclaves en lecture seule, au fur et à mesure de la montée en charge, vous remarquez que de nombreuses lectures prennent plus de temps que vous ne le voudriez et sont généralement trop couteuses. Vous ne voulez pas ajouter du matériel ad eternam pour résoudre votre problème alors que vous savez que votre application pourrait encore être optimisée. Aussi, vous commencez à dé normalisez vos données. Au début, vous copiez stratégiquement de petites quantités de données pour éviter les jointures. Toutefois, avec le temps et la charge croissante, vous finissez par suivre cette route bien plus loin que prévu, dé normalisant de partout et éliminant toujours plus de jointures. En cours de route, vous ne cessez de modifier vos définitions de table et devez gérer les complications induites.
  4. Vous avez optimisé les lectures et les écritures, mais vous continuez à monter en charge. Vous constatez que la charge de vos machines accueillant votre BDR augmente de façon inquiétante. En réponse, vous éliminez autant de logique que possible de la base de donnée, tuant autant de triggers et de procédures stockées que possible. Parallèlement, vous pré matérialisez vos requêtes les plus complexes, qui, du fait de leur complexité, ont résisté à toutes vos tentatives de dé normalisation.
  5. Enfin, mais non des moindres, il se peut que les écritures commencent à être des goulets d’étranglement, même avec du matériel dopés aux hormones. A ce moment là, vous pouvez tenter de partitionner horizontalement vos données. Ceci n’est pas, pour la plupart des moteurs relationnels, géré de façon transparente par la base de données. Il faut donc gérer la chose depuis votre application. Ou vous supprimez vos index secondaires. Vous commencez alors à construire et gérer vos propres index secondaires, là où ils sont requis. A ce moment là, votre application doit être plus intelligente sur quand et comment accéder ses données.

La fin de partie de ce petit jeu est que, au final, vous utilisez vos données comme des paires clés/valeurs. Malheureusement, désormais, les fonctionnalités, structures, relations et les transactions d’une BDR sont autant d’obstacles. Des choses comme la rigidité du schéma ou les transactions ne font qu’ajouter du poids mort à chaque opération, même si la majorité, voir toutes, ne font désormais plus appel à ces fonctionnalités.

Comparons maintenant ce processus avec l’équivalent lorsqu’on travaille avec Mongo.

  1. Avec Mongo, pour commencer, les lectures sont sacrément rapides. Elles peuvent bien sûr être cachées de façon externe comme avec une BDR, mais d’après notre expérience cela tend à venir bien plus tard quand on utilise Mongo. Pourquoi ? Mongo utilise des fichiers stockés en mémoire, vous pouvez donc jeter de la RAM à votre instance Mongo et votre OS l’utilisera de façon efficace pour cacher les données. Aussi, même si vous en arrivez là, ce n’est pas un désavantage en soi de Mongo. De plus, Mongo a été construit depuis le début pour supporter le sharding (NdT: partitionnement en fonction des lignes et non des colonnes, chaque ligne pouvant être sur une machine différente, permettant lectures et recherches parallèles sur de plus petites unités), qui devrait être prêt pour la production d’ici peu. Ainsi, parallèlement à un ajout de RAM ou de cache frontal, vous pouvez faire des partitions horizontales et répartir vos lectures sur plusieurs machines.
  2. Pour les écritures, Mongo est également, d’entrée de jeu, sacrément rapide, vu que les transactions et autres niveaux d’isolations ne sont pas supportés. De plus, comme solution complémentaire à la montée en puissance matérielle, le sharding vous permet de monter en charge horizontalement d’une façon prévue par la base de données. L’application n’a pas à se soucier de la chose, il suffit de choisir les bonnes clés de partitionnement.
  3. Mongo ne fait jamais de jointure car elles ne sont pas supportées. Cela peut être vu comme un inconvénient. De l’autre côté, vu que Mongo est sans schéma, il est très facile de copier des données de ci de là et de découvrir graduellement la meilleure structure. Et chemin faisant, pas de mise à jour, modification et gestion (avec retour arrière occasionnels) de votre schéma, car il n’y en a pas.
  4. Map/Reduce est l’outil de Mongo pour la démarche d’optimisation consistant à pré matérialiser. L’aspect sympa est que les opérations de map/reduce sauce Mongo peuvent utiliser le sharding de la même façon que des lectures ou écritures classiques. Les batchs map/reduce s’exécuteront donc en parallèle et pourront ensuite être combinés. C’est la raison pour laquelle Mongo exige que le mapping et la réduction retournent la même structure. Faire tourner périodiquement une fonction de map/reduce est ainsi une façon très souple et performante de pré matérialiser vos requêtes et de pré agréger vos données.
  5. Enfin, Mongo supporte les indexes secondaires tout comme une BDR. En général, le même processus d’optimisation d’index peut s’appliquer avec Mongo qu’avec une BDR. Soit de les supprimer graduellement au cours du temps une fois que les changements de votre application permettent de faire sans. Comme Mongo est sans schéma, les changements qui résultent nécessairement de cette démarche de suppression/restructuration peuvent se faire sans se soucier de la définition du schéma et des éventuels retours arrières. De plus, les index sont également shardés. La FAQ de Mongo à propos de sharding aborde les détails, mais, sommairement, vu que les clés des shards déterminent quels shards une requête va accéder si votre index contient une clé de shard, alors vous pourrez mettre en oeuvre des requêtes qui:
    • impactent le minimum requis de shards,
    • obtiennent leurs données directement d’un index de ces shards.

J’aime les compromis de Mongo entre les fonctionnalités des base de données relationnelles et les structures clés/valeurs. Cela permet une montée en puissance graduelle sans nécessiter de connaissance préalable sur la façon exacte dont votre application va fonctionner. Et le partitionnement horizontal n’y est pas une verrue ou une rustine à posteriori.

Si vous voulez en savoir plus à propos de Mongo et rencontrer des personnes qui l’utilisent, vous devriez considérer d’assister à MongoNYC (NdT: événement passé au moment où je traduis ces lignes, mais Mongo propose régulièrement des événements, notamment en Europe). Vous pouvez utiliser le code « hotpotato » à l’enregistrement pour une réduction de 25%. J’y serai aussi, passez donc me dire bonjour.

Étiquettes : , , ,
%d blogueurs aiment cette page :