aj
ajteaches
En esta página
BlogSparkBigDataDataEngineeringPythonDatabricks

Apache Spark: Introduction

A�
Alejandro Jaimes 🥭10 min read · 16 de junio de 2026 · 01:17 a. m.
Apache Spark: Introduction

¿Alguna vez intentaste abrir un archivo de 10 millones de filas en Excel y todo se colgó? Eso es exactamente el problema que Spark resuelve. En esta guía te explico cómo funciona el motor de procesamiento distribuido más usado en la industria, sin necesitar un doctorado para entenderlo.

Panorama del procesamiento de datos

El procesamiento de datos no tiene una sola arquitectura. Dependiendo del problema, del volumen y de la velocidad a la que llegan los datos, las organizaciones trabajan con modelos distintos: OLTP para transacciones en tiempo real, OLAP y data warehouses para análisis histórico, pipelines ETL para mover y transformar datos entre sistemas, bases de datos columnares para agregaciones rápidas, streaming para procesar eventos conforme llegan, y procesamiento batch para grandes volúmenes acumulados.

Big Data no es un producto ni una arquitectura específica. Es una categoría de problemas que aparece cuando los datos superan la capacidad de las herramientas convencionales para procesarlos.

El límite no es un número fijo —depende de la infraestructura disponible— pero la señal es concreta: las consultas que antes tardaban segundos empiezan a tardar minutos, luego horas. Los JOINs entre tablas grandes se vuelven operaciones que bloquean sistemas enteros. Los procesos que corrían en una sola máquina dejan de terminar.

Esta es la razón por la que existe Spark.


¿Cúando sé que necesito Spark?

Antes de entrar en la arquitectura, vale la pena describir el tipo de problemas que justifican un motor como este.

Image by author
  • Una empresa de telecomunicaciones tiene una tabla de eventos de red con 800 millones de registros. Necesita cruzarla con una tabla de clientes de 50 millones para calcular el consumo por segmento en los últimos 90 días. Si el servidor tiene 128 GB de RAM y el conjunto de datos combinado supera ese tamaño, una base de datos relacional convencional tiene pocas opciones: o la consulta tarda horas, o falla directamente.
  • Un banco necesita recalcular el scoring de riesgo de 30 millones de clientes a partir de 10 años de histórico transaccional. El proceso requiere múltiples pasadas sobre los mismos datos. Con un enfoque tradicional, cada pasada lee desde disco, procesa y escribe resultados intermedios. Para diez iteraciones del modelo, son diez ciclos completos de lectura y escritura en disco.
  • Una plataforma de e-commerce registra 200,000 eventos por segundo: clics, búsquedas, conversiones. Necesita actualizar recomendaciones en tiempo real y al mismo tiempo recalcular métricas de campaña con datos históricos. Un proceso batch nocturno no resuelve el primero. Una solución de streaming puro no resuelve el segundo fácilmente. Se necesita un motor que maneje ambos modelos sin duplicar la lógica.

Estos no son casos de compañías con cientos de ingenieros. Son escenarios que aparecen en cualquier organización que haya operado datos por más de tres años y haya crecido.


¿Qué es Apache Spark?

Apache Spark es un motor de procesamiento distribuido de datos, de código abierto, creado originalmente en la Universidad de Berkeley en 2009 y donado a la Apache Software Foundation en 2013. Diseñado para ejecutar cómputo sobre grandes volúmenes de datos distribuyéndolo entre múltiples máquinas que trabajan en paralelo.

Image by author

Lo que hace especial a Spark frente a sus predecesores es que trabaja principalmente en memoria RAM (en lugar de escribir constantemente a disco), lo que lo hace hasta 100x más rápido que su antecesor, Hadoop MapReduce.

Hadoop trata el disco como su espacio de trabajo. Cada vez que termina un paso, escribe el resultado en disco. Cuando empieza el siguiente paso, vuelve a leer desde disco. Si tienes 5 transformaciones encadenadas, son 5 lecturas + 5 escrituras. El disco es lento — acceder a él toma aproximadamente 100 veces más tiempo que acceder a RAM.

Image by author

Spark carga los datos en memoria al inicio y hace todas las transformaciones ahí dentro. Solo toca el disco al principio (para leer) y al final (para guardar). Las 5 transformaciones intermedias nunca salen de RAM.

Image by author

En pocas palabras: si tiene que procesar millones (o miles de millones) de registros, y necesita aplicar transformaciones, joins o agregaciones pesadas sobre esos datos, Spark es la herramienta correcta para el trabajo. Dividir la carga en partes más pequeñas, las distribuye entre muchos nodos para procesarlas en paralelo, y al final unifica los resultados. Todo esto ocurre de forma transparente para quien escribe el código — uno escribe transformaciones sobre un DataFrame, y Spark se encarga de decidir cómo repartir ese trabajo entre el clúster


Arquitectura de Spark

Toda aplicación Spark tiene tres piezas. Esta es la imagen que ya armamos antes y vale la pena retomarla aquí, porque cada pieza tiene un rol específico en lo que viene después.

El Driver es el proceso que ejecuta el código principal (main). No procesa datos directamente — su trabajo es:

  • Convertir código en un plan de ejecución
  • Dividir ese plan en unidades de trabajo (jobs, stages, tasks — ver siguiente sección)
  • Enviar esas unidades a los executors
  • Recopilar los resultados finales

Los Executors son procesos que corren en los nodos worker. Cada executor:

  • Ejecuta las tareas que le asigna el driver
  • Guarda particiones de datos en memoria o disco
  • Reporta el progreso y los resultados de vuelta al driver

El Cluster Manager decide qué recursos (CPU, memoria) están disponibles en el clúster y le asigna executors a la aplicación. Puede ser YARN, Kubernetes, Mesos, o el Standalone Cluster Manager de Spark.


RDD: La estructura de datos sobre la que corre todo

El modelo de programación de Spark se basa en los RDD (Resilient Distributed Dataset): colecciones de datos particionadas entre los nodos del clúster, tolerantes a fallos.

Un RDD es una colección de datos particionada —dividida en fragmentos— y distribuida entre los nodos del clúster. Cada partición vive en la memoria (o disco, si no cabe) de un executor distinto. Cuando escribe una operación sobre un DataFrame de 800 millones de filas, por debajo Spark la traduce a operaciones sobre un RDD dividido en, por ejemplo, 200 particiones de 4 millones de filas cada una, repartidas entre los nodos disponibles.

La "R" de Resilient no es decorativa. Cada RDD recuerda cómo se construyó —a partir de qué datos y con qué transformaciones— en una estructura llamada lineage (linaje). Esto es la base de la tolerancia a fallos.


Jobs, Stages y Tasks

Esta es la jerarquía que el Driver construye cada vez que el código le pide un resultado.

Image by author

Application es el programa completo: el script o notebook de principio a fin. Una aplicación puede lanzar muchos jobs a lo largo de su ejecución.

Job se crea cada vez que el código ejecuta una acción —una operación que requiere un resultado concreto, como count(), collect(), write() o show(). Si el notebook tiene cinco .write(), probablemente generó cinco jobs.

Stage es una subdivisión de un job. Un job se parte en stages cada vez que aparece un shuffle — una operación que requiere redistribuir datos entre particiones, típicamente un groupBy, un join o un repartition. Las operaciones dentro de un mismo stage se pueden encadenar y ejecutar sin mover datos entre nodos; cruzar a un nuevo stage implica que los datos sí se mueven por la red.

Task es la unidad mínima de trabajo: una stage aplicada a una sola partición de datos. Si el DataFrame tiene 200 particiones, esa stage genera 200 tasks, y cada una se asigna a un executor disponible para ejecutarse en paralelo.


Lazy Evaluation: por qué Spark "no hace nada" hasta que se le pide

Este es probablemente el comportamiento que más confunde a quien empieza con Spark.

Las operaciones de Spark se dividen en dos categorías:

Transformaciones (select, filter, withColumn, groupBy, join...) son lazy. Cuando se escriben, Spark no procesa ni un solo dato. Lo único que hace es anotar la operación en un plan lógico — una especie de receta de lo que hay que hacer, sin cocinarlo todavía.

Acciones (count, collect, show, write, take...) son las que disparan la ejecución real. En el momento en que Spark encuentra una acción, toma todo el plan acumulado, lo optimiza (Catalyst entra aquí), lo traduce en jobs → stages → tasks, y recién ahí empieza a mover datos.

¿Por qué Spark está diseñado así? Porque le permite optimizar el plan completo antes de ejecutar nada. Si encadena un filter después de un select, Spark puede reordenar esas operaciones para filtrar primero y leer menos datos — algo que sería imposible si cada línea se ejecutara inmediatamente, una por una.

consecuencia práctica: si el notebook tiene 20 celdas con transformaciones y la última tiene un .show(), las 20 celdas anteriores no tardan nada en ejecutarse — ninguna hizo trabajo real. Todo el tiempo de cómputo aparece en la celda con .show(), donde puede parecer (engañosamente) que "esa celda es lenta", cuando en realidad está pagando el costo de las 20 anteriores.


¿Qué pasa cuando un nodo muere a mitad de proceso?

En un clúster de cientos de máquinas, que un nodo falle durante un job largo no es una excepción — es estadísticamente esperable. Spark está diseñado para que eso no tire abajo todo el trabajo ya hecho.

Acá es donde vuelve a importar el lineage del que hablamos al inicio. Cada RDD —y por extensión cada partición de un DataFrame— sabe exactamente de qué datos viene y qué transformaciones se le aplicaron para llegar a su estado actual.

