BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles A la découverte de l'architecture de la base de données NuoDB, Partie 1

A la découverte de l'architecture de la base de données NuoDB, Partie 1

Favoris

Introduction

Traditionnellement, les base de données relationnelles étaient conçues pour les architectures à scalabilité verticale. Il y a encore quelques années, cela signifiait que pour supporter de la scalabilité horizontale, vous deviez soit laisser tomber le SQL soit mettre en oeuvre des astuces telles que du sharding et une réplication active/passive. Si vous souhaitiez une base de données à la fois ACID, flexible et relationnelle, vous n'aviez pas de solution. C'est ce manque qui a inspiré le mouvement NewSQL et qui est au coeur de l'origine de NuoDB.

NuoDB est une base de données relationnelle conçue pour le cloud. Qu'entendons nous par là? Il s'agit d'un vrai service SQL qui dispose de toutes les propriétés des transactions ACID, qui supporte le langage SQL standard et la logique relationnelle que vous connaissez (et je l'espère) aimez. Cette base est aussi conçue à la base pour offrir la scalabilité que vous attendez d'un service conçu pour le cloud.

Je ne vous ennuirai pas ici avec de longues définitions du "cloud scale". Si vous êtes vraiment intéressés, je suis allé dans les détails (probablement plus que vous le voudriez) sur notre blog technique dans un article sur ce que veut dire être cloud scale. La version courte est que vous avez besoin d'un modèle supportant la scalabilité horizontale (bien sûr), mais je pense que vous avez aussi besoin d'une solution qui est agile, facile d'accès, automatisable, sécurisé et supportant la haute disponibilité. Le reste de cet article s'appuie sur ce point de vue.

Notez que NuoDB est "simplement" une application. Ce qui veut dire que nous nous appuyons sur Linux, Mac, Windows ou Solaris que ce soit sut votre PC portable, un cluster privé ou un cloud public. Vous pouvez l'utiliser sur Amazon Web Services ou Google Compute Engine, l'intégrer avec Open Stack ou le lancer comme un service Windows local sur votre PC portable. L'application est flexible, ce qui permet de la tester et de l'utiliser en développement où vous voulez et de décider, par la suite, où et comment vous voulez la déployer.

Ce que couvre cet article c'est : ce que NuoDB est, comment la solution est architecturée pour répondre aux exigences actuelles et quels sont les problèmes que vous pouvez résoudre en l'utilisant. A la fin de cet article, vous serez familiarisés avec les concepts clés et les particularités de l'architecture de NuoDB. Nous aurons aussi abordé les aspects pratiques du déploiement et des fonctionnalités de management et vous serez enfin prêts à mettre en place votre base NuoDB.

Architecture Trois Tiers

L'approche la plus simple de NuoDB est de la concevoir comme une architecture trois tiers. Il y a un tiers d'administration, un tiers transactionnel et un tiers dédié au stockage. Nous reviendrons plus tard sur la couche d'administration. Pour l'instant, nous nous concentrerons sur la deuxième et la troisième couche.

Séparer les tiers transactionnels et de stockage est une partie de la clé permettant de créer un système relationnel scalable. Traditionnellement, la mise en oeuvre d'une base de données SQL consiste en un exercice de synchronisation entre une représentation des données sur le disque (sous forme de pages) avec une structure en mémoire basée sur des B-trees. Ce couplage fort est efficace mais hautement sensible aux IOPS (nombre opérations d'écriture et de lecture par seconde) et supporte très mal la scalabilité horizontale. En séparant ces rôles, nous avons une architecture qui peut scaler horizontalement sans être aussi sensible aux problèmes tels que le débit du disque.

Dans NuoDB, la durabilité est une tâche complètement différente du traitement transactionnel, ce qui veut dire qu'il est possible de scaler ces tiers et de gérer les défaillances de manière totalement indépendante. Vous voulez scaler horizontalement la couche transactionnelle? Vous pouvez le faire sans ajouter de disques. Vous voulez des archives indépendantes pour vous préserver des défaillances des data centers? Vous pouvez le faire sans affecter les performances des transactions. Cette séparation n'est pas uniquement utile pour aider le système à scaler, elle le rend plus prompt à s'adapter à la demande et vous permet de provisionner les ressources en fonction de vos besoins.

La couche transactionnelle est responsable de l'Atomicité, de la Consistance et de l'Isolation, mais ne sait rien de la Durabilité. Ce qui veut dire que cette couche est en mémoire, donc qu'elle est rapide et que n'importe quel noeud peut tomber ou être éteint sans perte de données ou de consistance. Parce qu'elle est en mémoire, c'est aussi dans cette couche que nous gérons le cache (plus spécifiquement, il s'agit d'un cache "à la demande" sur lequel je reviendrai plus tard). Vous n'avez pas besoin d'une couche de cache supplémentaire au dessus de la base de données NuoDB.

