Taller Spark: el motor sobre el clúster que ya tienes
Taller Spark: el motor sobre el clúster que ya tienes
Este taller es la práctica de la teoría de Spark. Partes del clúster ya montado (HDFS, YARN y spark-client). No se vuelve a construir Docker ni a explicar el NameNode. No es PySpark: no abres Jupyter ni escribes DataFrames. El objetivo es ver el motor: tipo SPARK en el portal, driver y executors, un DAG frente a un job MapReduce.
Nivel: intermedio. Este taller no trae comandos resueltos. Cada ejercicio te da un objetivo, qué debes lograr y un análisis. Tú construyes las órdenes. La señal de que resolviste un ejercicio no es que “no dé error”, sino que puedes explicar por qué YARN y Spark respondieron como respondieron.
Tu herramienta de referencia:
spark-submit --help,yarn application -help,yarn node -help. Saber leerla es parte de lo que se evalúa.
Datos que ya dejó el laboratorio del cliente (no los reinventes):
| Dato | Valor |
|---|---|
| Atajo Compose (los dos YAML) | dc() { docker compose -f compose.yaml -f compose.spark.yaml "$@"; } |
| JAR de ejemplos | /opt/spark/examples/jars/spark-examples_2.12-3.5.3.jar |
| SparkPi | clase org.apache.spark.examples.SparkPi |
| Wordcount Java | clase org.apache.spark.examples.JavaWordCount |
| Texto del curso | hdfs://namenode:9000/yarn/entrada/texto.txt |
| Portal YARN | http://localhost:8088 |
| UI del driver | http://localhost:4040 mientras el driver vive |
Requisitos previos
- Laboratorio del cliente Spark terminado (
spark-client,dc, SparkPi de comprobación). - MapReduce (teoría y laboratorio): sabes leer tipo
MAPREDUCEy unpart-r-*. - Teoría de Spark: DAG, evaluación perezosa, driver, executors, aplicación / job / etapa / tarea.
Convención de terminales:
- 🖥️ HOST — Bash en
~/hdfs-docker-lab. Aquí definesdc(se pierde al cerrar la ventana). - 🔥 CLIENTE — órdenes Spark y Hadoop dentro de
spark-client(dc exec spark-client ...). - 🌐 NAVEGADOR — ResourceManager
:8088. La UI Spark:4040solo existe con el driver arriba.
docker composea secas no vespark-client. Sidc psno lista ese servicio, el atajo no está leyendo el segundo YAML.
Mapa del taller
| # | Ejercicio | Frente | Concepto | Dificultad |
|---|---|---|---|---|
| 0 | Clúster y cliente arriba | Infra | dc, no rehacer HDFS |
Básico |
| 1 | SparkPi y tipo SPARK |
Motor | Mismo YARN, otro tipo | Básico |
| 2 | Historia: MAPREDUCE frente a SPARK |
Motor | Dos motores, un portal | Básico |
| 3 | Wordcount Spark sobre el mismo texto | Motor | Shuffle en Spark | Intermedio |
| 4 | Comparar con el wordcount MapReduce | Motor | Mismo conteo, otro job | Intermedio |
| 5 | Aplicación, job, etapa, tarea | Modelo | Jerarquía de la teoría | Intermedio |
| 6 | Dónde está el driver | Arquitectura | Modo client | Intermedio |
| 7 | Dónde están los executors | Arquitectura | Contenedor YARN ≠ Docker | Medio-alto |
| 8 | Un Pi más largo y :4040 |
Observación | UI del driver | Medio-alto |
| 9 | Job en ACCEPTED |
Recursos | 2 GB por NodeManager | Medio-alto |
| 10 | Matar una aplicación Spark | Operación | KILLED vs SUCCEEDED |
Medio-alto |
| 11 | SparkPi no lee HDFS | Modelo | MapReduce π vs SparkPi | Intermedio |
| 12 | Reto integrador | Mixto | Explicar un DAG con evidencias | Alto |
Ejercicio 0 — Clúster y cliente arriba
Objetivo: trabajar sobre el clúster ya montado, sin crear otro proyecto Compose.
Qué debes lograr:
- Estar en
~/hdfs-docker-labcon el atajodcactivo. - Ocho servicios, incluido
spark-client, en marcha (o arrancarlos sin recrear volúmenes). - Modo seguro OFF, tres DataNodes vivos, dos NodeManagers
RUNNING. /yarn/entrada/texto.txttodavía tiene las cuatro líneas del curso.
Análisis: ¿por qué docker compose ps puede ocultar spark-client aunque el contenedor exista? Si el texto falta, ¿lo subes otra vez desde el cliente o desde el NameNode, y qué cambia?
Parte 1 — El mismo YARN, otro motor
Ejercicio 1 — SparkPi y tipo SPARK
Objetivo: enviar SparkPi y reconocer el motor en el portal.
Qué debes lograr:
- Lanzar SparkPi con
spark-submiten modo client, masteryarn, desdespark-client. - Ver en la terminal una estimación cercana a 3,14.
- En
:8088, una aplicación de nombre tipo Spark Pi, tipoSPARK, estadoFINISHED / SUCCEEDED.
Análisis: en el laboratorio del cliente ya corriste SparkPi para comprobar que el contenedor hablaba con YARN. ¿Qué pregunta responde ahora, en este taller? ¿Por qué el tipo no es MAPREDUCE si YARN es el mismo?
Ejercicio 2 — Historia: MAPREDUCE frente a SPARK
Objetivo: el portal mezcla motores. Tú los separas.
Qué debes lograr:
- Listar aplicaciones en todos los estados (
ALL). - Identificar al menos una
MAPREDUCE(π o wordcount de MapReduce) y unaSPARK(SparkPi). - Anotar Application ID, tipo y estado final de cada una.
Análisis: ¿qué pieza decide el tipo que ves: el ResourceManager, el ApplicationMaster o el JAR que enviaste? Si alguien dice “el job corrió en Hadoop”, ¿cómo contestas con esta tabla?
Ejercicio 3 — Wordcount Spark sobre el mismo texto
Objetivo: un cálculo con shuffle (reagrupar por clave a través de la red), no solo π.
Qué debes lograr:
- Enviar
JavaWordCountsobrehdfs://namenode:9000/yarn/entrada/texto.txt. - Recuperar el conteo (esta clase imprime en la salida estándar del driver; no tiene por qué dejar
part-*en HDFS). - Confirmar en
:8088otra aplicación tipoSPARK.
Análisis: ¿por qué este ejemplo sí necesita el archivo de HDFS y SparkPi no? Relaciónalo con las tres fases de MapReduce: ¿dónde está aquí el equivalente de map, shuffle y reduce?
Ejercicio 4 — Comparar con el wordcount MapReduce
Objetivo: el mismo diccionario, dos motores.
Qué debes lograr:
- Releer un
part-r-*de MapReduce que ya tengas (/yarn/salida_wc,/yarn/teoria_mr_wco la salida de Streaming). - Poner lado a lado las seis claves: datos, hadoop, hdfs, mapreduce, spark, yarn.
- Si una salida MapReduce no existe, no montes un clúster nuevo: relanza el JAR de ejemplos Hadoop desde el cliente que ya usas, a un directorio de salida nuevo.
Análisis: si los números coinciden, ¿qué quedó demostrado y qué no? (pista: coincidir no prueba que Spark “sea MapReduce por dentro”.)
Parte 2 — La jerarquía y quién calcula
Ejercicio 5 — Aplicación, job, etapa, tarea
Objetivo: usar los cuatro términos de la teoría con una corrida real.
Qué debes lograr:
- Para una aplicación Spark que hayas lanzado, decir: cuál es la aplicación YARN (
application_…), cuándo nació el job (qué acción lo disparó), si hubo más de una etapa, y qué es una tarea. - Apoyarte en
:8088(detalle de la app) y, si alcanzas a abrirla, en:4040(Jobs / Stages).
Análisis: SparkPi y el wordcount, ¿cuántos jobs YARN ves (uno o dos) y cuántas aplicaciones? ¿Por qué esa diferencia importa cuando alguien dice “lanzé dos jobs”?
Ejercicio 6 — Dónde está el driver
Objetivo: modo client no es un adorno del YAML.
Qué debes lograr:
- Explicar, con evidencia, que el driver (quien arma el plan y recoge el resultado) no corre como contenedor YARN de los NodeManagers.
- Relacionarlo con
spark.submit.deployMode/--deploy-mode clienty con el hostnamespark-client.
Análisis: si el driver estuviera en un contenedor YARN (cluster mode), ¿podrías usar Jupyter con el kernel en spark-client como en el laboratorio del cliente? ¿Por qué sí o por qué no?
Ejercicio 7 — Dónde están los executors
Objetivo: contenedor YARN ≠ contenedor Docker.
Qué debes lograr:
- Localizar en qué NodeManagers corrieron contenedores de tu aplicación Spark (intento, AM, executors).
- Comprobar que no apareció un
docker compose/dc psnuevo: siguen los mismos ocho servicios.
Análisis: un executor pide heap + overhead (en el laboratorio: 512 MiB + 384 MiB). ¿Cuántos executors caben a la vez en un NodeManager de 2 GB si también hay que alojar el ApplicationMaster? Muestra la cuenta.
Parte 3 — Observar y operar
Ejercicio 8 — Un Pi más largo y :4040
Objetivo: la UI Spark no es el portal de YARN.
Qué debes lograr:
- Lanzar SparkPi con más slices (el entero al final del JAR) para que dure lo suficiente.
- Mientras corre, abrir http://localhost:4040 y anotar al menos: nombre de la app, número de executors, una etapa o un job.
- En
:8088, el estado durante la corrida (RUNNING) y al terminar (FINISHED).
Análisis: al acabar el spark-submit, :4040 deja de responder. :8088 sigue. ¿Qué proceso servía la 4040 y por qué muere con el driver en modo client?
Ejercicio 9 — Job en ACCEPTED
Objetivo: YARN aceptó la app y aún no le dio contenedores.
Qué debes lograr:
- Dejar una aplicación Spark viva (un Pi largo, o no cerrar otra app) y lanzar otra Spark a la vez.
- Capturar el síntoma
ACCEPTED(portal oyarn application -list). - Liberar recursos y ver que la segunda pasa a
RUNNINGo que decides no lanzarla.
Análisis: ¿el cuello es HDFS, el cliente o la memoria de los NodeManagers? ¿Qué harías antes de subir spark.executor.memory?
Ejercicio 10 — Matar una aplicación Spark
Objetivo: distinguir KILLED, FAILED y FINISHED / SUCCEEDED.
Qué debes lograr:
- Lanzar un SparkPi largo.
- Desde otra terminal, matar esa aplicación YARN por su
application_…. - Dejar evidencia del estado final y de que los contenedores volvieron al pool (
yarn node -list/ métricas de:8088).
Análisis: ¿matar la aplicación YARN mata el spark-submit del driver? ¿Qué verías en la terminal del cliente?
Ejercicio 11 — SparkPi no lee HDFS
Objetivo: no todo trabajo Spark es “leer un txt y contar”.
Qué debes lograr:
- Contrastar SparkPi (sin
-inputde texto) con el wordcount Spark y con el π de MapReduce (QuasiMonteCarlo). - Una frase por cada uno: ¿lee HDFS? ¿hay shuffle de palabras? ¿para qué sirve en este curso?
Análisis: “Spark siempre trabaja en memoria sobre archivos de HDFS”. Con estas tres corridas, ¿dónde se rompe esa frase?
Ejercicio 12 — Reto integrador
Diseña una corrida (SparkPi o wordcount) y entrega un párrafo con evidencias, no un diario de comandos, que cubra:
- Qué aplicación YARN fue (ID, tipo
SPARK, estado). - Quién fue el driver y quiénes los executors (máquinas / servicios).
- Si hubo shuffle o no, y cómo lo sabes.
- Qué habría sido otro job MapReduce si hubieras encadenado dos pasos, y por qué Spark lo cuenta como un DAG de etapas.
- Qué no demostraste (por ejemplo: DataFrames, SQL, que “todo cabe en RAM”).
Diagnóstico
| Síntoma | Hacia dónde mirar |
|---|---|
dc no lista spark-client |
Atajo sin el segundo YAML; ventana de terminal nueva |
Connection refused a 9000 u 8088 |
Clúster HDFS/YARN no listo; no es un fallo de Spark |
ACCEPTED eterno |
Otra Spark viva; 2 GB por NM; spark.stop / matar apps |
:4040 no abre |
El spark-submit ya terminó (el driver se fue) |
| Wordcount “Path does not exist” | Falta /yarn/entrada/texto.txt (laboratorio del cliente o de YARN) |
Tipo MAPREDUCE cuando esperabas Spark |
Enviaste el JAR de Hadoop, no spark-submit |
Listo cuando: tienes al menos una app SPARK de SparkPi y una de wordcount, sabes separarlas de las MAPREDUCE del portal, y puedes decir dónde corrió el driver y dónde los executors.
Siguiente: PySpark (PySpark: la API de Spark en Python y Taller de PySpark). El motor ya lo viste; allá escribes la API en Python.