L’organisation des flux au sein de CASSANDRA (Commitlog, Ecriture, Lecture, Replication…) est le mortier des fondations du SGBD. Vous avez été nombreux à me demander quelques explications sur le fonctionnement interne de CASSANDRA ainsi que la stratégie à adopter pour déployer un cluster de plusieurs noeuds. Il y a certaines zones d’ombres qui me reste à étudier (les relations entre «JVM» <=> «Commitlog» <=> Réplication) pour une parfaite compréhension du workflow d’enregistrement de la data et de sa réplication au sein d’un cluster. Si vous avez des précisions à apporter à ce billet ou même des corrections, vos recommandations et notes seront très très appréciés.

    Les flux dans CASSANDRA peuvent être séparés en deux grandes catégories à savoir :

  • Flux datas : enregistrement et lecture de la donnée,
  • Flux de services : communication entre les noeuds, gestion du partitionnement, stratégie de la réplication.

Nous allons aborder dans ce billet les flux datas : écriture et lecture de la donnée.

Workflow d’écriture de data dans CASSANDRA

Le workflow d’écriture de la donnée dans CASSANDRA est centrale et c’est l’une des forces de ce SGBD NOSQL. En effet, nous allons voir que le design adopté, rend l’écriture de la donnée très véloce.

    Enregistrer une donnée dans CASSANDRA, c’est faire intervenir 4 mécanismes principaux :

  • Ecriture de l’évènement : «Commitlog»,
  • Mise à disposition de la donnée le plus vite possible : «Memtable»,
  • Déclenchement du mécanisme qui rend la donnée consistante dans le temps : «SSTable»,
  • Ranger et Optimiser : «Compaction».

Les «commitlog» ou journalisation des évènements dans CASSANDRA

Le rôle des «commitlog» dans CASSANDRA, est de garantir que la donnée reçue par le cluster ne sera pas perdue. CASSANDRA, par ce mécanisme, dispose d’un système dit de «crash-recovery». Les «commitlog» sont enregistrés dans des fichiers binaires et représentent une période dans le temps. Lorsqu’un segment est plein, une rotation est effectuée et un nouveau segment est créé. Ils ont une taille identique (commitlog_segment_size_in_mb) et sont rangés dans un répertoire déterminé par la directive de configuration «commitlog_directory».

    Le gestionnaire propose deux systèmes pour garantir la validité et la pérennité de la donnée :

  • «Périodique»,
  • «Batch processing».

Par défaut, le mode périodique (commitlog_sync) est activé. Il permet d’avoir une mise à disposition de la donnée pour le client très rapidement. Il traite les évènements d’écriture par flux (au fur et à mesure) et rend la main au client. La donnée est réputée disponible même ci cette dernière n’a pas été écrite sur un disque. Il n‘ y a donc aucune garanti que la donnée ne sera pas perdu en cas de crash. Dans le contexte d’un cluster, on joue sur le mode de réplication pour éviter le problème.

Les «commitlog» pour être réputés immuables et garantir ainsi la persistance de la donnée sur un rejoue (en cas de crash), doit être écrite sur le disque : c’est le rôle du «sync» périodique. Cet intervalle régulier est configurable par la directive «commitlog_sync_period_in_ms» (10 secondes par défaut : valeur en milli seconde).

Le traitement «batch», traite les «commitlog» par lot. Tant que le lot n’a pas atteint une certaine taille, et qu’il n’ait pas été écrit sur le disque, la donnée n’est pas disponible. Le risque de perte de la data n’est pas le même mais permet de ne pas charger les IO du sync ! Le choix entre les deux va donc dépendre de la fréquence des enregistrements et de la volumétrie rencontrée. C’est pourquoi le mode «périodique» est le plus adapté car il offre un certain compromis entre disponibilité et persistance : persistance pouvant être améliorée avec une stratégie de réplication.

Comme nous venons de l’expliquer, le mécanisme de gestion des «commitlog» est très important et constitue le moteur de notre fusée CASSANDRA. Pour améliorer les performances, il est recommandé d’y dédier un périphérique de stockage. Il est intéressant de créer un disque de type mémoire pour augmenter la rapidité des écritures. Un périphérique mémoire est par nature beaucoup plus rapide qu’un disque classique. Le problème de cette solution est que les «commitlog» ne sont pas persistants en cas de crash du serveur qui héberge le noeud. Pour palier à ce problème, on peut mettre en place un mécanisme «système» pour faire une sauvegarde physique a posteriori via un rsync. On déporte le problème mais on permet d’améliorer très sensiblement la rapidité d’écriture.

Lorsque l’on démarre un noeud, CASSANDRA contrôle que les évènements ont bien été tous joués. Attention à la notion de «disponibilité» ou de «CONSISTENCY» d’une donnée fraichement écrite. Il ne faut pas confondre «CONSISTENCY» avec le facteur de «REPLICATION», même si ces deux notions sont frottements couplées.

    La donnée sera réputée écrite (accessible en lecture) dès lors que cette dernière sera :

  • enregistrée dans le second étage de la fusée CASSANDRA : les «Memtables»,
  • et que les «commitlog» seront écrits sur le périphérique de stockage. Le sync périodique libère le post traitement et la donnée va être répliquée sur les autres nodes.

Les «Memtable» : Rendre la donnée disponible en lecture le plus vite possible