La couche de stockage, naturellement, est là ou le D de ACID s'impose. Il s'agit la source de l'ensemble des données, toujours active et toujours consistante. Cette couche est responsable de la durabilité des données commitées et permet d'accéder aux données qui ne sont pas contenues dans le cache de la couche transactionnelle.

Notez que le sens du "commit" dans NuoDB est réglable. Vous disposez d'une flexibilité permettant de faire un compromis entre la performance et la haute disponibilité, en partie grâce à ces couches séparées. Pour comprendre comment et pourquoi vous voudriez ajuster les protocoles de commit, j'ai besoin de vous expliquer en quoi ces couches consistent.

Une Coordination Peer-to-Peer

Les deux couches de la base de données sont faites de processus répartis sur n'importe quel nombre d'hôtes. Il y a un exécutable unique qui peut être lancé dans deux modes : Transaction Engine (TE, Moteur Transactionnel) ou Storage Manager (SM, Gestionnaire de Stockage). Tous les processus sont des peers, sans coordinateurs ou point de défaillance uniques, et il n'y a pas de configuration particulière requise sur aucun des hôtes. Par défaut, les noeuds s'authentifient mutuellement et communiquent à l'aide de sessions cryptées.

Chaque TE accepte des connexion de clients SQL et gère les requêtes. Les caches sont internes aux processus du TE. Les SM et les TE communiquent entre eux à l'aide d'un protocole de coordination peer-to-peer. Lorsqu'un TE ne trouve pas un objet dans son cache local, il peut chercher l'objet dont il a besoin auprès d'un de ses pairs, ce qui veut dire demander à un autre TE, s'il y en a un qui dispose de l'objet dans son cache, dans la mesure où ce type de requêtes est plus rapide qu'une requête auprès d'un SM de charger un objet à partir du stockage durable.

Ce processus, à la fois simple et flexible, permet de rendre l'amorçage, la scalabilité et la migration très simples. Par exemple, mettons que vous vouliez la base NuoDB la plus simple possible. Il vous suffit de démarrer un unique TE et un SM sur le même hôte. Vous disposez alors d'une base de données ACID démarrée, mais elle est installée sur un hôte unique. Cette configuration est très pratique pour faire des tests sur votre PC, mais beaucoup moins satisfaisante pour un déploiement réel.

Ce que vous pourriez faire à présent, c'est installer l'application sur un nouvel hôte et lui envoyer un message lui indiquant de démarrer un nouveau TE. Ce nouveau TE s'authentifierait mutuellement avec les processus existants, chargerait quelques données de référence dans son cache et indiquerait qu'il est prêt à prendre en charge une partie des tâches transactionnelles. L'ensemble du processus à partir de l'envoie du message jusqu'à ce que le TE soit prêt à fonctionner prend moins de 100ms. Vous venez de doubler le débit transactionnel de votre base de données et vous avez augmenté votre résistance à la panne en lançant des TEs sur des hôtes distincts.

Bien, mais vous ne disposez que d'un seul point de durabilité. Pour palier à ce problème, vous pourriez ajouter un troisième hôte et lui envoyer le message de démarrer un second SM. Ce SM se synchroniserait automatiquement avec le système en cours d'exécution et, une fois prêt, le noeud participe à la base de données. Vous disposez maintenant de deux points de durabilité pour votre base de données. Plutôt facile aussi.

Enfin, disons que vous vouliez que votre premier TE et votre premier SM tournent sur des hôtes différents. Vous avez deviné : ajoutez un quatrième hôte, démarrez aussi bien un TE qu'un SM, puis, une fois qu'il est prêt, éteignez le TE ou SM original (en fonction de celui démarré sur le nouvel hôte). Ce que vous venez de faire est une migration de base de données à chaud. Pas d'arrêt. Vous avez aussi configuré une base de données totalement redondante, puisque n'importe lequel des quatre hôtes peut faire défaut et vous avez toujours accès à l'ensemble des données et au moteur transactionnel.

Tout ceci fonctionne simplement et rapidement grâce au modèle simple, orienté process et peer-to-peer sur lequel NuoDB est bâti. Une autre raison du bon fonctionnement de NuoDB est le procédé simple de gestion du cache à la demande et le format des données qui sont mises en cache et partagées. Non, il ne s'agit pas de structure SQL. Il s'agit de quelque chose que nous appelons les Atoms.

Tout est Atom

