Infra

Nivel medio

Memoria del driver vs. memoria del executor: no son el mismo problema de ajuste

«Simplemente sube la memoria» funciona distinto según de cuál memoria hablemos - y subir la equivocada solo retrasa el mismo crash.

Leer en:
collect() / toPandas() Broadcast sobredimensionado Particiones rastreadas
Las fuentes habituales de presión de memoria en el driver, aproximadamente en orden - ilustrativo, no medido.

El driver realiza un trabajo fundamentalmente distinto al de un executor: construye y planifica el DAG, no procesa particiones de datos - lo que significa que su presión de memoria viene de lugares completamente distintos.

Lo que realmente se ejecuta en el driver

Construcción del plan y planificación del DAG, coordinación de la asignación de tareas a executors, recolección de valores de acumuladores, y cualquier cosa que traiga datos de vuelta explícitamente al proceso del driver - collect(), toPandas(), take() sobre un resultado grande. Nada de eso es «procesar particiones de tu dataset», que es enteramente trabajo de los executors.

Por qué el OOM del driver tiene causas reales distintas

La más común, por lejos: alguien llamó a .collect() o .toPandas() sobre un DataFrame mucho más grande de lo esperado, trayendo todo al proceso único del driver en lugar de mantenerlo distribuido. La segunda más común: un broadcast join (ver el artículo sobre broadcast join) donde el lado «pequeño» en realidad no lo era - el driver recolecta esos datos antes de enviarlos a los executors, así que es el primero en hacer OOM. La tercera: un job que rastrea una cantidad enorme de particiones o un DAG muy profundo, donde el overhead de planificación por sí solo - sin ningún dato real de por medio - consume el heap del driver.

Por qué subir la memoria del executor no toca nada de esto

spark.executor.memory y spark.driver.memory son configuraciones genuinamente separadas que controlan procesos JVM separados - subir una no hace nada por la presión en la otra. Un OOM del driver por un collect() inesperado necesita un arreglo de código (agregar antes de recolectar, o directamente no recolectar) o spark.driver.memory específicamente; darle más memoria al executor en ese caso apunta a un proceso que nunca fue el que se estaba quedando sin memoria.

Diagnóstico rápido: un OOM de executor aparece como una tarea específica fallando con un ExecutorLostFailure o similar en el event log. Un OOM del driver mata toda la aplicación de golpe, muchas veces sin una sola tarea fallida a la que apuntar - una forma completamente distinta, y la primera pista de que estás mirando el ajuste equivocado.

Mira cómo se ve esto en tu propio pipeline.

Sube un event log real de Spark, un run_results.json de dbt, o una exportación de métricas de Flink, y recibe recomendaciones concretas que requieren tu aprobación - no otra regla general.