Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
| eadl:bloc5:fm3:td1 [2026/09/15 18:15] – [7. Générer un fichier de ventes] jcheron | eadl:bloc5:fm3:td1 [2026/09/17 14:29] (Version actuelle) – jcheron | ||
|---|---|---|---|
| Ligne 43: | Ligne 43: | ||
| ===== 3. Architecture utilisée ===== | ===== 3. Architecture utilisée ===== | ||
| - | <sxh> | + | <html>< |
| - | +-----------------+ | + | <code> |
| - | | ResourceManager | + | ┌─────────────────┐ |
| - | | | + | │ ResourceManager |
| - | +--------+--------+ | + | │ |
| - | | + | └────────┬────────┘ |
| - | | + | |
| - | | + | |
| - | +------v------+ | + | |
| - | | NodeManager | + | ┌──────▼──────┐ |
| - | | | + | │ NodeManager |
| - | +--------------+ | + | │ |
| - | | + | └─────────────┘ |
| - | | + | |
| - | | + | |
| - | +--------v--------+ | + | |
| - | | | + | ┌────────▼────────┐ |
| - | | Métadonnées HDFS| | + | │ |
| - | +-----------------+ | + | │ Métadonnées HDFS│ |
| - | </sxh> | + | └─────────────────┘ |
| + | </code> | ||
| + | < | ||
| ^ Composant ^ Rôle ^ | ^ Composant ^ Rôle ^ | ||
| | NameNode | Gère les métadonnées HDFS | | | NameNode | Gère les métadonnées HDFS | | ||
| Ligne 100: | Ligne 101: | ||
| git clone https:// | git clone https:// | ||
| cd docker-hadoop | cd docker-hadoop | ||
| + | </ | ||
| + | |||
| + | copier le fichier docker-compose.yml sous **docker-compose.yml.back** : | ||
| + | |||
| + | Remplacer l' | ||
| + | <sxh yml> | ||
| + | version: " | ||
| + | |||
| + | services: | ||
| + | namenode: | ||
| + | image: bde2020/ | ||
| + | container_name: | ||
| + | restart: always | ||
| + | ports: | ||
| + | - 9870:9870 | ||
| + | - 9000:9000 | ||
| + | volumes: | ||
| + | - hadoop_namenode:/ | ||
| + | environment: | ||
| + | - CLUSTER_NAME=test | ||
| + | env_file: | ||
| + | - ./ | ||
| + | datanode1: | ||
| + | image: bde2020/ | ||
| + | container_name: | ||
| + | restart: always | ||
| + | ports: | ||
| + | - " | ||
| + | volumes: | ||
| + | - hadoop_datanode1:/ | ||
| + | environment: | ||
| + | SERVICE_PRECONDITION: | ||
| + | env_file: | ||
| + | - ./ | ||
| + | datanode2: | ||
| + | image: bde2020/ | ||
| + | container_name: | ||
| + | restart: always | ||
| + | ports: | ||
| + | - " | ||
| + | volumes: | ||
| + | - hadoop_datanode2:/ | ||
| + | environment: | ||
| + | SERVICE_PRECONDITION: | ||
| + | env_file: | ||
| + | - ./ | ||
| + | datanode3: | ||
| + | image: bde2020/ | ||
| + | container_name: | ||
| + | restart: always | ||
| + | ports: | ||
| + | - " | ||
| + | volumes: | ||
| + | - hadoop_datanode3:/ | ||
| + | environment: | ||
| + | SERVICE_PRECONDITION: | ||
| + | env_file: | ||
| + | - ./ | ||
| + | resourcemanager: | ||
| + | image: bde2020/ | ||
| + | container_name: | ||
| + | restart: always | ||
| + | ports: | ||
| + | - " | ||
| + | environment: | ||
| + | SERVICE_PRECONDITION: | ||
| + | env_file: | ||
| + | - ./ | ||
| + | nodemanager1: | ||
| + | image: bde2020/ | ||
| + | container_name: | ||
| + | restart: always | ||
| + | ports: | ||
| + | - " | ||
| + | environment: | ||
| + | SERVICE_PRECONDITION: | ||
| + | env_file: | ||
| + | - ./ | ||
| + | historyserver: | ||
| + | image: bde2020/ | ||
| + | container_name: | ||
| + | restart: always | ||
| + | ports: | ||
| + | - " | ||
| + | environment: | ||
| + | SERVICE_PRECONDITION: | ||
| + | volumes: | ||
| + | - hadoop_historyserver:/ | ||
| + | env_file: | ||
| + | - ./ | ||
| + | volumes: | ||
| + | hadoop_namenode: | ||
| + | hadoop_datanode1: | ||
| + | hadoop_datanode2: | ||
| + | hadoop_datanode3: | ||
| + | hadoop_historyserver: | ||
| </ | </ | ||
| Ligne 118: | Ligne 215: | ||
| <sxh> | <sxh> | ||
| namenode | namenode | ||
| - | datanode | + | datanode1 |
| + | datanode2 | ||
| + | datanode3 | ||
| resourcemanager | resourcemanager | ||
| nodemanager | nodemanager | ||
| historyserver | historyserver | ||
| + | </ | ||
| + | |||
| + | Vérifier les hosts créés : | ||
| + | |||
| + | <sxh bash; | ||
| + | docker exec -it namenode hdfs dfsadmin -report | ||
| </ | </ | ||
| Ligne 130: | Ligne 235: | ||
| | ResourceManager | [[http:// | | ResourceManager | [[http:// | ||
| | NodeManager | [[http:// | | NodeManager | [[http:// | ||
| + | | DataNode1| [[http:// | ||
| + | | DataNode2| [[http:// | ||
| + | | DataNode3| [[http:// | ||
| <WRAP info round> | <WRAP info round> | ||
| Ligne 162: | Ligne 270: | ||
| On considère l’architecture suivante : | On considère l’architecture suivante : | ||
| - | <sxh gutter: | + | <html>< |
| + | <code> | ||
| Serveur unique | Serveur unique | ||
| │ | │ | ||
| Ligne 169: | Ligne 278: | ||
| ├── clics_j1.csv | ├── clics_j1.csv | ||
| └── application.log | └── application.log | ||
| - | </sxh> | + | </code> |
| + | < | ||
| <WRAP help round> | <WRAP help round> | ||
| Cette architecture atteint rapidement ses limites : | Cette architecture atteint rapidement ses limites : | ||
| Ligne 204: | Ligne 313: | ||
| " | " | ||
| ]) | ]) | ||
| - | date_depart = date(2026, 1, 1) | + | |
| - | for i in range(args.lignes): | + | |
| - | jour = date_depart + timedelta(days=random.randint(0, | + | jour = date_depart + timedelta(days=random.randint(0, |
| - | commande_id = f" | + | commande_id = f" |
| - | client_id = f" | + | client_id = f" |
| - | categorie = random.choice(categories) | + | categorie = random.choice(categories) |
| - | ville = random.choice(villes) | + | ville = random.choice(villes) |
| - | montant = round(random.uniform(5, | + | montant = round(random.uniform(5, |
| - | | + | |
| - | jour, | + | jour, |
| - | commande_id, | + | commande_id, |
| - | client_id, | + | client_id, |
| - | categorie, | + | categorie, |
| - | ville, | + | ville, |
| - | montant | + | montant |
| - | ]) | + | ]) |
| </ | </ | ||
| Ligne 721: | Ligne 830: | ||
| Les fichiers Parquet doivent être relus avec Spark plutôt qu’avec '' | Les fichiers Parquet doivent être relus avec Spark plutôt qu’avec '' | ||
| - | ====== Mission 10 - Synthèse de l’architecture | + | ====== Mission 10 - MapReduce sur nos propres données |
| - | Compléter | + | Le '' |
| + | |||
| + | <WRAP tip round> | ||
| + | Vous allez retrouver exactement le même problème que celui résolu par Spark en Mission 9 ('' | ||
| + | </ | ||
| + | |||
| + | ===== 19. MapReduce ===== | ||
| + | |||
| + | ==== 19.1 Rappel du format des données ==== | ||
| <sxh> | <sxh> | ||
| - | Fichier de ventes | + | date, |
| - | | | + | 2026-01-05, |
| - | v | + | 2026-01-12, |
| - | _________ | + | ... |
| - | | + | |
| - | | | + | |
| - | v | + | |
| - | Découpage en blocs | + | |
| - | | | + | |
| - | v | + | |
| - | | + | |
| - | | + | |
| - | | | + | |
| - | v | + | |
| - | Attribution de ressources | + | |
| - | | | + | |
| - | v | + | |
| - | | + | |
| - | | | + | |
| - | v | + | |
| - | Résultats stockés dans HDFS | + | |
| </ | </ | ||
| - | Associer chaque composant à son rôle : | + | ---- |
| - | < | + | ==== 19.2 Écrire le mapper ==== |
| - | HDFS | + | |
| - | YARN | + | Sur la machine hôte, créer '' |
| - | NameNode | + | |
| - | DataNode | + | < |
| - | ResourceManager | + | # |
| - | Spark | + | import sys |
| - | MapReduce | + | |
| + | for line in sys.stdin: | ||
| + | line = line.strip() | ||
| + | |||
| + | if line.startswith(" | ||
| + | continue | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | # clé = catégorie, valeur = montant | ||
| + | | ||
| </ | </ | ||
| - | ====== Travail à rendre ====== | + | ---- |
| - | Un fichier '' | + | ==== 19.3 Écrire le reducer ==== |
| - | ===== Partie 1 - Architecture ===== | + | Créer '' |
| - | * un schéma de l’architecture Hadoop ; | + | <sxh python> |
| - | * le rôle de chaque composant ; | + | # |
| - | * la différence entre Hadoop, HDFS et YARN. | + | import sys |
| - | ===== Partie 2 - Blocs ===== | + | totaux |
| - | * la taille du fichier ; | + | for line in sys.stdin: |
| - | * le nombre de blocs ; | + | |
| - | * le facteur de réplication ; | + | |
| - | * les DataNodes utilisés ; | + | |
| - | * un schéma de répartition des blocs. | + | |
| - | ===== Partie 3 - Tolérance aux pannes ===== | + | for categorie, total in sorted(totaux.items()): |
| + | print(f" | ||
| + | </ | ||
| - | * état du cluster avant l’arrêt d’un DataNode ; | + | ---- |
| - | * état du cluster après l’arrêt ; | + | |
| - | * résultat de la lecture du fichier ; | + | |
| - | * explication du comportement observé. | + | |
| - | ===== Partie | + | ==== 19.4 Copier les scripts dans le conteneur |
| - | * liste des nœuds ; | + | <sxh bash> |
| - | * observation d’une application ; | + | docker cp mapper.py docker-hadoop-namenode-1:/ |
| - | * rôle du ResourceManager ; | + | docker cp reducer.py docker-hadoop-namenode-1:/ |
| - | * rôle des NodeManagers ; | + | </ |
| - | * explication de la notion de conteneur. | + | |
| - | ===== Partie 5 - Traitement ===== | + | Dans le conteneur '' |
| - | * commande de soumission ; | + | <sxh bash> |
| - | * résultat obtenu ; | + | chmod +x /tmp/mapper.py / |
| - | * emplacement des résultats dans HDFS ; | + | </ |
| - | * schéma du parcours des données. | + | |
| - | ===== Partie 6 - Conclusion ===== | + | ---- |
| - | Répondre en une dizaine de lignes : | + | ==== 19.5 Lancer le traitement avec Hadoop Streaming ==== |
| - | > En quoi HDFS et YARN répondent-ils à des problèmes différents, | + | <sxh bash> |
| + | hadoop jar / | ||
| + | -input / | ||
| + | -output / | ||
| + | -mapper / | ||
| + | -reducer / | ||
| + | -file / | ||
| + | -file / | ||
| + | </ | ||
| + | |||
| + | <WRAP important round> | ||
| + | Le répertoire de sortie ne doit pas déjà exister dans HDFS. Le supprimer si besoin : | ||
| + | |||
| + | <sxh bash> | ||
| + | hdfs dfs -rm -r / | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | <WRAP info round> | ||
| + | Le chemin exact du jar hadoop-streaming peut varier selon l' | ||
| + | <sxh bash> | ||
| + | find / -name " | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== 19.6 Observer le résultat ==== | ||
| + | |||
| + | <sxh bash> | ||
| + | hdfs dfs -cat / | ||
| + | </ | ||
| + | |||
| + | Pendant l' | ||
| + | |||
| + | <sxh bash> | ||
| + | yarn application -list | ||
| + | </ | ||
| + | |||
| + | Répondre : | ||
| + | |||
| + | - Combien de reducers ont été utilisés ? Comment le savez-vous ? | ||
| + | - Ce traitement est-il apparu comme une application | ||
| + | | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== 19.7 À vous de jouer — montant moyen par ville ==== | ||
| + | |||
| + | On souhaite maintenant calculer le **montant moyen des ventes par ville**. | ||
| + | |||
| + | <WRAP important round> | ||
| + | **Piège classique** : on ne peut pas calculer une moyenne globale en faisant la moyenne des moyennes calculées par chaque mapper. Pourquoi ? | ||
| + | </ | ||
| + | |||
| + | Indice : le reducer doit recevoir | ||
| + | |||
| + | ==== Instructions ==== | ||
| + | |||
| + | - Modifier '' | ||
| + | - Modifier '' | ||
| + | - Relancer le traitement avec un nouveau répertoire de sortie : ''/ | ||
| + | - Observer le résultat. | ||
| + | |||
| + | ==== Squelette du reducer à compléter ==== | ||
| + | |||
| + | <sxh python> | ||
| + | # | ||
| + | import sys | ||
| + | |||
| + | sommes = {} | ||
| + | compteurs = {} | ||
| + | |||
| + | for line in sys.stdin: | ||
| + | ville, montant = line.strip().split(" | ||
| + | montant = float(montant) | ||
| + | # TODO : mettre à jour sommes[ville] et compteurs[ville] | ||
| + | |||
| + | for ville in sorted(sommes): | ||
| + | moyenne = None # TODO : calculer la moyenne | ||
| + | print(f" | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== 19.8 Questions de synthèse ==== | ||
| + | |||
| + | - Pourquoi ne peut-on pas faire la moyenne des moyennes obtenues par chaque mapper pour obtenir la moyenne globale ? | ||
| + | - Combien de lignes le mapper a-t-il produites en sortie ? Combien le reducer en a-t-il produites ? | ||
| + | - Si vous deviez calculer le CA par catégorie **et** par ville en même temps, comment modifieriez-vous la clé émise par le mapper ? | ||
| + | - En quoi ce traitement | ||
| + | - Où sont physiquement stockés les fichiers '' | ||
| + | |||
| + | <WRAP tip round> | ||
| + | Comparez vos résultats MapReduce avec ceux de la mission 9 obtenus en Spark. | ||
| + | </ | ||
| ====== Commandes utiles ====== | ====== Commandes utiles ====== | ||
| Ligne 847: | Ligne 1049: | ||
| </ | </ | ||
| - | ====== Schéma final à retenir ====== | ||
| - | |||
| - | <sxh gutter: | ||
| - | YARN | ||
| - | | ||
| - | | ResourceManager | ||
| - | | NodeManagers | ||
| - | | Allocation des ressources| | ||
| - | | ||
| - | | | ||
| - | v | ||
| - | Spark | ||
| - | ou MapReduce | ||
| - | | | ||
| - | v | ||
| - | HDFS | ||
| - | | ||
| - | | NameNode | ||
| - | | DataNodes | ||
| - | | Blocs et réplication | ||
| - | | ||
| - | </ | ||
| - | |||
| - | **HDFS stocke. YARN organise les ressources. Spark ou MapReduce traitent.** | ||