Si un executor muere a mitad de un stage:

  1. El Driver detecta que ese executor dejó de responder
  2. Identifica qué particiones estaban siendo procesadas en ese nodo
  3. Usando el lineage, recalcula solo esas particiones desde la fuente o desde el último punto persistido — no desde cero, no el dataset completo
  4. Reasigna esas tasks a otro executor disponible

No hay checkpoints manuales que gestionar ni snapshots que configurar para que esto funcione — es el comportamiento por defecto. El costo de esta resiliencia es que, si el lineage es muy largo (muchas transformaciones encadenadas sin persistir resultados intermedios), recalcular una partición perdida puede ser costoso. Por eso existe .cache() y .persist(): le dicen a Spark: "Guarde este resultado intermedio en memoria, para no tener que recalcular todo el lineage desde el origen si algo falla o si va a reutilizar este resultado más adelante"


Ecosistema Spark

Spark ofrece un ecosistema bastante generoso para cada carga de trabajo. El framework de Spark incluye las siguientes capacidades:

aws - what is apache spark?

Spark Core — base de la plataforma, gestión de memoria, recuperación de fallos, APIs para Java/Scala/Python/R.

Spark SQL — motor de consultas distribuido, hasta 100x más rápido que MapReduce, optimizador Catalyst, soporta JDBC, ODBC, JSON, HDFS, Hive, ORC, Parquet, Redshift, Cassandra, MongoDB, Elasticsearch y más.

Spark Streaming — procesamiento en tiempo real por minilotes, mismo código para batch y streaming, soporta Kafka, Flume, HDFS, ZeroMQ.

MLlib — machine learning a escala, clasificación, regresión, clustering, filtrado colaborativo, minería de patrones, entrenable con R o Python.

GraphX — procesamiento de grafos distribuido, ETL, análisis exploratorio, computación iterativa, algoritmos de grafos distribuidos.


Hasta aquí hemos visto cada pieza por separado: cómo Spark distribuye los datos en particiones, cómo el Driver coordina con el Cluster Manager, cómo los executors ejecutan las tasks, cómo las transformaciones se acumulan sin ejecutarse hasta que una acción las dispara. Ahora veamos cómo todo eso ocurre junto, de principio a fin, en una sola aplicación real.

Flujo completo, de principio a fin

Uniendo todo lo anterior, así es el recorrido completo de una aplicación Spark:

  1. Se escriben las transformaciones sobre un DataFrame. Spark las acumula como un plan lógico, sin ejecutar nada (lazy evaluation).
  2. Invocar a una acción (write, count, show). Esto dispara la ejecución.
  3. Catalyst optimiza el plan lógico y genera un plan físico — el conjunto de pasos reales a ejecutar, en el orden más eficiente posible.
  4. El Driver traduce ese plan físico en jobs, y cada job en stages, separando por shuffles.
  5. Cada stage se divide en tasks — una por partición — y el Cluster Manager las distribuye entre los executors disponibles.
  6. Los executors procesan sus particiones en paralelo, manteniendo los datos en memoria cuando es posible (gracias al RDD/lineage que respalda cada partición).
  7. Si un executor falla en el camino, el Driver usa el lineage para recalcular solo lo perdido y reasignar esas tasks.
  8. Los resultados finales —ya agregados o escritos— vuelven al Driver o se persisten directamente en el almacenamiento de destino.

Tutoriales Recomendados

  1. Databricks — Getting Started with Apache Spark: Tutorial auto-guiado en 6 módulos que cubre desde el quick start hasta DataFrames, Spark SQL, Machine Learning y Streaming. Cada módulo incluye notebooks descargables con datasets reales para ejecutar directamente. Es el recurso oficial de los creadores de Spark.
  2. Apache Spark Architecture: A Guide for Data Practitioners: Tutorial auto-guiado de arquitectura, con ilustraciones y conceptualización suficiente para entender el funcionamiento de spark de principio a fin. Útil para entender comportamientos e identificar mejoras conforme se avanza en el desarrollo de aplicaciones masivas.
  3. Bryan Cafferky — Databricks & Spark Step by Step:Serie gratuita en YouTube que construye desde cero hasta productivo. No solo enseña Spark en aislamiento sino cómo se usa dentro de Databricks: notebooks, workflows, y patrones reales de data engineering.

Referencias


Si leyó hasta aquí, gracias — de verdad.

Escribir esto tomó tiempo y saber que alguien lo lee hasta el final lo hace valer la pena. Si algo no quedó claro, tiene dudas, o simplemente quiere debatir algún punto, queda la cajita de los comentarios. Leo todo (casi siempre jajaja).

Si quiere estar al tanto, de cuando salen artículos como este — suscríbase. Sin spam, solo contenido valioso cuando haya algo que valga la pena compartir.

Nos vemos en la próxima, espero que haya sido de mucha utilidad.

— Alejo🥭

Comments (0)

Sign in to comment