Un journal trop gros pour un disque
Une chaîne de magasins garde un ticket pour chaque passage en caisse. En deux ans, le journal atteint 6 To. Aucun disque du siège ne le contient, et un seul ordinateur passerait une journée de travail entière rien qu'à le lire une fois.
Les outils de données massives découpent le fichier, rangent les morceaux sur de nombreuses machines et font travailler chaque machine sur son propre morceau.
À la fin de cette leçon
Remarque
Je peux expliquer comment un fichier est découpé et traité en parallèle.
Mots clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Bloc | un morceau de taille fixe d'un gros fichier | 128 Mo |
| NameNode | la machine qui sait où se trouve chaque bloc | |
| DataNode | une machine qui garde des blocs | |
| Réplique | une copie d'un bloc sur une autre machine | |
| Map | l'étape qui transforme chaque donnée en paires | |
| Reduce | l'étape qui additionne les paires d'une même clé |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
HDFS découpe un fichier en blocs
HDFS est le système de fichiers de Hadoop. Il découpe chaque fichier en blocs de taille fixe, 128 Mo par défaut. Le dernier bloc prend ce qui reste.
Chaque bloc est rangé sur un DataNode, puis copié ailleurs : une panne ne perd rien. Un seul NameNode tient la liste des blocs de chaque fichier et de leur emplacement.
Exemple : un fichier de 520 Mo
| Bloc | Taille | Copies gardées | Rangé sur |
|---|---|---|---|
| 1 à 4 | 128 Mo chacun | 3 chacun | trois DataNodes différents |
| 5 | 8 Mo | 3 | trois DataNodes différents |
| Total | 520 Mo | 15 copies | Le NameNode ne garde que la liste |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Compter les blocs d'un fichier
# Un fichier est découpé en blocs de taille fixe.
taille_mo = 520
bloc_mo = 128
entiers = taille_mo // bloc_mo
reste = taille_mo % bloc_mo
blocs = entiers
if reste > 0:
blocs = blocs + 1
print("blocs :", blocs)
print("taille du dernier bloc :", reste, "Mo")
copies = blocs * 3
print("copies gardées sur disque :", copies)
# Remplacez 520 par 900 puis relancez.
Votre labo est plus petit
Le laboratoire n'a qu'un seul DataNode. Il garde donc une seule copie de chaque bloc, pas trois. Les idées restent les mêmes : un vrai cluster ajoute des machines.
Le terminal du labo n'a pas la commande hadoop. Vous interrogez le cluster avec curl, par l'adresse web du NameNode.
Lister le dossier d'entrée du labo
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input?op=LISTSTATUS' | grep -o '"pathSuffix":"[^"]*"'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Demander sa taille de bloc et sa longueur
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input/sentence.txt?op=GETFILESTATUS' | grep -o '"blockSize":[0-9]*\|"length":[0-9]*'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Demander combien de copies HDFS garde
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input/sentence.txt?op=GETFILESTATUS' | grep -o '"replication":[0-9]*'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Demander la place prise par le dossier
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/input?op=GETCONTENTSUMMARY' | grep -o '"spaceConsumed":[0-9]*'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Une erreur fréquente
Attention
On croit souvent que le NameNode garde le fichier. Il ne garde que la liste des blocs et leur emplacement. Les octets sont sur les DataNodes. Demandez « qui a les octets ? » : la réponse est un DataNode.
MapReduce envoie le travail aux données
Copier 6 To à travers un réseau est lent. Hadoop envoie donc le petit programme aux machines qui détiennent déjà les blocs.
Chaque machine lance l'étape map sur son bloc, sans parler aux autres. Les paires sont ensuite regroupées par clé : c'est le mélange (shuffle en anglais). L'étape reduce additionne chaque groupe.
Exemple : compter les mots des tickets
| Étape | Bloc un | Bloc deux |
|---|---|---|
| Entrée | pain lait / lait riz | pain riz / pain lait |
| Map | pain 1, lait 1, lait 1, riz 1 | pain 1, riz 1, pain 1, lait 1 |
| Mélange (regroupé par mot) | pain : 1, 1, 1 / lait : 1, 1, 1 / riz : 1, 1 | Les paires des deux blocs se retrouvent ici |
| Reduce (addition) | pain 3, lait 3, riz 2 | Un seul total par mot |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Map et reduce en Python simple
# Deux blocs d'un journal de tickets de caisse.
bloc_un = ["pain lait", "lait riz"]
bloc_deux = ["pain riz", "pain lait"]
def appliquer_map(lignes):
# L'étape map : chaque mot devient une paire [mot, 1].
paires = []
for ligne in lignes:
for mot in ligne.split():
paires.append([mot, 1])
return paires
def appliquer_reduce(paires):
# L'étape reduce : on additionne les 1 de chaque mot.
totaux = {}
for paire in paires:
mot = paire[0]
if mot in totaux:
totaux[mot] = totaux[mot] + paire[1]
else:
totaux[mot] = paire[1]
return totaux
toutes = appliquer_map(bloc_un) + appliquer_map(bloc_deux)
print(appliquer_reduce(toutes))
# Ajoutez la ligne "riz thym" à bloc_deux puis relancez.
Un job laisse son résultat dans HDFS
Une exécution de MapReduce s'appelle un job. Le ResourceManager distribue le travail, et le résultat est écrit dans HDFS sous forme de fichiers.
Chaque reducer écrit un fichier nommé part-r- suivi d'un numéro. Un fichier vide nommé _SUCCESS indique que le job est terminé.
Lister le dossier de sortie du job
curl -s 'http://namenode:9870/webhdfs/v1/user/lab/wordcount-out?op=LISTSTATUS' | grep -o '"pathSuffix":"[^"]*"'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Lire le total du mot « the »
curl -s -L 'http://namenode:9870/webhdfs/v1/user/lab/wordcount-out/part-r-00000?op=OPEN' | grep '^the'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Demander comment le job a fini
curl -s http://resourcemanager:8088/ws/v1/cluster/apps | grep -o '"finalStatus":"[A-Z]*"'Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Pour aller plus loin : additionner avant d'envoyer
Le bloc deux envoie quatre paires au mélange, dont deux fois « pain 1 ». Un vrai job peut d'abord additionner à l'intérieur de chaque bloc. Cette étape s'appelle un combiner.
Modifiez appliquer_map dans le bloc MapReduce pour qu'elle rende les totaux de son propre bloc, sous forme de paires. Exécutez. Combien de paires quittent maintenant le bloc deux, et le résultat final change-t-il ?