DASHBOARD
Spark Logo

SPARKCore

DISTRIBUTED SYSTEM ARCHITECTURE

EL NUEVO PARADIGMA

De Monolito a Enjambre

En el módulo anterior (SQL Server), el universo de datos estaba limitado por el hardware de una sola caja metálica. Escalamiento Vertical: Comprar un servidor más grande.

En Spark, el límite es tu presupuesto para conectar máquinas commodity. Escalamiento Horizontal: Agregar más servidores baratos al cluster.

SQL: 1 CPU Ultra, 1TB RAM
Spark: 100 CPUs Normales, 10GB RAM c/u
OVERLOAD

ANATOMÍA DEL CONTENEDOR

Para entender la ingeniería de datos, no podemos usar "cajas negras". Hemos diseñado un contenedor Docker personalizado que expone las capas reales de un nodo de Spark.

La Paradoja PySpark: Aunque escribes código en Python, Spark es nativo de Scala y corre sobre la JVM. Tu código Python es solo un "títere" que controla el motor Java a través de una librería llamada Py4J.

Dockerfile (Extracto)
# 1. Base del Sistema Operativo
FROM python:3.11-slim

# 2. El Corazón (JVM)
# Sin Java, Spark no arranca
RUN apt-get install -y openjdk-17-jre

# 3. El Motor Distribuido
RUN pip install pyspark==3.5.0

# 4. Capa de Almacenamiento
RUN pip install delta-spark==3.0.0
Tu Docker Image
Debian Linux (OS)
Java Virtual Machine
Spark Core (Scala)
PySpark Wrapper
Tu Notebook .ipynb
Py4J Bridge

ARQUITECTURA FÍSICA

DOCKER-COMPOSE NETWORK: ml-net
The Architect
Jupyter

Driver

jupyter-lab:8888

Aquí vive tu código. Convierte lógica Python en un DAG (Grafo Dirigido Acíclico) y se lo envía al Master.
⚠️ NO procesa datos masivos.

The Manager
Spark

Master

spark-master:7077

Negocia recursos. Recibe el DAG del Driver y busca qué Workers tienen CPU/RAM libre para ejecutar las tareas.

The Worker

Worker 1

spark-worker:7078

Aquí viven los Executors. Procesan particiones de datos en la JVM y almacenan bloques en caché.

Core 1
Core 2

EL CEREBRO: CATALYST

Spark no ejecuta tu código línea por línea. Lo compila. El Optimizador Catalyst toma tu consulta ineficiente y la reescribe matemáticamente antes de tocar un solo byte de datos.

Optimizaciones Clave

  • Predicate Pushdown

    Si pides df.filter(year=2023), Spark empuja ese filtro hasta el disco (Parquet) y solo lee los archivos relevantes. Ahorra I/O masivo.

  • Column Pruning

    Si tu tabla tiene 100 columnas pero solo seleccionas 2, Spark ignora las otras 98 desde la lectura física.

graph TD Code[Python API] -->|Unresolved Plan| Analysis Analysis -->|Logical Plan| Opt[Catalyst Optimizer] Opt -->|Optimized Logical Plan| Phy[Physical Planner] Phy -->|Cost Model| Selected[Best Physical Plan] Selected -->|Code Generation| JVM[Java Bytecode] style Code fill:#fff,stroke:#333,color:#000 style Opt fill:#10b981,stroke:#fff,color:#000,stroke-width:2px style Selected fill:#e25516,stroke:#fff,color:#fff

EL MOTOR: TUNGSTEN

¿Por qué Spark es más rápido que Hadoop MapReduce?
Respuesta: Project Tungsten.

La JVM tradicional es mala gestionando objetos grandes (Garbage Collection Pauses). Tungsten soluciona esto gestionando la memoria explícitamente (Off-Heap) en formato binario, similar a C++.

Beneficios:

  • Sin overhead de objetos Java.
  • Procesamiento Cache-aware (L1/L2/L3).
  • Generación de código "Whole-Stage" (compila la query entera en una sola función).

Unified Memory Manager (Executor Heap)

Reserved Memory (300MB)
Unified Region (60% Heap)
Storage Memory Cached Dataframes
Execution Memory Shuffles, Joins, Sorts
Dynamic Boundary: Execution can evict Storage
User Memory (40% - Tus UDFs y Metadatos)

JERARQUÍA DE EJECUCIÓN

Cuando ejecutas una acción (ej: df.count()), Spark crea un Job. Este Job se descompone jerárquicamente. Entender esto es vital para depurar en la Spark UI.

APPLICATION

SparkContext

Es tu sesión completa (el notebook vivo).

JOB

Disparado por Acción

Una acción (`count`, `collect`, `save`) inicia un Job.

STAGE

Frontera de Shuffle

Un Job se rompe en Stages cuando los datos necesitan moverse por la red (Shuffle). Dentro de un Stage, todo es paralelo.

TASK

Unidad Atómica

1 Tarea = 1 Partición de datos. Se ejecuta en un Core del Executor.

EL PELIGRO: SHUFFLE

En un sistema distribuido, el recurso más lento no es el disco, es la RED. El "Shuffle" es el proceso de redistribuir datos entre particiones (y por ende, entre máquinas).

Narrow Transformation

Rápido

El dato se procesa donde está. No hay tráfico de red. Cada partición de salida depende de una sola de entrada.

df.filter(col("id") > 5) df.select("nombre")

Wide Transformation

Lento (Network I/O)

Los datos deben viajar entre Workers para agruparse. Implica: Serialización (Disco) -> Envío (Red) -> Deserialización.

df.groupBy("depto").count() df1.join(df2, "id")

TOLERANCIA A FALLOS: LINAJE

¿Qué pasa si un Worker muere?

En sistemas tradicionales, perder un nodo significa perder datos o reiniciar todo.
Spark usa RDD Lineage (Linaje). No guarda copias de los datos (eso consume mucha RAM), guarda la receta para reconstruirlos.

Si una partición se pierde, el Master le dice a otro Worker: "Ejecuta los pasos A, B y C sobre el archivo original para recuperar este pedazo".

graph BT RDD3[RDD Final: Perdido] -->|Recalcular| RDD2[RDD Filtrado] RDD2 -->|Recalcular| RDD1[RDD Base] RDD1 -->|Leer| File[Archivo Disco] style RDD3 fill:#ef4444,stroke:#fff,color:#fff style RDD2 fill:#3b82f6,stroke:#fff,color:#fff style RDD1 fill:#3b82f6,stroke:#fff,color:#fff style File fill:#10b981,stroke:#fff,color:#fff

MISIÓN: CONSTRUIR EL CLUSTER

Has dominado la teoría del reactor. Ahora es momento de ensamblarlo.
En el siguiente laboratorio, crearás tu propio Dockerfile, levantarás la red distribuida y procesarás terabytes virtuales de datos de SECOP II.

INICIAR DESPLIEGUE