Méthode de stockage de données - KVELL : conception et mise en œuvre d'un stockage clé-valeur persistant rapide

avant-propos

Récemment, je travaille sur un projet open source avec mes amis. La direction est le stockage de données. Récemment, j'ai étudié beaucoup de connaissances et lu quelques articles. KVELL est l'un d'entre eux. Je pense que c'est très bon, donc je vais Partagez-le.
Les amis intéressés peuvent y jeter un coup d'œil, le titre est KVell : la conception et la mise en œuvre d'un magasin clé-valeur persistant rapide.

1. Origines

1. Deux paradigmes de stockage actuellement populaires

Il existe actuellement deux paradigmes principaux pour les KV persistants :

  • Les LSM KV
    sont largement considérés comme le meilleur choix pour les charges de travail dominées par l'écriture. Les LSM KV sont utilisés dans des systèmes populaires tels que RocksDB et Cassandra.
  • Les KV B-tree
    sont considérés comme plus adaptés aux charges de travail intensives en lecture. Les arbres B et leurs variantes sont utilisés dans MongoDB

2. Développement des performances SSD

Considérons trois appareils qui ont été introduits au cours des 5 dernières années :

• Config-SSD. Un Intel Xeon à 32 cœurs à 2,4 GHz, 128 Go de RAM et un SSD Intel DC S3500 de 480 Go (2013).

• Config-Amazon-8NVMe. Une instance WS i3.metal, avec 36 processeurs (72 cœurs) fonctionnant à 2,3 GHz, 488 Go de RAM et 8 disques SSD NVMe de 1,9 To chacun (marque inconnue, technologie 2016).

• Config-Optane. Un Intel i7 à 4 cœurs à 4,2 GHz, 60 Go de RAM et un Intel Optane 905P de 480 Go (2018).

IOPS

