HBase
 sql >> Base de données >  >> NoSQL >> HBase

Fractionnement et fusion de régions Apache HBase

Cet article de blog a été publié sur Hortonworks.com avant la fusion avec Cloudera. Certains liens, ressources ou références peuvent ne plus être exacts.

Pour cet article, nous approfondissons techniquement l'un des principaux domaines de HBase. Plus précisément, nous examinerons comment Apache HBase distribue la charge à travers les régions et gère le fractionnement des régions. HBase stocke des lignes de données dans des tables. Les tableaux sont divisés en blocs de lignes appelés « régions ». Ces régions sont réparties sur le cluster, hébergées et mises à la disposition des processus clients par le processus RegionServer. Une région est une plage continue dans l'espace clé, ce qui signifie que toutes les lignes de la table triées entre la clé de début et la clé de fin de la région sont stockées dans la même région. Les régions ne se chevauchent pas, c'est-à-dire qu'une seule clé de ligne appartient à exactement une région à tout moment. Une région n'est desservie que par un seul serveur de région à tout moment, c'est ainsi que HBase garantit une forte cohérence au sein d'une seule ligne #. Avec -ROOT- et .META. régions, les régions d'une table forment effectivement un arbre B à 3 niveaux dans le but de localiser une ligne dans une table.

Une Région quant à elle, se compose de plusieurs « Magasins », qui correspondent à des familles de colonnes. Un magasin contient un memstore et zéro ou plusieurs fichiers de magasin. Les données de chaque famille de colonnes sont stockées et accessibles séparément.

Une table se compose généralement de plusieurs régions, qui sont à leur tour hébergées par de nombreux serveurs de région. Ainsi, les régions sont le mécanisme physique utilisé pour répartir la charge d'écriture et de requête sur les serveurs de région. Lorsqu'une table est créée pour la première fois, HBase, par défaut, n'alloue qu'une seule région pour la table. Cela signifie qu'initialement, toutes les requêtes iront à un seul serveur de région, quel que soit le nombre de serveurs de région. C'est la principale raison pour laquelle les phases initiales de chargement des données dans une table vide ne peuvent pas utiliser toute la capacité du cluster.

Pré-split

La raison pour laquelle HBase ne crée qu'une seule région pour la table est qu'il ne peut pas savoir comment créer les points de partage dans l'espace de clé de ligne. La prise de telles décisions est fortement basée sur la distribution des clés dans vos données. Plutôt que de deviner et de vous laisser gérer les conséquences, HBase vous fournit des outils pour gérer cela depuis le client. Avec un processus appelé pré-fractionnement, vous pouvez créer une table avec de nombreuses régions en fournissant les points de fractionnement au moment de la création de la table. Étant donné que le pré-fractionnement garantit que la charge initiale est répartie plus uniformément dans le cluster, vous devez toujours envisager de l'utiliser si vous connaissez à l'avance la distribution de votre clé. Cependant, le pré-fractionnement présente également un risque de créer des régions, qui ne répartissent pas vraiment la charge uniformément en raison de l'asymétrie des données ou en présence de lignes très chaudes ou volumineuses. Si l'ensemble initial de points de partage de région est mal choisi, vous risquez de vous retrouver avec une distribution de charge hétérogène, ce qui limitera à son tour les performances de vos clusters.

Il n'y a pas de réponse courte pour le nombre optimal de régions pour une charge donnée, mais vous pouvez commencer avec un multiple inférieur du nombre de serveurs de région en nombre de divisions, puis laisser la division automatisée s'occuper du reste.

Un problème avec le pré-fractionnement est le calcul des points de partage pour la table. Vous pouvez utiliser l'utilitaire RegionSplitter. RegionSplitter crée les points de partage en utilisant un SplitAlgorithm enfichable. HexStringSplit et UniformSplit sont deux algorithmes prédéfinis. Le premier peut être utilisé si les clés de ligne ont un préfixe pour les chaînes hexadécimales (comme si vous utilisez des hachages comme préfixes). Ce dernier divise l'espace clé de manière égale en supposant qu'il s'agit de tableaux d'octets aléatoires. Vous pouvez également implémenter votre SplitAlgorithm personnalisé et l'utiliser à partir de l'utilitaire RegionSplitter.

$ hbase org.apache.hadoop.hbase.util.RegionSplitter test_table HexStringSplit -c 10 -f f1

où -c 10, spécifie le nombre de régions demandé comme 10, et -f spécifie les familles de colonnes que vous voulez dans le tableau, séparées par ":". L'outil créera une table nommée "test_table" avec 10 régions :

