Chez Qumulo, nous construisons un système de fichiers évolutif. Comme vous vous en doutez, nous avons beaucoup de «magasins de valeurs-clés» dans notre système: par exemple, il y a des B-Trees distribués pour les composants du système de fichiers tels que les répertoires et les extensions. Il existe également divers magasins de valeurs-clés de configuration. Ces structures sont construites sur notre architecture de magasin protégé distribué. Récemment, mon équipe a créé un nouveau magasin clé-valeur distribué pour définir la composition du système de protection utilisé par notre système de fichiers en cluster (QSFS).

Magasins protégés

En gros, QSFS est construit sur une collection de magasins protégés (PStores). Les PStores offrent les propriétés dont nous avons besoin pour notre système de fichiers: transactionnalité, tolérance aux pannes (effacement ou mise en miroir), récupération de pannes, adressage indépendant du disque, lectures et écritures efficaces, etc. sur plusieurs nœuds. Comment nous atteignons les propriétés ACID avec PStores est un sujet pour un autre article.

Etat du système de protection

Le mappage entre PStores et leurs composants constitutifs est essentiel à la fiabilité et aux performances de notre système. Nous appelons cela la carte PStore. Cette carte est normalement statique. cependant, il change pendant la reprotection après une défaillance du disque ou du nœud, après le remplacement du disque et lorsque nous ajoutons des nœuds au système. De plus, l'état du système de protection inclut un numéro de transaction validée globalement qui est utilisé pour contrôler les transactions. Ce nombre est normalement incrémenté quelques fois par seconde. La carte Pstore, le numéro de génération et quelques autres éléments d'information constituent l'état du système de protection que nous devons stocker de manière fiable de manière distribuée, durable et cohérente.

Paxos V1

Le système existant de stockage de l’état du système de protection que nous avons décidé de remplacer était une collection de magasins multi-Paxos. Chaque nœud du cluster remplissait les fonctions d’accepteur Paxos et d’apprenant Paxos. Un proposant Paxos a vécu sur les nœuds 1 ou 2 (leaders du quorum [1]). Ce système avait un certain nombre de problèmes que nous espérions résoudre avec notre nouveau magasin de clés:

  • Les données sur les accepteurs et les apprenants de Paxos étaient stockées sur des disques système moins fiables que les disques SSD utilisés pour les blocs PStore. Nous avons constaté que même les charges relativement modestes générées par le magasin Paxos entraînaient des défaillances prématurées de ces appareils.
  • La carte PStore était stockée sous la forme d'une valeur Paxos unique. Cette valeur peut être très grande en fonction de la taille du cluster. Bien que nous mettions à jour chaque PStore indépendamment lors de la reprotection (comme pour les reconstructions de lecteur), ces mises à jour ont nécessité le verrouillage et l'écriture de la totalité de la carte. Cela a entraîné des goulots d'étranglement au niveau des performances et une usure accélérée de nos lecteurs système.
  • Parce que Paxos V1 était un système écrit au début de l'histoire de Qumulo, il n'utilisait pas nos nouvelles méthodes et frameworks de test. En conséquence, le code de test pour Paxos V1 était difficile à maintenir et à étendre.

Un nouveau magasin Key-Value est conçu

Pour résoudre ces problèmes, nous avons conçu un nouveau système dans lequel Paxos joue un rôle réduit. Une seule instance multi-Paxos stocke l'ensemble de disques SSD contenant des magasins de valeurs-clés contenant l'état du système de protection. Les données relatives à l’accepteur et à l’apprenant Paxos sont stockées dans le superbloc résidant sur chaque disque SSD. Chaque disque SSD fournit de l'espace pour l'ensemble complet de clés système de protection que nous devons stocker dans un ensemble de blocs appelés un volume KV. À chaque quorum, nous lisons et écrivons à Paxos une seule fois. L'identité des volumes NKV définit le magasin DKV (Distributed Key-Value) mis en miroir. Ecrire au DKV est simple. écrire à tous les N miroirs. La lecture peut être faite à partir de n’importe quel miroir. Lors du démarrage du quorum, nous devons synchroniser l'un des volumes KV du dernier quorum avec les différents volumes KV N-1 du nouveau quorum. Une simple transaction est suffisante pour ce système. Une erreur lors de l'écriture peut entraîner un désaccord entre les magasins individuels. Nous sélectionnons la nouvelle valeur ou l'ancienne valeur comme source de synchronisation, éliminant ainsi toute incohérence.

Notre système de quorum garantit que les opérations de cluster s'exécutent avec une majorité de nœuds connectés. Les erreurs de connexion amènent le cluster à réformer le quorum où chaque nœud participe à une séquence d'étapes coordonnée par un responsable. Les opérations en ligne se produisent généralement dans des quorums à long terme.

Paxos V2

Notre nouveau magasin de valeurs-clés distribuées s'appuierait toujours sur le protocole Paxos pour stocker l'ensemble des ID de lecteurs composant le magasin DKV actuel. L'implémentation de Paxos V2 était simple car nos besoins sont modestes; Notre système de quorum nous garantit une garantie unique et nous avons des exigences de performances modestes, car nous n'avons besoin de lire et d'écrire qu'une petite quantité de données Paxos une fois par quorum.

Volumes KV