Bien qu'il soit vrai que NuoDB est une base de données relationnelle, ça n'est pas ce à quoi son architecture interne ressemble. La partie frontale d'un TE est quelque chose qui parle le SQL et qui sait comment optimiser les transactions. Sous cette couche, toute la logique se base sur des objets appelés Atoms. Les Atoms sont essentiellement des entités autonomes qui représentent des types d'informations spécifiques (données, indexes, schémas, etc.). Même le méta-model interne est stocké sous forme d'Atoms.

Les Atoms sont des "tranches" de données, mais ils ne doivent pas être vus comme les pages présentes traditionnellement dans les bases de données relationnelles. D'une certaine manière, les Atoms sont en fait des noeuds de notre réseau, coordonnant leurs instances par l'état en cache et la sérialisation/désérialisation dans la couche de stockage. Ils contiennent des portions arbitraires de données, la taille d'un Atom étant choisie pour permettre d'optimiser la communication, le nombre d'objets en cache, la complexité de suivi des changements, etc.

En plus du contenu de la base de données, il y a aussi des Atoms qui servent de catalogues. Un catalogue est la manière dont NuoDB résout les autres Atoms. Il s'agit essentiellement d'un service de recherche distribué et autonome. Lorsqu'un TE démarre, il n'a besoin que d'un seul Atom, que l'on appelle le Master Catalog. Il s'agit de l'Atom "racine" à partir duquel tous les autres Atoms peuvent être trouvés. Dans l'exemple précédent, lorsque le second TE remonte un objet à partir du cache du premier TE, il sait qu'il est en mesure d'effectuer cette opération parce que le catalogue lui indique où l'Atom requis peut être trouvé. C'est ce simple mécanisme d'amorçage qui fait que c'est simple et rapide de connecter un nouveau TE.

Les Atoms sont plus qu'une manière élégante d'organiser les données. Ils simplifient considérablement les communications internes et la gestion du cache parce que nous n'avons pas à penser à une structure SQL spécifique. Tout est contenu dans la même structure de données générique et basé sur des identifiants cohérents.

Cette vue de l'état interne nous aide aussi à assurer la cohérence de la base de données dans son ensemble. Parce que les méta-données et le catalogue sont stockés dans la même structure à base d'Atoms que les données elle mêmes, tous les changements sont mis en oeuvre dans le même contexte transactionnel. Ainsi, si nous mettons à jour les méta-données de la base ou du catalogue au cours d'une opération SQL, soit tous les changements sont appliqués, soit rien ne se passe. Nous ne courrons pas le risque d'effectuer des changements incohérents qui faussent les données et les états.

Finalement, modéliser l'ensemble des données comme des Atoms rend la durabilité plus aisée à mettre en oeuvre. Parce que le contenu d'une base de données est simplement une collection d'objets nommés, notre couche de durabilité est simplement une base clé-valeur. En théorie, il pourrait s'agir de n'importe quel type de base. Nativement, dans la version 1.1 de NuoDB, nous supportons : n'importe quel système de fichiers, l'API S3 de Amazon et Hadoop HDFS. Il y aura du support pour d'autres types de stockage dans les versions futures. Il est possible, dans une même base de données, de mélanger plusieurs mécanismes de stockage, ce qui veut dire que vous pourriez utiliser (par exemple), à la fois le système de fichiers local et un service S3 pour stocker votre base de données.

Contrôle de la Concurrence basé sur les Versions Multiples

La structure des Atoms est très puissante, elle simplifie le comportement de l'architecture ce qui nous aide à scaler. Néanmoins, sans une solution de gestion des conflits et de renforcement de la cohérence, NuoDB ne pourrait pas supporter la sémantique ACID. Pour gérer ce type de problématiques, nous utilisons le Multi-Version Concurrency Control (MVCC, Contrôle de la Concurrence basé sur les Versions Multiples). Contrairement aux systèmes basés sur des verrous globaux ou sur des transactions distribuées, MVCC fonctionne en versionnant l'ensemble des données et en traitant globalement la base de données comme une série d'ajout de lots de modifications.