L’objectif est de rendre disponible la donnée en lecture le plus vite possible tout en garantissant une rapidité dans le processus d’écriture. Le goulot d’étranglement identifiable sera clairement lié aux I/O disque. Pour éviter cet engorgement, la JVM va propulser la donnée dans une table de type mémoire appelée «Memtable». Grâce à ce design technique, la vitesse d’écriture est rapide tout en permettant une lecture véloce. Par contre, ce mécanisme ne garantit pas, du moins pas encore, la persistance de la donnée au sein du cluster.

    Posons nous trois questions ! :

  • Quel est le risque que l’architecture technique tombe ?
  • Si cette dernière tombe, quel sera le volume de données perdues ?
  • Si de la data est perdue : est ce que cela est acceptable d’un point de vue business ? par exemple : perdre quelques données pour le calcul d’agrégats à partir d’une volumétrie dite «Big Data» est-elle acceptable ?

Répondre à ces trois questions, c’est calculer un niveau de risque. Anticiper et accepter ce risque c’est vous permettre de choisir ou pas, un montage technique ou les «commitlog» sont aussi montés sur des disques de type mémoire.

Penchons-nous un instant sur le processus de récupération de la donnée pour expliquer celui de l’écriture identifiable par les trois workflow suivants :

  • Passage de la réception de la donnée au «commitlog»,
  • Passage du «commitlog» à la «Memtable»,
  • Passage de la «Memtable» à la «SSTable».
  • La récupération de la donnée est un processus mettant en oeuvre plusieurs briques techniques dans «CASSANDRA». Comprendre l’enchainement de ces derniers permettent d’appréhender ceux mis en oeuvre pour l’écriture. Si vous avez des précisions à apporter à ce qui suit, n’hésitez pas en m’en faire part !.

    Supposons que nous venons de créer une nouvelle entrée dans une CF «test» et que nous faisons une requête de sélection sur cette même clef. Le mécanisme de cache d’indexation «bloom filters» retournera «false». Ce mécanisme permet en effet de savoir si une clef existe ou pas au sein de «CASSANDRA». Tant que la «Memtable» n’aura pas été «flushée», elle gardera la fraicheur de cette donnée et c’est elle qui sera retournée au client.

    Dans le cas d’une mise à jour, le processus est différent. Le cache «bloom filters» retournera «true» et les autres mécanismes de cache («Row cache» ; «Key cache» ; «SSTable index») seront sollicités pour récupérer la valeur sauvegardée. Cette valeur sera comparée à la valeur contenue dans la «Memtable» suivant un «timestamp». Ce processus de vérification par les «timestamp» prévaut au sein du cluster. Lorsque votre data est présente sur plusieurs «node» (Réplication), en situation d’écriture intensive, se posera la problématique de la fraicheur de la data pour les lectures.

    En conclusion, les «Memtable» doivent être considérées comme des tampons. Le mécanisme de «triger» embarqué dans «CASSANDRA» aura la tâche de rendre la donnée définitivement persistante sur les disques. Cette persistance est supportée par les tables appelées «SSTABLE» (Sorted String Table).

      Cet évènement de «FLUSH» peut survenir dans trois cas :

    • La taille de la data atteint un quorum : MemtableThroughputInMB
    • Délais d’expiration atteint : MemtableFlushAfterMinutes
    • Le nombre d’objet écrit : MemtableOperationsInMillions

    Le paramétrage de ces trois variables de configuration vont donc influencer sur les performances globales du cluster. En parallèle de ces performances, vous devez prendre en considération votre aversion pour le risque et avoir un ratio acceptable entre persistance et rapidité ! Pour en savoir plus sur leur impact, suivez le wiki de cassandra

      Ci-dessous, une liste d’éléments à retenir sur les «Memtable» :

    • Création d’une «Memtable» par «Column family»,
    • Stockage de la data par clé/valeur et «merge» de cette dernière pour les requêtes de type «UPDATE»,
    • «Triger» pour rendre la data dans les «Memtable» persistante
    • Système de «Cache» et indexation

    Persistance de la donnée grâce aux «SSTables»

    Le mécanisme de persistance des données est assuré par les SSTables (Sorted String Table).

      Ce qui est important de retenir :

    • Il faut leur dédier un périphérique physique de préférence rapide,
    • Elles ont une organisation particulière : plusieurs «SSTable» peuvent cohabiter et contenir la même clef avec une valeur différente !
    • Elles sont gérées par un mécanisme de «compaction» : Amélioration des performances de lecture.

    A chaque cycle de «Flush» des «Memtable» (déclenché par l’une des trois directives vu ci-dessus), une «SSTable» est créé. Il y a potentiellement N «SSTable» par «Column family». Nous avons fait jusqu’ici une présentation très linéaire des flux engendrée par une écriture dans «CASSANDRA». Il faut avoir à l’esprit que l’ensemble fonctionne en parallèle avec des «triger».

    Certains évènements sont toutefois chronologiques et il faut donc aborder l’optimisation de manière globale. Les «commitlog» permettent de rejouer l’enregistrement dans le cas ou la donnée contenue dans la «memtable» n’ait pas pu être «flushée» sur le disque physique. Le «commitlog» écrit un «flag» et le set à 1 temps que la «memtable» responsable de la data n’a pas été flushée. Cette écriture sur la «SSTable» libère ce flag.

    Attention si toutefois votre aversion pour la prise de risque est très faible !. Il serait contre productif de vouloir faire un «fsync» à chaque écriture. Nous serions effectivement très tenté de mettre en place cette solution pour garantir de manière presque immédiate la consistance de la donnée !! Cette solution n’est pas viable car très lente du fait de la rotation nécessaire des plateaux du disque pour l’enregistrement (5 à 10ms / rotation).
    Quoiqu’il se passe, il y aura toujours un risque de perdre de la donnée : Reste à savoir à quel endroit positionner ce curseur «risque» !

    Ci-dessous en guise de conclusion, je vous propose un schéma qui récapitule les flux lorsque l’on fait une opération d’écriture dans CASSANDRA.

    Cycle de vie d'une écriture dans cassandra

    Cycle de vie d'une écriture dans cassandra

    Laisser un commentaire

    Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

    *

    Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>