(Le nombre d'E/S par seconde est une mesure utilisée pour tester les performances des périphériques de stockage informatiques tels que les disques durs (HDD), les disques SSD ou les réseaux de stockage (SAN). Le tableau 1 montre les trois périphériques. nombre maximal d'IOPS en lecture et en écriture et bande passante aléatoire et séquentielle. Premièrement, le nombre d'IOPS et la bande passante augmentent considérablement. Deuxièmement, les écritures aléatoires étaient beaucoup plus lentes que les écritures séquentielles sur les appareils plus anciens, mais ce n'est plus le cas. De même, le mélange de lectures et d'écritures aléatoires n'entraîne plus de mauvaises performances comme c'était le cas sur les appareils plus anciens. Par exemple, Config-Optane utilise le lecteur Intel Optane 905P sorti au troisième trimestre 2018, qui peut maintenir plus de 500 000 IOPS quel que soit le mélange de lectures et d'écritures, et l'accès aléatoire n'est que légèrement plus lent que l'accès séquentiel.

Latence et bande passante

Le tableau ci-dessous montre les mesures de latence et de bande passante pour trois appareils en fonction de la profondeur de la file d'attente de l'appareil, avec un cœur effectuant des écritures aléatoires. Les appareils de la génération précédente ne pouvaient supporter que des temps de réponse inférieurs à la milliseconde avec un petit nombre de demandes d'E/S simultanées (32 dans le cas de Config-SSD). Config-Amazon-8NVMe et Config-Optane prennent en charge un parallélisme plus élevé, les deux disques étant capables de répondre à 256 requêtes simultanées avec une latence inférieure à la milliseconde. Ces deux pilotes ne peuvent atteindre qu'une fraction de leur bande passante lorsqu'il y a trop peu de requêtes dans la file d'attente de l'appareil. Ainsi, même sur les appareils modernes, il doit y avoir un juste équilibre entre envoyer trop peu de requêtes simultanées (entraînant une bande passante sous-optimale) et en envoyer trop (entraînant une latence élevée).
insérez la description de l'image ici

réduction du débit

Le tableau ci-dessous montre les IOPS au fil du temps sur les trois appareils. Ce graphique montre également les progrès de la technologie des appareils. Par exemple, la configuration ssd peut supporter 50 000 IOPS en écriture pendant 40 minutes, mais ses performances chutent lentement à 11 000 IOPS. Les nouveaux SSD n'ont pas ce problème et les IOPS restent élevés au fil du temps.

insérez la description de l'image ici

E/S en rafale

La figure 2 montre la latence d'une opération d'écriture 4K avec une profondeur de file d'attente de 64 sur Config-Amazon-8NVMe et Config-Optane. Les SSD d'ancienne génération souffrent de pics de latence dans les charges de travail intensives en écriture en raison des opérations de maintenance internes. Sur le Config-SSD, nous avons observé des pics de latence allant jusqu'à 100 ms après 5 heures, par rapport à une latence d'écriture normale de 1,5 ms. Ces résultats ne sont pas représentés sur la figure 2 car la taille de pic de cet appareil masquerait les résultats d'autres appareils. Les disques Config-Amazon-8 NVMe souffrent également de pics de latence périodiques. La latence maximale observée est de 15 ms (alors que 99,1 % est de 3 ms). Sur le pilote Config-Optane, les pics de latence se produisent de manière irrégulière et leur amplitude est généralement inférieure à 1 ms, le pic le plus élevé étant observé à 3,6 ms (contre 700 us pour 99 % des pics).

insérez la description de l'image ici

3. Problèmes avec les KV actuels sur le SSD NVMe

3.1 Le processeur est le goulot d'étranglement

insérez la description de l'image ici

Figure 3. Config-Optane.
Chronologie de la bande passante d'E/S (à gauche) et de la consommation de CPU (à droite) pour RocksDB (LSM KV) et WiredTiger (B-tree KV). Aucun des deux systèmes ne peut utiliser la bande passante d'E/S de l'ensemble du périphérique. Charge de travail : 50 % d'écriture YCSB - 50 % de lecture, distribution uniforme des clés, la taille de l'élément KV est de 1 Ko.

Le CPU est le goulot d'étranglement des LSM KV

Les LSM KV optimisent les charges de travail intensives en écriture en absorbant les mises à jour dans les mémoires tampons. Lorsque la mémoire tampon est pleine, elle est vidée sur le disque. Un thread d'arrière-plan fusionne ensuite les tampons vidés dans la structure arborescente maintenue dans le stockage persistant. La structure sur disque se compose de plusieurs niveaux avec des tailles de niveau croissantes. Chaque couche contient plusieurs fichiers triés immuables avec des plages de valeurs-clés incohérentes (à l'exception de la première couche, qui est réservée aux tampons de mémoire d'écriture). Pour préserver cette structure sur disque, les LSM KV implémentent une opération de maintenance intensive en CPU et en E/S appelée compactage, qui fusionne les données de niveau inférieur en données de niveau supérieur dans l'arborescence LSM, maintient l'ordre des éléments et supprime les doublons.

Sur les appareils plus anciens, la compression est en concurrence pour la bande passante du disque, mais la fusion, l'indexation et le code du noyau sont également en concurrence pour le temps CPU, et sur les appareils plus récents, le CPU est devenu le principal goulot d'étranglement. L'analyse montre que RocksDB consacre jusqu'à 60 % du temps CPU à la compression (28 % pour la fusion de données, 15 % pour la création d'index et le reste pour la lecture et l'écriture de données sur le disque). Le besoin de compression découle des exigences de conception de LSM, à savoir l'accès séquentiel au disque et la conservation des données triées sur le disque. Cette conception est avantageuse pour les disques plus anciens où dépenser des cycles CPU pour garder les données triées et garantir de longs accès séquentiels au disque en vaut la peine.

Le CPU est le goulot d'étranglement des KV B-tree

Il existe deux variantes d'arbres B conçus pour le stockage persistant : les arbres B+ et les arbres Bϵ. Les arbres B+ contiennent des entrées KV dans les feuilles. Les nœuds internes ne contiennent que des clés et sont utilisés pour le routage. En règle générale, les nœuds internes résident dans la mémoire et les feuilles résident dans le stockage persistant. Chaque nœud feuille a une gamme triée d'éléments KV, et les nœuds feuilles sont liés dans une liste liée pour une analyse facile. Les arborescences B+ à la pointe de la technologie (par exemple, WiredTiger) s'appuient sur la mise en cache pour obtenir de bonnes performances. Les mises à jour sont d'abord écrites dans le journal de validation de chaque thread, puis dans le cache. Finalement, lorsque les données sont expulsées du cache, l'arborescence est mise à jour avec les nouvelles informations. Les mises à jour utilisent un numéro de série, qui est requis pour la numérisation. Les opérations de lecture traversent le cache, ne visitant l'arborescence que si l'élément n'est pas mis en cache.

Il existe deux types d'opérations qui conservent les données dans l'arborescence :

  • point de contrôle et
  • expulsion.

Les points de contrôle se produisent périodiquement ou lorsqu'un certain seuil de taille est atteint dans le journal. Les points de contrôle sont nécessaires pour limiter la taille du journal de validation. L'éviction écrit les données modifiées du cache dans l'arborescence. L'éviction est déclenchée lorsque la quantité de données sales dans le cache dépasse un certain seuil.

Les arbres Bϵ sont une variante des arbres B+, améliorés avec un stockage temporaire des clés et des valeurs dans des tampons à chaque nœud. Finalement, lorsque la mémoire tampon est pleine, les entrées KV parcourent l'arborescence et sont écrites dans un stockage persistant.

La conception B-tree est sujette à la surcharge de synchronisation. Le profilage dans WiredTiger révèle ceci : les threads de travail passent 47 % de leur temps à attendre un créneau dans le journal (dans la fonction __log_wait_for_earlier_slot, qui utilise l'appel système sched_yield pour attendre occupé). Le problème provient du fait qu'il n'est pas possible d'avancer le numéro de série assez rapidement pour une mise à jour. Dans le chemin de code principal mis à jour, à l'exclusion du temps passé dans le noyau, WiredTiger ne passe que 18 % de son temps à exécuter la logique de requête client, et le reste du temps est passé à attendre. WiredTiger doit également effectuer des opérations en arrière-plan : le vidage des données modifiées du cache de la page prend 12 % du temps total et la gestion du journal de validation prend 5 % du temps total. Seulement 25 % du temps dans le noyau est utilisé pour les appels de lecture et d'écriture, et le reste du temps est utilisé pour les fonctions futex et yield.

Les arbres Bϵ subissent également une surcharge de synchronisation. Étant donné que l'arborescence Bϵ conserve les données ordonnées sur le disque, les threads de travail finissent par modifier la structure de données partagée, provoquant des conflits. L'analyse de TokuMX montre que les threads passent 30% de leur temps sur des verrous ou des opérations atomiques utilisées pour protéger les pages partagées. La mise en mémoire tampon s'est également avérée être une source majeure de surcharge dans les arbres Bϵ. Dans YCSB, une charge de travail, TokuMX, a passé plus de 20 % du temps à déplacer des données de la mémoire tampon vers l'emplacement correct dans les feuilles. Ces surcoûts de synchronisation l'emportent largement sur les autres surcoûts.

3.2 Fluctuations des performances des KV LSM et B-tree

En plus d'être limités par le processeur, les KV LSM et B-tree souffrent d'importantes fluctuations de performances. La figure 4 montre la fluctuation du débit au fil du temps pour RocksDB et WiredTiger exécutant la charge de travail principale YCSB a. Le débit est mesuré toutes les secondes. Dans les KV LSM et B-tree, le problème de base est similaire : les mises à jour du client s'arrêteront en raison d'opérations de maintenance.

Dans les KV LSM, le débit chute car les mises à jour doivent parfois attendre la fin du compactage. Lorsque le premier niveau de l'arborescence LSM est plein, les mises à jour doivent attendre que de l'espace soit libéré par compactage. Cependant, nous avons vu que la compression peut être un goulot d'étranglement du processeur lorsque les LSM KV sont exécutés sur des disques modernes. La différence de performances en termes de débit augmente d'un ordre de grandeur au fil du temps : RocksDB maintient une moyenne de requêtes de 63 K/s, mais chute à 1,5 K lorsque les écritures se bloquent. L'analyse montre que le thread d'écriture est bloqué environ 22 % du temps, en attendant que les composants de la mémoire soient vidés. L'actualisation des composants de la mémoire est retardée car le compactage ne peut pas suivre les mises à jour.

Des solutions pour réduire l'impact des compactages sur les performances ont été proposées, à savoir retarder les compactages ou les exécuter uniquement lorsque le système est inactif, mais ces solutions ne sont pas adaptées pour fonctionner sur des SSD haut de gamme. Par exemple, les machines Config-Optane actualisent les composants de mémoire à 2 Go/s. Retarder la compression de plus de quelques secondes peut entraîner un important arriéré de travail et un gaspillage d'espace.

Dans les arbres B, les pauses dans les charges de travail des utilisateurs peuvent également affecter les performances. Les écritures des utilisateurs sont retardées car les expulsions ne peuvent pas se produire assez rapidement. La pause a fait chuter le débit d'un ordre de grandeur, de 120 Kops/s à 8,5 Kops/s. Nous avons conclu que dans les deux cas, les opérations de maintenance telles que les compactages et les évictions perturbaient fortement la charge de travail des utilisateurs, provoquant des pauses de plusieurs secondes. Par conséquent, les nouvelles conceptions de KV devraient éviter les opérations de maintenance.
insérez la description de l'image ici

2. KVEL

1. Principes de conception des KV

  • Ne partage pas. Dans KVell, cela se traduit par la prise en charge du parallélisme et la minimisation de l'état partagé entre les threads de travail KV afin de réduire la surcharge du processeur.

  • Ne triez pas sur disque, mais gardez l'index en mémoire. KVell conserve les éléments non triés à leur emplacement final sur le disque, évitant ainsi des opérations de réorganisation coûteuses.

  • L'objectif est de réduire les appels système, pas les E/S séquentielles. Au lieu de cibler l'accès séquentiel au disque, KVell profite du fait que l'accès aléatoire est presque aussi efficace que l'accès séquentiel sur les SSD modernes. Au lieu de cela, il s'efforce de minimiser la surcharge CPU des appels système en regroupant les E/S.

  • Les journaux ne sont pas validés. KVell ne met pas les mises à jour en mémoire tampon, il n'a donc pas besoin de s'appuyer sur le journal de validation, évitant ainsi les E/S inutiles.

1.1 Pas de partage

Dans le cas courant d'une seule lecture et écriture, le thread de travail traitant la demande n'a pas besoin de se synchroniser avec d'autres threads. Chaque thread gère les requêtes pour un sous-ensemble donné de clés et maintient un ensemble de structures de données privées de thread pour gérer cet ensemble de clés.
Les structures de données clés sont :

  • (i) Un index B-tree léger en mémoire pour suivre l'emplacement des clés dans le stockage persistant
  • (ii) les files d'attente d'E/S, chargées de stocker et de récupérer efficacement les informations du stockage persistant
  • (iii) Liste libre, une partie de la liste des blocs de disque mémoire contient pour stocker des éléments et (iv) cache de page - KVell utilise son propre cache de page interne qui ne dépend pas des structures au niveau du système d'exploitation. Les balayages sont les seules opérations qui nécessitent une synchronisation minimale sur un index B-tree en mémoire.

Cette approche sans partage est une différence essentielle par rapport aux conceptions KV traditionnelles, où la totalité ou la plupart des structures de données principales sont partagées par tous les threads de travail. L'approche traditionnelle nécessite une synchronisation à chaque requête, ce qui est complètement évité par KVell. Les demandes de partitionnement peuvent provoquer des déséquilibres de charge, mais nous avons constaté que cet effet est minime si un partitionnement approprié est utilisé.

1.2 Ne pas trier sur disque, mais garder l'index en mémoire

KVell ne trie pas les données dans le jeu de travail du thread de travail. Étant donné que KVell ne trie pas les clés, il peut conserver les éléments à leur emplacement final sur le disque. Le fait de ne pas avoir d'ordre du tout sur le disque réduit la surcharge d'insertion d'éléments (c'est-à-dire la recherche du bon endroit pour insérer) et élimine la surcharge du processeur associée aux opérations de maintenance sur disque (ou au tri avant d'écrire sur le disque). Le stockage des clés dans le désordre sur le disque est particulièrement avantageux pour les opérations d'écriture et permet d'obtenir des latences de queue faibles.

Lors des scans, les clés consécutives ne se trouvent plus dans le même bloc de disque, ce qui peut être un inconvénient. Cependant, peut-être de manière surprenante, pour les charges de travail avec des termes kv moyens et grands (comme les analyses dans le benchmark YCSB ou les charges de travail de production, comme nous le montrons dans la section 6), les performances d'analyse ne souffrent pas de manière significative Influence.

1.3 L'objectif est de réduire les appels système, pas les E/S séquentielles

Dans KVell, toutes les opérations (y compris les analyses) effectuent un accès aléatoire au disque. Parce que l'accès aléatoire est tout aussi efficace que l'accès séquentiel, KVell ne gaspille pas les cycles CPU en forçant les E/S séquentielles.

Semblables aux LSM KV, les KVell envoient des requêtes au disque par lots. Cependant, les objectifs sont différents. Les LSM KV utilisent principalement des E/S par lots et trient les éléments KV afin de tirer parti de l'accès séquentiel au disque. KVell regroupe les requêtes d'E/S, l'objectif principal est de réduire le nombre d'appels système, réduisant ainsi la surcharge du processeur.

Le traitement par lots est un compromis, comme on le voit dans la section 2, le disque doit être constamment occupé afin d'atteindre son pic d'IOPS, mais seulement si le nombre de requêtes contenues dans la file d'attente matérielle est inférieur à un montant donné (par exemple sur Config-Optane 256 requêtes), le disque répond avec une latence inférieure à la milliseconde. Un système efficace doit envoyer suffisamment de requêtes aux disques pour les occuper, mais ne pas les submerger avec de grandes files d'attente de requêtes, qui entraînent une latence élevée.

Dans les configurations à plusieurs disques, chaque agent stocke les fichiers sur un seul disque. Cette décision de conception est essentielle pour limiter le nombre de requêtes en attente par disque. En fait, comme les travailleurs ne communiquent pas entre eux, ils ne savent pas combien de requêtes les autres travailleurs envoient à un disque donné. Si les travailleurs stockent des données sur un seul disque, le nombre de requêtes sur le disque est limité (taille du lot multipliée par le nombre de travailleurs sur chaque disque). Si les travailleurs doivent accéder à tous les disques, les disques peuvent avoir jusqu'à (taille du lot multipliée par le nombre total de travailleurs) demandes en attente.

1.4 Ne soumettez pas de journaux

KVell ne reconnaît les mises à jour qu'une fois qu'elles ont été conservées sur le disque à l'emplacement final, sans s'appuyer sur un journal de validation. Une fois qu'une mise à jour est validée dans un thread de travail, elle sera conservée sur le disque dans le prochain lot d'E/S. La suppression du journal de validation permet à KVell d'utiliser la bande passante du disque uniquement pour le traitement utile des requêtes client.

2. Réalisation de KVELL

2.1 Interface d'exploitation client

KVell implémente les mêmes interfaces de base que les KV LSM :

  • L'écriture de Update(k,v)
    associe la valeur v à la clé k. Update(k,v) ne revient qu'après que la valeur a été conservée sur le disque
  • Lire Get(k)
    Get(k) renvoie la valeur la plus récente de k
  • Balayage de plage Balayage(k1,k2).
    Renvoie la plage d'éléments KV entre k1 et k2.

2.2 Structure des données du disque

Pour éviter la fragmentation, les éléments qui correspondent à la même plage de taille sont stockés dans le même fichier. Nous appelons ces fichiers des dalles. KVell accède au slab avec une granularité de bloc, qui correspond à la taille de la page (4 Ko) sur notre machine.

Si l'élément est plus petit que la taille de la page (par exemple, plusieurs éléments peuvent tenir sur une seule page), KVell ajoute l'élément dans la dalle avec un horodatage, une taille de clé et une taille de valeur. Les éléments supérieurs à 4K ont un en-tête d'horodatage au début de chaque bloc sur le disque. Les éléments qui sont plus petits que la taille de la page seront mis à jour sur place. Pour les articles plus volumineux, une mise à jour consiste à attacher l'article à la dalle, puis à écrire une pierre tombale à l'endroit où se trouvait l'article. Lorsqu'un élément change de taille, KVell écrit d'abord l'élément mis à jour dans la nouvelle dalle, puis le supprime de l'ancienne dalle.

2.3 Structures de données en mémoire

indice

KVell s'appuie sur des index en mémoire rapides et légers avec des temps d'insertion et de recherche prévisibles pour trouver l'emplacement des éléments sur le disque. KVell utilise un arbre B en mémoire pour chaque travailleur afin de stocker l'emplacement des éléments sur le disque. Les éléments sont indexés selon leur clé (préfixe). Nous utilisons des préfixes au lieu de hachages pour préserver l'ordre des clés pour les analyses de plage. Les arbres B fonctionnent mal lors du stockage de données moyennes / volumineuses, mais sont rapides lorsque les données tiennent (principalement) en mémoire et que les clés sont petites. KVell tire parti de cette propriété et n'utilise que des arbres B pour stocker les informations de recherche (les informations de préfixe et d'emplacement occupent 13B).

L'implémentation arborescente de KVell utilise actuellement une moyenne de 19 B par entrée (préfixe de stockage, informations de localisation et structure B-tree), ce qui équivaut à 1,7 Go de RAM pour stocker 100 M d'entrées. Sur une charge de travail YCSB (éléments de 1 Ko), l'index équivaut à 1,7 % de la taille de la base de données. Nous avons trouvé cette valeur raisonnable dans la pratique. KVell ne prend actuellement pas explicitement en charge le vidage des parties des arbres B sur le disque, mais les données des arbres B sont allouées à partir de fichiers mmap et peuvent être rappelées par le noyau.

cache de pages

KVell maintient son propre cache de page interne pour éviter de récupérer les pages fréquemment consultées à partir du stockage persistant. La taille de la page mise en cache est un paramètre système. Le cache de pages se souvient des pages mises en cache dans l'index et supprime les pages du cache dans l'ordre LRU.

S'assurer que les recherches et les insertions dans l'index ont une charge CPU minimale est essentiel pour de bonnes performances. Notre première implémentation de cache de page utilise une table de hachage uthash rapide comme index. Cependant, lorsque le cache de page est volumineux, les insertions dans le hachage peuvent prendre jusqu'à 100 ms (le temps de développer la table de hachage), ce qui augmente la latence de queue. Le passage aux arbres B supprime ces pics de latence.

liste gratuite

Lorsqu'un élément est supprimé d'une dalle, sa position dans cette dalle est insérée dans la pile de mémoire de chaque dalle, que nous appelons la liste libre de la dalle. Ensuite, écrivez une pierre tombale à l'emplacement du projet sur le disque. Pour lier l'utilisation de la mémoire, nous ne gardons en mémoire que les N derniers emplacements libérés (actuellement, N est défini sur 64). Son objectif est de limiter l'utilisation de la mémoire tout en conservant la possibilité de réutiliser plusieurs emplacements libres par lot d'E/S sans nécessiter d'accès disque supplémentaire.

Lorsque le (N+1)ème élément est libéré, KVell fait pointer son disque tombstone vers le premier emplacement libéré. Ensuite, KVell supprime le premier emplacement libéré de la pile mémoire et insère (N+1) emplacements libérés. Lorsque le (N+2)ème élément est libéré, sa pierre tombale pointe vers le deuxième emplacement libéré, et ainsi de suite. En un mot, KVell maintient N piles indépendantes dont les têtes résident en mémoire et le reste sur le disque. Cela permet à Kvell de réutiliser jusqu'à N points inactifs par lot d'E/S. S'il n'y a qu'une seule pile, KVell doit lire séquentiellement N pierres tombales du disque pour trouver les N prochains emplacements à libérer.

2.4 Exécution efficace des E/S

KVell s'appuie sur l'API d'E/S asynchrones de Linux (AIO) pour envoyer des requêtes au disque par lots de 64 requêtes maximum. En regroupant les requêtes, KVell amortit la surcharge des appels système sur plusieurs requêtes client. Nous avons choisi d'utiliser les E/S asynchrones Linux car cela nous permet d'effectuer plusieurs E/S avec un seul appel système. Nous estimons que les performances seraient à peu près les mêmes si de tels appels étaient disponibles dans l'API d'E/S synchrone.

Nous rejetons deux alternatives populaires pour effectuer des E/S : (1) utiliser mmap qui s'appuie sur le cache de page du système d'exploitation (par exemple, RocksDB) et (2) utiliser des appels système d'E/S en lecture et écriture directes (par exemple, TokuMX). Aucune de ces techniques n'est aussi efficace que l'utilisation d'une interface AIO. Le tableau 3 résume nos résultats, montrant le maximum d'IOPS réalisable sur Config-Optane, en écrivant de manière aléatoire dans des blocs de 4K (cela nécessite des opérations de lecture-modification-écriture sur l'appareil). L'ensemble de données auquel on accède est 3 fois plus volumineux que la RAM disponible.

Tableau 3. Config-Optane L'IOPS maximum dépend de la technologie d'accès au disque.

La première approche consiste à s'appuyer sur le cache de page au niveau du système d'exploitation. Les performances de cette approche ne sont pas optimales dans le cas d'un seul thread, car elle ne peut émettre qu'une seule lecture de disque à la fois lorsqu'un défaut de page se produit (la valeur de lecture anticipée est définie sur 0 car les données sont accessibles de manière aléatoire). De plus, les pages modifiées ne sont vidées sur le disque que périodiquement. Cela se traduit par des profondeurs de file d'attente sous-optimales dans la plupart des cas, suivies d'une rafale d'E/S. Lorsque l'ensemble de données ne tient pas complètement dans la RAM, le noyau doit également mapper et démapper des pages hors de l'espace d'adressage virtuel du processus, ce qui entraîne une surcharge CPU importante. Pour le multi-threading, le cache de page souffre d'une surcharge de verrouillage lors du vidage du LRU (tous les 32 Ko, un verrou est vidé sur le disque en moyenne) et de la rapidité avec laquelle le système invalide les entrées TLB pour les cœurs distants. En fait, lorsqu'une page est démappée de l'espace d'adressage virtuel, le mappage virtuel-physique doit être invalidé sur tous les cœurs qui ont accédé à la page, ce qui entraîne une surcharge énorme pour la communication IPI.

La deuxième méthode consiste à s'appuyer sur des E/S directes. Cependant, les appels système de lecture/écriture d'E/S directes ne remplissent pas la file d'attente du disque lorsque les requêtes sont exécutées de manière synchrone (chaque thread a une requête en attente). Cette technique est préférée à la méthode mmap car il n'est pas nécessaire de gérer la logique complexe de mappage et de démappage des pages de l'espace d'adressage virtuel.

En revanche, les E/S par lots ne nécessitent qu'un seul appel système par lot et permettent à KVell de contrôler la longueur de la file d'attente des périphériques pour une faible latence et une bande passante élevée. Bien que théoriquement les techniques de traitement par lots des E/S puissent être appliquées aux LSM et aux KV à arbre B, la mise en œuvre nécessitera des efforts considérables. Dans un arbre B, différentes opérations peuvent avoir des effets conflictuels sur les E/S (par exemple, une scission d'une feuille provoquée par une insertion suivie d'une fusion de deux feuilles). De plus, les données peuvent être déplacées sur le disque en raison de la réorganisation, ce qui rend également difficile le traitement par lots asynchrone des demandes. Le traitement par lots des demandes d'écriture a été implémenté dans les LSM KV via le composant mémoire. Cependant, le traitement par lots augmente légèrement la complexité du chemin de lecture, car le travailleur doit s'assurer que le thread de compactage ne supprime pas tous les fichiers qu'il doit lire.

2.5 Mise en œuvre de l'opération client

L'algorithme 1 résume l'architecture KVell. Pour plus de simplicité, l'algorithme n'affiche qu'une seule page d'éléments KV. Lorsqu'une requête entre dans le système, elle est affectée à un worker en fonction de sa clé (lignes 3 et 5, algorithme 1) Le thread worker effectue les E/S disque et gère la logique de la requête client.

obtenir (k). La lecture d'un élément (Lignes 17-22, Algorithme 1) implique l'obtention de son emplacement sur le disque à partir de l'index et la lecture de la page correspondante. Si la page est déjà mise en cache, aucun accès au stockage persistant n'est requis et les valeurs seront renvoyées de manière synchrone au client. Si ce n'est pas le cas, le travailleur qui traite la demande la place dans la file d'attente de son moteur d'E/S.

mise à jour(k,v). La mise à jour d'un élément (Lignes 24-35, Algorithme 1) implique d'abord la lecture de la page qui le stocke, la modification de la valeur, puis l'écriture de la page sur le disque. La suppression d'un élément implique l'écriture d'une valeur de désactivation et l'ajout de la position de l'élément à la liste libre de la dalle. Réutilise les emplacements libérés lors de l'ajout de nouveaux éléments ou ajoute des éléments s'il n'existe aucun emplacement libre. KVell confirme uniquement que la mise à jour est terminée lorsque l'élément mis à jour est entièrement conservé sur le disque (c'est-à-dire que l'appel système io_getevents nous informe que l'opération d'écriture sur le disque correspondant à la mise à jour est terminée (ligne 37 de l'algorithme 1). les données sont immédiatement vidées sur le disque, car le cache de page de KVell n'est pas utilisé pour les mises à jour de tampon. De cette façon, KVell offre des garanties de durabilité plus solides que les KV à la pointe de la technologie. Par exemple, RocksDB ne garantit la durabilité qu'à la granularité du journal de validation Synchronisation sur disque Dans une configuration typique, la synchronisation ne se produit que par lots de mises à jour.

Balayage(k1, k2). Une analyse consiste à (1) récupérer l'emplacement de la clé à partir de l'index et (2) lire la page correspondante. Pour calculer la liste des clés, KVell analyse tous les index : un thread verrouille, analyse et déverrouille simplement tous les index des travailleurs de manière séquentielle, et finalement fusionne les résultats pour obtenir une liste de clés à lire à partir du KVell. La lecture est ensuite effectuée à l'aide de la commande Get(), qui contourne la recherche d'index (puisque KVell a déjà accès à l'index). L'analyse est la seule opération qui doit être partagée entre les threads. KVell renvoie la dernière valeur associée à chaque touche touchée par le scan. En revanche, RocksDB et WiredTiger effectuent des analyses sur les instantanés KV.

2.6 Modèle de défaillance et récupération

L'implémentation actuelle de KVell est optimisée pour un fonctionnement sans problème. En cas de plantage, toutes les plaques sont scannées et l'index en mémoire est reconstruit. Même avec des analyses qui maximisent la bande passante séquentielle du disque, la récupération peut encore prendre quelques minutes sur de très grands ensembles de données.

Si un élément apparaît deux fois sur le disque (par exemple, un plantage survient lors de la migration d'un élément d'un slab à un autre), seul l'élément le plus récent est conservé dans l'index de la mémoire tandis que l'autre est inséré dans la liste libre. Pour les éléments plus grands que la taille du bloc, KVell utilise un en-tête d'horodatage pour supprimer les éléments qui ne sont que partiellement écrits.

KVell est conçu pour les lecteurs capables d'écrire automatiquement des pages de 4 Ko, même en cas de panne de courant. Cette contrainte peut être levée en évitant une modification sur place de la page, en écrivant la nouvelle valeur dans la nouvelle page, puis en ajoutant l'ancien emplacement à la liste libre de la dalle une fois la première opération d'écriture terminée.

ps: L'implémentation de ce papier est open source, KVELL

Résumer

KVELL est une solution de stockage de données relativement nouvelle, qui est principalement conçue pour les SSD dont les performances ont été continuellement améliorées ces dernières années.
Son cœur est l'index de mémoire + le stockage non séquentiel. Dans le même temps, il existe certaines optimisations pour SSD, telles que le mécanisme Slab similaire au fatcache, les E/S par lots sous-jacentes, la conception non partagée, etc.

En bref, KVELL est une solution de stockage conçue pour le stockage SSD moderne, et revient dans une certaine mesure à la manière originale de lire et d'écrire (lecture et écriture séquentielles -> lecture et écriture aléatoires).

Je dois soupirer, le charme du design réside dans le compromis !

Je suppose que tu aimes

Origine blog.csdn.net/qq_46101869/article/details/127970850
conseillé
Classement