Ensuite, nous avions besoin d'un moyen d'identifier les blocs sur un disque SSD contenant le magasin de valeurs-clés. Nous savons que les disques SSD peuvent fournir l’espace nécessaire au stockage du DKV, mais nous aurons besoin de prendre en charge le provisionnement dans les grappes existantes ultérieurement. À ce stade du projet, nous avons créé les blocs au besoin (tests) ou nous sommes basés sur la disponibilité des blocs sur les clusters nouvellement créés.

Les blocs SSD nécessaires étaient gérés par un volume KV sur chaque SSD. Le volume a fourni plusieurs fonctionnalités importantes:

  • Marquage d'allocation Au démarrage, les volumes KV ont rejoint d'autres structures sur SSD que nous parcourons pour déterminer ce qui est alloué et ce qui est gratuit. Les blocs de volume sont liés à des blocs d'arbre pour permettre des lectures parallèles rapides.
  • Mappage de la clé de volume à l'adresse du bloc.
  • Lire et écrire des blocs de valeur par clé de volume.
  • Synchronisation efficace des volumes d'un SSD à un autre.

Étant donné une liste de blocs disponibles (à nouveau, garantis à ce stade), une classe de générateur produirait le couplage sur disque nécessaire et les objets de volume résultants.

Magasins KV

Le magasin KV fournit un mappage des clés aux valeurs situées en haut du volume KV sur un seul SSD. Les blocs de notre système ont une taille 4KiB; Nous avons déterminé que les valeurs d'état du système de protection n'auraient jamais besoin d'être aussi grandes que 1KiB, nous stockons donc les valeurs 4 par bloc de volume. L'espace clé est linéaire et non épars. La modification des valeurs implique read-modify-write, nous avons donc construit un simple cache de volume pour améliorer les performances.

Les magasins KV doivent être sécurisés pour les threads, de sorte que cette couche possède également un verrouillage local des nœuds. Comme les clés sont aliasées par les blocs de valeur de volume, nous avons haché l'ID de bloc de volume dans un ensemble fixe de mutex. Les API de lecture et d'écriture comportent des variantes de clé unique et de masse.

Stockage KV distribué et synchronisation

Nous avons créé une simple classe dkv_store composée de N instances de kv_store (pour nos exigences de tolérance aux pannes, N est actuellement 3). Les écritures sont transmises en parallèle à chaque membre kv_store via RPC et les lectures sont transmises à n’importe quel magasin membre. C'est la première partie du système qui est exposée aux utilisateurs (par exemple, aux composants d'état du système de protection). Nous exposons un espace de clés qui est un mappage direct des clés kv_store des composants. Plus tard, lorsque nous avons introduit le sharding, ce mappage a changé.

Construire une dkv_store instance est la responsabilité d'une fonction de synchronisation. Lorsque nous démarrons un nouveau quorum, la synchronisation effectue les étapes suivantes:

  1. Interrogez les noeuds en ligne pour obtenir la liste des volumes KV en ligne.
  2. Lisez l'ID de volume KV défini dans le quorum précédent à partir de Paxos.
  3. Choisissez un volume en ligne du précédent ensemble de quorum comme source.
  4. Répliquez depuis les volumes de destination source vers N-1 inutilisés dans le quorum précédent.
  5. Stockez le nouvel ensemble d'ID de volumes dans Paxos.

Le test de ce composant était crucial. Nous avons développé des tests exhaustifs pour couvrir une matrice de taille de cluster, de nœuds en panne, de disques en panne et d'erreurs de progression partielle. Comme la synchronisation retarde le démarrage du quorum et donc la disponibilité du système de fichiers, nous avons optimisé et parallélisé ce processus pour réduire son temps d'exécution à quelques secondes.

Inscription

Jusque là, nous avions affaire à de nouveaux clusters uniquement. Pour déployer notre nouveau système, nous devions gérer les clusters existants sur les sites des clients. Nous avons écrit du code pour mettre à niveau les données de l'ancien magasin Paxos vers le DKV. Il y avait deux phases à cela: l'approvisionnement en volume et la traduction des données.

Sur un cluster actif, les blocs SSD sont utilisés à diverses fins (par exemple, les blocs de journalisation, les arborescences de blocs et le cache d'écriture différée, par exemple). Nous pouvons demander des blocs mais uniquement lorsque le système est entièrement en ligne. Un agent rend les blocs disponibles en faisant migrer des blocs dans un PStore du disque SSD vers son disque de sauvegarde. La première partie de la mise à niveau lance un processus d'arrière-plan en ligne sur tous les nœuds pour mettre en place des blocs de chaque SSD. Rappelez-vous qu'une fois qu'un volume est construit sur un SSD, les blocs sont liés et alloués, empêchant toute utilisation ultérieure pour d'autres besoins. À mesure que chaque volume est construit, le processus d'arrière-plan informe un maître de mise à niveau résidant sur le nœud principal. Une fois que tous les disques SSD ont des volumes, le maître lance un redémarrage du quorum.

Dans le quorum suivant, la seconde moitié de la mise à niveau prend le relais. Notant que tous les volumes sont présents mais pas dkv_store est défini dans le nouveau Paxos, un processus de traduction sélectionne un ensemble arbitraire de volumes dkv_store. Le processus lit ensuite les anciennes données de Paxos V1 et les écrit dans le DKV. Le processus persiste alors l'ID de volume DKV défini dans Paxos V2. À la fin du démarrage du quorum, une cale d'état du système de protection passe de l'utilisation de l'ancien stockage au nouveau stockage. Le quorum futur commence par le processus de synchronisation normal décrit ci-dessus.