table des matières
Distance entre les nœuds de topologie du réseau
Distance de nœud : somme des distances entre deux nœuds et l'ancêtre commun le plus proche.
Si le nœud n1 sur le rack r1 dans le centre de données d1 est défini comme / d1 / r1 / n1, les résultats suivants seront obtenus:
- distance (/ d1 / r1 / n1, / d1 / r1 / n1) = 0 (deux applications sur le même nœud)
- distance (/ d1 / r1 / n1, / d1 / r1 / n2) = 2 (deux nœuds sur le même rack)
- distance (/ d1 / r1 / n1, / d1 / r2 / n3) = 4 (deux nœuds sur des racks différents dans le même centre de données)
- distance (/ d1 / r1 / n1, / d2 / r3 / n4) = 6 (deux nœuds dans différents centres de données)
Processus de lecture
Comme le montre la figure ci-dessous, supposons que le client HDFS ait besoin de lire le fichier one.txt et que le fichier one.txt soit divisé en deux blocs de données, BlockA et BlockB . Le nombre de copies est de 3. BlockA est stocké dans D2, D5, D7; BlockB est stocké dans D3, D9, D11.
Le client HDFS communique avec NameNode
- Étant donné que le NameNode stocke les métadonnées du bloc de données de one.txt, le client doit envoyer une demande au NameNode pour une liste de DataNodes qui stockent le bloc de données de one.txt.
- NameNode reçoit la demande du client et vérifie d'abord les autorisations de l'utilisateur client. Si l'utilisateur client dispose des autorisations suffisantes, le NameNode vérifie alors si le fichier demandé existe. S'il existe, le NameNode enverra une liste de DataNodes qui stockent des blocs de données de one.txt (les DataNodes de la liste sont classés par ordre décroissant de la distance entre le client et le DataNode). En même temps, le NameNode donnera au client un jeton de sécurité . Lorsque le client accède au DataNode, il doit utiliser le jeton pour l'authentification.
Le client HDFS communique avec DataNode
- Lorsque le client reçoit la liste DataNode envoyée par le NameNode, le client communique directement avec le DataNode. Envoyez une requête au DataNode (BlockA en D2 et BlockB en D3) le plus proche du client via l' objet FSDataInputStream . Parmi eux, DFSInputStream gère la communication entre le client et le DataNode.
- L'utilisateur client affiche le jeton de sécurité donné par le NameNode au DataNode, puis commence à lire les données du DataNode, et les données circuleront du DataNode vers le client dans un flux.
- Après avoir lu tous les blocs de données, le client appelle la méthode close () pour fermer FSDataInputStream.
Le processus détaillé de lecture des données HDFS
- Le client appelle la méthode open () de FileSystem (DistributedFileSystem implémente FileSystem dans le système de fichiers HDFS).
- DistributedFileSystem appelle à distance le NameNode via RPC pour demander l'emplacement du DataNode qui stocke les premiers blocs de données de one.txt. Ensuite, le NameNode renvoie les adresses de tous les DataNodes qui stockent le bloc de données (NameNode trie les DataNodes en fonction de la distance du client)
- Après open (), DistributedFileSystem renvoie un flux d' entrée FSDataInputStream au client. Pour HDFS, le flux d'entrée spécifique est DFSInputStream et DistributedFileSystem utilisera DFSInputStream pour instancier FSDataInputStream.
- Le client appelle la méthode read () pour lire les données. Le flux d'entrée DFSInputStream sélectionne le DataNode le plus proche du client pour établir une connexion et lire les données en fonction des résultats de tri obtenus. Ensuite, les données circulent du DataNode vers le client sous la forme d'un flux.
- Lorsque le bloc de données est lu, DFSInputStream ferme la connexion avec le DataNode. Envoyez ensuite une requête au NameNode pour obtenir l'emplacement du bloc de données suivant (si le cache client contient déjà les informations du bloc de données, il n'est pas nécessaire de demander le NameNode)
- Trouvez le meilleur DataNode pour le bloc de données suivant et lisez les données.
- Si une erreur se produit entre le DFSInputStream et le DataNode communicant pendant le processus de lecture, le client sélectionnera un autre DataNode le plus proche de lui. DFSInputStream marquera également les DataNodes qui n'ont pas réussi à éviter de lire ces DataNodes dans le bloc suivant. En même temps, DFSInputStream vérifiera la somme de contrôle des données. Si une erreur est détectée, il signalera au NameNode puis lira les autres DataNodes.
- Lorsque le client lit toutes les données, il appelle close () de FSDataInputStream pour fermer le flux d'entrée.
Code
public static void read() throws IOException, InterruptedException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), conf , "root");
FSDataInputStream fis = fs.open(new Path("/picture.jpg"));
FileOutputStream fos = new FileOutputStream("picture.jpg");
int numBytes = 0;
byte[] buffer = new byte[1024];
while ((numBytes = fis.read(buffer)) > 0) {
fos.write(buffer, 0, numBytes);
}
fis.close();
fos.close();
fs.close();
}
Écrire des données
Dans une opération d'écriture, DFSOutputStream maintient deux files d'attente, à savoir une file d'attente de données (file d'attente de données) et la file d'attente d'accusé de réception ( file d'attente d'acquittement ).
Supposons que vous souhaitiez écrire le fichier two.txt sur HDFS (supposez que le NameNode a déjà écrit les informations de two.txt et que le DataNode a déjà écrit les données. Il est un peu difficile de dessiner les deux processus dans le diagramme statique, vous pouvez donc comprendre la signification)
Le client HDFS communique avec NameNode
- Pour écrire le fichier two.txt sur HDFS, le client doit lancer une requête au NameNode. Le NameNode vérifie d'abord les autorisations de l'utilisateur client. Si l'utilisateur dispose d'autorisations suffisantes et qu'il n'y a pas de fichier portant le même nom, le NameNode crée un enregistrement correspondant (métadonnées) pour le fichier. Si le fichier existe déjà, la création du fichier échoue et une IOException est signalée.
- Le NameNode fournit au client les adresses de tous les DataNodes qui peuvent écrire le fichier two.txt, et le NameNode donnera au client un jeton de sécurité. Avant que le client n'écrive le DataNode, le jeton est utilisé pour l'authentification.
Le client HDFS communique avec DataNode
- Une fois que le client a reçu la liste DataNode et autorisé l'autorisation d'écriture du NameNode, le client obtient la liste DataNode et l'autorisation d'écriture autorisée, et écrit directement les données dans le premier DataNode de la liste. Lorsqu'un DataNode est en cours d'écriture, il effectuera une copie vers un autre DataNode en fonction du facteur de nombre de copies. Si le facteur de nombre de copies est de 3, il y a au moins 3 copies de blocs de données sur différents DataNodes.
- Lorsque la copie est créée, le DataNode enverra un message de confirmation au client. Un pipeline est formé entre chaque DataNode.
Le processus détaillé de lecture des données HDFS
- Le client appelle la méthode create () de FileSystem ( DistributedFileSystem implémente FileSystem dans le système de fichiers HDFS).
- DistributedFileSystem appelle NameNode à distance via RPC pour créer un nouveau fichier two.txt dans l'espace de noms du système de fichiers.
- Le NameNode vérifie les autorisations de l'utilisateur client et vérifie également si le fichier two.txt existe. Si l'utilisateur dispose d'autorisations suffisantes et qu'il n'existe aucun fichier portant le même nom, le NameNode crée le fichier et ajoute les informations sur le fichier.
- Une fois l'appel de la méthode distante terminé, DistributedFileSystem renvoie un flux de sortie FSDataOutputStream au client, et cet objet encapsule un DFSOutputStream. Le client utilise write () pour écrire des données sur HDFS.
- Lorsque le client commence à écrire des données, DFSOutputStream divise les données du client en plusieurs paquets de données et écrit ces paquets dans une file d'attente de données interne. Parmi eux, DataStreamer utilise cette file d'attente de données pour s'appliquer au NameNode pour plusieurs DataNodes qui enregistrent des fichiers et dupliquent des blocs de données. Ces DataNodes formeront un pipeline de flux de données, et le nombre de DataNodes dans le pipeline est déterminé par le nombre de réplicas. DataStreamer envoie le paquet de données au premier DataNode du pipeline, et le premier DataNode enregistre le paquet de données et l'envoie au second DataNode. De même, le deuxième DataNode l'enregistre et l'envoie au DataNode suivant, et ainsi de suite.
- DFSOutputStream gère également une file d'attente de confirmation pour la réception des informations de confirmation du DataNode. Une fois que le DataNode crée une copie, il envoie une confirmation pour garantir l'intégrité des données. Les informations de confirmation circulent en amont le long du pipeline de flux de données, passent à tour de rôle par chaque DataNode et sont finalement envoyées au client. Lorsque le client reçoit la confirmation, il supprime le paquet correspondant de la file d'attente de confirmation jusqu'à ce que toutes les confirmations soient reçues.
- Le client appelle la méthode close () pour fermer le flux de sortie, il videra toutes les données restantes dans le pipeline DataNode et attendra la confirmation. Lorsque la file d'attente de confirmation de DFSOutputStream reçoit toutes les confirmations, elle appelle complete () pour indiquer au NameNode d'écrire le fichier.
Que se passe-t-il si le DataNode échoue lors de l'écriture des données
Lors de l'écriture de données, si le DataNode échoue, les opérations suivantes se produiront et ces opérations sont transparentes pour le client.
- Le pipeline sera fermé et les paquets de données dans la file d'attente de confirmation seront ajoutés au début de la file d'attente de données pour garantir que les paquets de données qui ont été envoyés au DataNode ne sont pas perdus.
- Le bloc de données actuel sur le DataNode normal obtient un nouvel identificateur, puis cet identificateur est envoyé au NameNode afin que le DataNode défaillant puisse être récupéré et que le bloc de données sur ce DataNode puisse être supprimé.
- Supprimez le DataNode défaillant du pipeline et construisez un nouveau pipeline pour les DataNodes normaux restants, et les données restantes seront écrites dans le DataNode normal via le nouveau pipeline.
- Lorsque le NameNode détecte que le bloc de données n'est pas suffisamment répliqué, il s'arrangera pour créer une copie supplémentaire sur un autre DataNode. Les autres blocs de données à venir sont écrits normalement.
Code
public static void write() throws IOException, InterruptedException, URISyntaxException {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), conf , "root");
FileInputStream fis = new FileInputStream("picture.jpg");
FSDataOutputStream fos = fs.create(new Path("/picture.jpg"));
int numBytes = 0;
byte[] buffer = new byte[1024];
while ((numBytes = fis.read(buffer)) > 0) {
fos.write(buffer, 0, numBytes);
}
fis.close();
fos.close();
fs.close();
}
S'il y a une erreur, veuillez signaler (ง • ̀_ • ́) ง (* • ̀ ㅂ • ́) و