13/01/18 18:49:32 DEBUG hbase.HRegionInfo: Current INFO from scan results = {NAME => 'test_table,,1358563771069.acc1ad1b7962564fc3a43e5907e8db33.', STARTKEY => '', ENDKEY => '19999999', ENCODED => acc1ad1b7962564fc3a43e5907e8db33,}
13/01/18 18:49:32 DEBUG hbase.HRegionInfo: Current INFO from scan results = {NAME => 'test_table,19999999,1358563771096.37ec12df6bd0078f5573565af415c91b.', STARTKEY => '19999999', ENDKEY => '33333332', ENCODED => 37ec12df6bd0078f5573565af415c91b,}
...

Si vous avez des points de partage à portée de main, vous pouvez également utiliser le shell HBase pour créer le tableau avec les points de partage souhaités.

hbase(main):015:0> create 'test_table', 'f1', SPLITS=> ['a', 'b', 'c']

ou

$ echo -e  "anbnc" >/tmp/splits
hbase(main):015:0> create 'test_table', 'f1', SPLITSFILE=>'/tmp/splits'

Pour une répartition optimale de la charge, vous devez penser à votre modèle de données et à la répartition des clés pour choisir le bon algorithme de fractionnement ou les bons points de fractionnement. Quelle que soit la méthode que vous avez choisie pour créer la table avec un nombre prédéterminé de régions, vous pouvez maintenant commencer à charger les données dans la table et voir que la charge est répartie dans votre cluster. Vous pouvez laisser le fractionnement automatisé prendre le relais une fois que l'ingestion des données a commencé et surveiller en permanence le nombre total de régions pour la table.

Fractionnement automatique

Que le pré-splittage soit utilisé ou non, une fois qu'une région atteint une certaine limite, elle est automatiquement divisée en deux régions. Si vous utilisez HBase 0.94 (fourni avec HDP-1.2), vous pouvez configurer le moment où HBase décide de diviser une région et la manière dont il calcule les points de division via l'API enfichable RegionSplitPolicy. Il existe quelques règles de fractionnement de région prédéfinies :ConstantSizeRegionSplitPolicy, AugmentationToUpperBoundRegionSplitPolicy et KeyPrefixRegionSplitPolicy.

La première est la stratégie par défaut et uniquement fractionnée pour les versions HBase antérieures à 0.94. Il divise les régions lorsque la taille totale des données pour l'un des magasins (correspondant à une famille de colonnes) dans la région devient supérieure à « hbase.hregion.max.filesize » configuré, qui a une valeur par défaut de 10 Go. Cette politique de fractionnement est idéale dans les cas où vous avez effectué un pré-fractionnement et souhaitez obtenir un nombre inférieur de régions par serveur de région.

La stratégie de fractionnement par défaut pour HBase 0.94 et le tronc est AugmentationToUpperBoundRegionSplitPolicy, qui effectue un fractionnement plus agressif en fonction du nombre de régions hébergées sur le même serveur de région. La stratégie de fractionnement utilise la taille maximale du fichier de magasin basée sur Min (R^2 * "hbase.hregion.memstore.flush.size", "hbase.hregion.max.filesize"), où R est le nombre de régions du même table hébergée sur le même serveur de région. Ainsi, par exemple, avec la taille de vidage du magasin de mémoire par défaut de 128 Mo et la taille de magasin maximale par défaut de 10 Go, la première région sur le serveur de région sera divisée juste après le premier vidage à 128 Mo. Au fur et à mesure que le nombre de régions hébergées dans le serveur de région augmente, il utilisera des tailles de division croissantes :512 Mo, 1 152 Mo, 2 Go, 3,2 Go, 4,6 Go, 6,2 Go, etc. Après avoir atteint 9 régions, la taille de division ira au-delà de la configuration .hregion.max.filesize », à quel point, une taille fractionnée de 10 Go sera utilisée à partir de là. Pour ces deux algorithmes, quel que soit le moment où le fractionnement se produit, le point de fractionnement utilisé est la clé de ligne qui correspond au point médian de "l'index de bloc" pour le plus grand fichier de magasin dans le plus grand magasin.

KeyPrefixRegionSplitPolicy est un curieux ajout à l'arsenal HBase. Vous pouvez configurer la longueur du préfixe de vos clés de ligne pour les regrouper, et cette politique de fractionnement garantit que les régions ne sont pas fractionnées au milieu d'un groupe de lignes ayant le même préfixe. Si vous avez défini des préfixes pour vos clés, vous pouvez utiliser cette stratégie de fractionnement pour vous assurer que les lignes ayant le même préfixe de clé de ligne se retrouvent toujours dans la même région. Ce regroupement d'enregistrements est parfois appelé « groupes d'entités » ou « groupes de lignes ». Il s'agit d'une fonctionnalité clé lorsque vous envisagez d'utiliser la fonctionnalité "transactions locales" (lien alternatif) dans la conception de votre application.

Vous pouvez configurer la stratégie de fractionnement par défaut à utiliser en définissant la configuration « hbase.regionserver.region.split.policy » ou en configurant le descripteur de table. Pour vous les âmes courageuses, vous pouvez également implémenter votre propre politique de fractionnement personnalisée et la brancher au moment de la création de la table ou en modifiant une table existante :

HTableDescriptor tableDesc = new HTableDescriptor("example-table");
tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, AwesomeSplitPolicy.class.getName());
//add columns etc
admin.createTable(tableDesc);

Si vous effectuez un pré-fractionnement et que vous souhaitez gérer manuellement les fractionnements de région, vous pouvez également désactiver les fractionnements de région en définissant « hbase.hregion.max.filesize » sur un nombre élevé et en définissant la politique de fractionnement sur ConstantSizeRegionSplitPolicy. Cependant, vous devez utiliser une valeur de sauvegarde de l'ordre de 100 Go, afin que les régions ne dépassent pas les capacités d'un serveur de région. Vous pouvez envisager de désactiver le fractionnement automatisé et vous fier à l'ensemble initial de régions du pré-fractionnement, par exemple, si vous utilisez des hachages uniformes pour vos préfixes de clé, et vous pouvez vous assurer que la charge en lecture/écriture de chaque région ainsi que sa taille est uniforme dans toutes les régions du tableau.

Fractionnements forcés

HBase permet également aux clients de forcer le fractionnement d'une table en ligne du côté client. Par exemple, le shell HBase peut être utilisé pour diviser toutes les régions de la table, ou diviser une région, éventuellement en fournissant un point de division.

hbase(main):024:0> split 'b07d0034cbe72cb040ae9cf66300a10c', 'b'
0 row(s) in 0.1620 seconds

Avec une surveillance attentive de votre distribution de charge HBase, si vous constatez que certaines régions reçoivent des charges inégales, vous pouvez envisager de fractionner manuellement ces régions pour égaliser la charge et améliorer le débit. Une autre raison pour laquelle vous voudrez peut-être effectuer des fractionnements manuels est lorsque vous constatez que les fractionnements initiaux pour la région s'avèrent sous-optimaux et que vous avez désactivé les fractionnements automatisés. Cela peut arriver, par exemple, si la distribution des données change au fil du temps.

Comment les fractionnements régionaux sont mis en œuvre

Lorsque les demandes d'écriture sont gérées par le serveur de région, elles s'accumulent dans un système de stockage en mémoire appelé "memstore". Une fois que le magasin de mémoire est rempli, son contenu est écrit sur le disque sous forme de fichiers de magasin supplémentaires. Cet événement est appelé "memstore flush". Au fur et à mesure que les fichiers de stockage s'accumulent, le RegionServer les "compacte" en fichiers combinés plus volumineux. Après chaque fin de vidage ou de compactage, une demande de division de région est mise en file d'attente si RegionSplitPolicy décide que la région doit être divisée en deux. Étant donné que tous les fichiers de données dans HBase sont immuables, lorsqu'une scission se produit, les régions filles nouvellement créées ne réécriront pas toutes les données dans de nouveaux fichiers. Au lieu de cela, ils créeront de petits fichiers de type lien symbolique, nommés fichiers de référence, qui pointent vers la partie supérieure ou inférieure du fichier de magasin parent en fonction du point de division. Le fichier de référence sera utilisé comme un fichier de données normal, mais seulement la moitié des enregistrements. La région ne peut être scindée que s'il n'y a plus de références aux fichiers de données immuables de la région parent. Ces fichiers de référence sont progressivement nettoyés par des compactages, de sorte que la région cesse de se référer à ses fichiers parents et puisse être divisée davantage.

Bien que la division de la région soit une décision locale prise au niveau du RegionServer, le processus de division lui-même doit être coordonné avec de nombreux acteurs. Le RegionServer informe le maître avant et après la scission, met à jour le .META. table afin que les clients puissent découvrir les nouvelles régions filles et réorganise la structure de répertoires et les fichiers de données dans HDFS. Split est un processus multi-tâches. Pour activer la restauration en cas d'erreur, le RegionServer conserve un journal en mémoire sur l'état d'exécution. Les étapes suivies par le RegionServer pour exécuter la scission sont illustrées par la figure 1. Chaque étape est étiquetée avec son numéro d'étape. Les actions de RegionServers ou Master sont affichées en rouge, tandis que les actions des clients sont affichées en vert.

1. RegionServer décide localement de diviser la région et prépare la division. Dans un premier temps, il crée un znode dans zookeeper sous /hbase/region-in-transition/region-name dans l'état SPLITTING.
2. Le maître prend connaissance de ce znode, car il dispose d'un observateur pour le znode parent de la région en transition.
3. RegionServer crée un sous-répertoire nommé ".splits" sous le répertoire de la région parent dans HDFS.
4. RegionServer ferme la région parente, force un vidage du cache et marque la région comme étant hors ligne dans ses structures de données locales. À ce stade, les demandes des clients arrivant dans la région parent lèveront NotServingRegionException. Le client va réessayer avec une pause.
5. RegionServer crée les répertoires de région sous le répertoire .splits, pour les régions filles A et B, et crée les structures de données nécessaires. Ensuite, il divise les fichiers de magasin, dans le sens où il crée deux fichiers de référence par fichier de magasin dans la région parent. Ces fichiers de référence pointeront vers les fichiers des régions parentes.
6. RegionServer crée le répertoire de région réel dans HDFS et déplace les fichiers de référence pour chaque fille.
7. RegionServer envoie une requête Put au .META. table et définit le parent comme étant hors ligne dans le fichier .META. table et ajoute des informations sur les régions filles. À ce stade, il n'y aura pas d'entrées individuelles dans .META. pour les filles. Les clients verront que la région parente est divisée s'ils scannent .META., mais ne connaîtront pas les filles tant qu'elles n'apparaissent pas dans .META. réussit, le parent sera effectivement divisé. Si le RegionServer échoue avant que ce RPC réussisse, le maître et le prochain serveur de région ouvrant la région nettoieront l'état sale de la division de la région. Après le .META. mise à jour, cependant, la division de la région sera reportée par Master.
8. RegionServer ouvre les filles en parallèle pour accepter les écritures.
9. RegionServer ajoute les filles A et B à .META. ainsi que des informations qu'il héberge les régions. Après ce point, les clients peuvent découvrir les nouvelles régions et envoyer des demandes à la nouvelle région. Les clients mettent en cache le .META. entrées localement, mais lorsqu'ils font des demandes au serveur de région ou à .META., leurs caches seront invalidés et ils apprendront les nouvelles régions à partir de .META..
10. RegionServer met à jour znode /hbase/region-in-transition/region-name dans zookeeper pour indiquer SPLIT, afin que le maître puisse en prendre connaissance. L'équilibreur peut librement réaffecter les régions filles à d'autres serveurs de région s'il le souhaite.
11. Après la scission, meta et HDFS contiendront toujours des références à la région parente. Ces références seront supprimées lorsque les compactages dans les régions filles réécriront les fichiers de données. Les tâches de récupération de place dans le maître vérifient périodiquement si les régions filles font toujours référence aux fichiers parents. Sinon, la région parente sera supprimée.

Fusion de régions

Contrairement au fractionnement de région, HBase à ce stade ne fournit pas d'outils utilisables pour fusionner des régions. Bien qu'il existe des outils HMerge et Merge, ils ne sont pas très adaptés à un usage général. Il n'y a actuellement aucune prise en charge des tables en ligne et de la fonctionnalité de fusion automatique. Cependant, avec des problèmes tels que OnlineMerge, les fusions de régions automatiques initiées par le maître, les verrous de lecture/écriture basés sur ZK pour les opérations de table, nous travaillons pour stabiliser les divisions de régions et permettre une meilleure prise en charge des fusions de régions. Restez à l'écoute !

Conclusion

Comme vous pouvez le voir, HBase sous le capot fait beaucoup de ménage pour gérer les divisions de régions et effectuer un partitionnement automatisé à travers les régions. Cependant, HBase fournit également les outils nécessaires pour la gestion des régions, afin que vous puissiez gérer le processus de fractionnement. Vous pouvez également contrôler précisément quand et comment les divisions de région se produisent via une RegionSplitPolicy.

Le nombre de régions dans une table et la manière dont ces régions sont divisées sont des facteurs cruciaux pour comprendre et régler la charge de votre cluster HBase. Si vous pouvez estimer votre distribution de clés, vous devez créer la table avec un fractionnement préalable pour obtenir des performances de chargement initiales optimales. Vous pouvez commencer avec un multiple inférieur du nombre de serveurs de région comme point de départ pour le nombre initial de régions, et laisser le fractionnement automatisé prendre le relais. Si vous ne pouvez pas estimer correctement les points de partage initiaux, il est préférable de créer simplement la table avec une région, de commencer un chargement initial avec un fractionnement automatisé et d'utiliser AugmentationToUpperBoundRegionSplitPolicy. Cependant, gardez à l'esprit que le nombre total de régions se stabilisera au fil du temps et que l'ensemble actuel de points de division de région sera déterminé à partir des données que la table a reçues jusqu'à présent. Vous souhaiterez peut-être surveiller la répartition de la charge dans les régions à tout moment, et si la répartition de la charge change au fil du temps, utilisez le fractionnement manuel ou définissez des tailles de fractionnement de région plus agressives. Enfin, vous pouvez essayer la fonctionnalité de fusion en ligne à venir et apporter votre cas d'utilisation.