Persistencia y Particionado de Datos en Spark

Clase 23 de 25Curso de Fundamentos de Spark para Big Data

Contenido del curso

Data Frames y SQL

Resumen

Cada vez que ejecutas una acción sobre un RDD o un DataFrame en Spark, el motor vuelve a calcular todo el linaje de transformaciones desde el origen. Esto se traduce en reprocesamiento innecesario que consume tiempo y recursos del clúster. Comprender cómo funciona la persistencia de datos y el particionado te permite eliminar ese costo y mantener la información disponible de forma eficiente.

¿Por qué Spark recomputa los datos y cómo evitarlo?

Por diseño, Spark recalcula cada componente del linaje de un RDD cada vez que se invoca una acción [0:12]. Si un RDD se usa en múltiples operaciones a lo largo del flujo, esa recomputación se repite una y otra vez, generando un gasto significativo de procesamiento.

La solución directa es conservar el RDD o DataFrame en memoria —o en disco— para que Spark no tenga que reconstruirlo desde cero. PySpark ofrece dos métodos principales para lograrlo:

  • cache: almacena los datos en memoria con el nivel de persistencia por defecto.
  • persist: permite elegir un nivel de persistencia específico, combinando memoria, disco, serialización y replicación.

PySpark almacena los datos de forma serializada por defecto, es decir, en una estructura compacta que facilita su disponibilidad y transporte entre nodos [1:08].

¿Qué niveles de persistencia existen en PySpark?

El módulo StorageLevel vive en pyspark.storagelevel y recibe cinco parámetros clave [3:18]:

  • useDisk: indica si los datos se almacenan en disco (True o False).
  • useMemory: indica si se almacenan en memoria.
  • useOffHeap: reserva una porción de los datos fuera del heap de la JVM para reducir tiempos de espera.
  • deserialized: define si los datos se guardan deserializados.
  • replication: número de copias del dato en el clúster.

Spark incluye niveles predefinidos como MEMORY_ONLY, MEMORY_AND_DISK, DISK_ONLY y variantes con replicación de dos. Sin embargo, por cuestiones estadísticas se recomienda que la replicación sea de al menos tres, ya que con tres copias la probabilidad de perder el dato se reduce drásticamente [3:50].

¿Cómo aplicar caché y verificar el estado de persistencia?

En el ejemplo práctico se trabaja con un DataFrame llamado medallista_por_año. Antes de persistirlo, la propiedad is_cached devuelve False, lo que confirma que Spark lo recalcula en cada uso [2:30].

python from pyspark.storagelevel import StorageLevel

Enviar a caché

medallista_por_año.rdd.cache()

Verificar nivel de almacenamiento

medallista_por_año.rdd.getStorageLevel()

Esta salida describe la configuración activa: si usa disco, memoria, serialización y cuántas réplicas tiene [2:55].

¿Qué ocurre si se intenta cambiar el nivel de persistencia?

Spark no permite modificar el nivel de persistencia de un RDD que ya está en caché. Al intentarlo, lanza un error indicando que el nivel ya fue asignado [4:30]. La solución es retirar la persistencia actual con unpersist y luego aplicar el nuevo nivel:

python

Retirar persistencia actual

medallista_por_año.rdd.unpersist()

Aplicar nuevo nivel

medallista_por_año.rdd.persist(StorageLevel.MEMORY_AND_DISK_2)

Con MEMORY_AND_DISK_2, Spark almacena los datos tanto en memoria como en disco y mantiene dos réplicas del RDD completo en el clúster [4:50].

¿Cómo crear niveles de persistencia personalizados?

Cuando los niveles predefinidos no cubren los requisitos del negocio, puedes construir uno propio instanciando StorageLevel directamente [5:20]:

python StorageLevel.MEMORY_AND_DISK_3 = StorageLevel(True, True, False, False, 3)

medallista_por_año.rdd.unpersist() medallista_por_año.rdd.persist(StorageLevel.MEMORY_AND_DISK_3)

En este caso, los parámetros indican:

  • True para disco.
  • True para memoria.
  • False para off-heap.
  • False para deserializado.
  • 3 réplicas.

Esto es especialmente útil en entornos donde la alta disponibilidad es crítica y se necesitan diez o incluso doce réplicas para garantizar que el dato siempre esté accesible [6:10].

Un detalle importante: si el RDD fue particionado previamente, la replicación actúa sobre cada partición, no sobre el conjunto completo como bloque monolítico [5:05]. Esto impacta directamente en el uso de almacenamiento y debe considerarse al definir la estrategia de persistencia.

Experimenta con distintos niveles de persistencia en tu propio clúster y comparte cuál combinación te dio mejores resultados según tu caso de uso.