MVCC propose beaucoup de propriétés intéressantes lorsqu'il s'agit de prendre en compte la scalabilité d'une base de données distribuée. Tout d'abord, lorsque les données sont modifiées, ce que nous faisons réellement c'est créer une nouvelle version de la donnée (qui est "en attente" jusqu'à ce que la transaction soit committée). Dans le cache on peut trouver plusieurs versions en attente au même titre que la version "canonique" d'une donnée, ce qui fait que rien n'est jamais réellement changé. Tout ceci rend les rollback triviaux (la transaction n'est simplement jamais committée et le changement en attente est supprimé) ce qui signifie que les messages de mise à jour peuvent être très optimistes.

Non seulement ces messages peuvent être optimistes, mais dans NuoDB ils sont généralement asynchrones. Ce qui implique que lorsqu'une transaction est en train d'essayer d'effectuer un changement, elle enverra les messages associés (voir plus loin) immédiatement et continuera. Si le TE a un retour selon lequel le changement est autorisé avant que la transaction ne soit committée, alors aucun coût lié à l'envoi du message n'est constaté. Dans le cas contraire, la transaction se met en attente, mais seulement une fois arrivée à la fin, quand elle doit décider si le commit est autorisé. Cette combinaison de comportements optimistes et asynchrones, associée au système de messagerie, permet à NuoDB de se préserver des pics de latences et autres comportements imprévisibles du réseau dans un environnement tel qu'un cloud.

Le second avantage du versionnement des données, c'est qu'il permet de disposer d'un modèle clair. Dans son mode par défaut, NuoDB propose une isolation par snapshots. En d'autres termes, vous disposez d'une vue cohérente de la donnée telle qu'elle existait au moment où la transaction a démarré. Nous supportons, par ailleurs, une isolation read-committed et une opération SQL de select-for-update, mais j'ai le sentiment que l'isolation par snapshots correspond à ce que vous voulez vraiment dans une base de données distribuée.

En pratique, une transaction sur un TE peut lire des données tandis qu'une autre transaction, sur un autre TE, peut modifier les mêmes données sans conflit. Tant que tout à part la première transaction interagit avec un état cohérent correspondant à la version courante de l'objet, alors la cohérence est maintenue. MVVC permet au système de connaître l'ensemble des versions en attente et commitées, ce qui lui permet de maintenir une vue toujours cohérente des données, avec un minimum de coordination globale des messages et de gestion des conflits.

Les opérations qui nécessitent un arbitrage sont les conflits écriture/écriture. Pour gérer ce type de conflits, NuoDB choisit un hôte qui a pour rôle d'être le Chairman (président) de l'objet. C'est un nom élégant, mais sa fonctionnalité réelle est simplement de faire un arbitrage lorsque deux transactions concurrentes veulent mettre à jour le même objet. Seuls les TEs qui contiennent un objet dans leur cache peuvent occuper la fonction de Chairman pour cet objet donné, dans le cas où un objet est seulement en cache dans un unique TE, la médiation se fait localement. Lorsqu'un un TE est arrêté, est en échec ou supprime un objet de son cache, nous avons un moyen déterministe de sélectionner un nouveau Chairman sans communication.

Pour finir, MVVC nous offre un dernier avantage sur les performances du système. Les SMs ne sont pas uniquement responsables de l'archivage de la base de données, elles peuvent aussi (et nous vous le recommandons) alimenter un journal. Parce que NuoDB est un système versionné, le journal est simplement une suite (en ajout seulement) de différences, qui tendent donc à être très petits. Cette conception rend la journalisation très efficace et implique que le coût de l'ajout d'un SM journalisé n'ait pratiquement aucun impact sur le temps d'exécution d'une transaction classique.

De la même manière que les messages de mise à jour peuvent être envoyé de manière optimiste, les mise à jours peuvent être ajoutées à un journal avant que la transaction ne soit committée. Si une transaction n’aboutit pas, alors nous le notons et lors de la sauvegarde du journal, la mise à jour associée ne sera pas ajouté au lot de changements à archiver. La coordination optimiste ne porte donc pas uniquement sur les données en mémoire, mais aussi sur les données durables. Un détail important à retenir est que la gestion des versions des enregistrements est effectuée à l'aide des Atoms mais pas sur les Atoms eux mêmes. Les Atoms pourraient contenir beaucoup d'enregistrements mais ils auraient une granularité trop grosse pour minimiser efficacement les conflits.

Dans la seconde partie de cet article, nous présenterons l'implémentation du système transactionnel, le rôle de la couche d'administration, l'intégration des différents composants entre eux ainsi que nos évolutions à venir.

A propos de l'auteur

 Seth Proctor est le CTO de NuoDB, Inc. il a 15 ans d'expérience dans la recherche, la conception et l'implémentation de système scalables. Cette expérience inclue des travaux sur les réseaux, les langages, les systèmes d'exploitation, la sécurité, les bases de données et les environnements distribués, qui font partie partie intégrante du projet NuoDB. Avant d'intégrer NuoDB, Seth travaillait pour Nokia sur l'architecture de leur cloud interne privé. Avant cela, il était chez Sun Microsystem où il travaillait dans les laboratoires de recherches et il collaborait avec des groupes produits et des universités.

Seth détient huit brevets suite à son travail dans plusieurs disciplines techniques. Il dispose de cinq autres brevets en cours d'approbation, liés aux performances des bases de données et à l'agilité de l'utilisateur final dans les déploiements de la base de données centralisée NuoDB. Vous pouvez le contacter ici

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT