hadoop memory memory-management apache-spark out-of-memory

hadoop - Apache Spark Efectos de la memoria del controlador, memoria del ejecutor, sobrecarga de la memoria del controlador y sobrecarga de la memoria del ejecutor en caso de éxito de las ejecuciones del trabajo



memory memory-management (1)

Estoy haciendo un ajuste de memoria en mi trabajo Spark en YARN y veo que diferentes configuraciones darían resultados diferentes y afectarían el resultado de la ejecución del trabajo Spark. Sin embargo, estoy confundido y no entiendo completamente por qué sucede y agradecería que alguien me brinde alguna orientación y explicación.

Proporcionaré información general y publicaré mis preguntas y describiré los casos que he experimentado después de ellos a continuación.

La configuración de mi entorno era la siguiente:

  • Memoria 20G, 20 VCores por nodo (3 nodos en total)
  • Hadoop 2.6.0
  • Spark 1.4.0

Mi código filtra de manera recursiva un RDD para hacerlo más pequeño (eliminando ejemplos como parte de un algoritmo), luego hace mapToPair y lo recolecta para reunir los resultados y guardarlos dentro de una lista.

Preguntas

  1. ¿Por qué se lanza un error diferente y la tarea se ejecuta más tiempo (para el segundo caso) entre el primer y segundo caso con solo la memoria del ejecutor que se incrementa? ¿Están los dos errores vinculados de alguna manera?

  2. Tanto el tercer como el cuarto caso tienen éxito y entiendo que es porque estoy dando más memoria que resuelve los problemas de memoria. Sin embargo, en el tercer caso,

spark.driver.memory + spark.yarn.driver.memoryOverhead = la memoria que YARN creará una JVM

= 11g + (memoriaMemoria * 0.07, con un mínimo de 384m) = 11g + 1.154g = 12.154g

Por lo tanto, a partir de la fórmula, puedo ver que mi trabajo requiere MEMORY_TOTAL de alrededor de 12.154g para ejecutarse con éxito, lo que explica por qué necesito más de 10 g para la configuración de la memoria del controlador.

Pero para el cuarto caso,

spark.driver.memory + spark.yarn.driver.memoryOverhead = la memoria que YARN creará una JVM

= 2 + (driverMemory * 0.07, con un mínimo de 384m) = 2g + 0.524g = 2.524g

Parece que con solo aumentar la sobrecarga de la memoria en una pequeña cantidad de 1024 (1g), se puede ejecutar el trabajo con éxito con una memoria del controlador de solo 2g y MEMORY_TOTAL de solo 2.524 g . Mientras que sin la configuración de gastos generales, la memoria del controlador menos de 11g falla, pero no tiene sentido por la fórmula, por lo que estoy confundido.

¿Por qué aumentar la sobrecarga de memoria (tanto para el controlador como para el ejecutor) permite que mi trabajo se complete con éxito con un MEMORY_TOTAL menor (12.154g frente a 2.524g) ? ¿Hay alguna otra cosa interna en el trabajo que me falta?

Primer caso

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 7g --executor-memory 1g --num-executors 3 --executor-cores 1 --jars <jar file>

Si ejecuto mi programa con cualquier memoria de controlador de menos de 11g, obtendré el siguiente error que es el SparkContext que se detiene o un error similar que es un método que se llama en un SparkContext detenido. Por lo que he reunido, esto está relacionado con que la memoria no es suficiente.

Segundo caso

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 7g --executor-memory 3g --num-executors 3 --executor-cores 1 --jars <jar file>

Si ejecuto el programa con la misma memoria de controlador pero memoria de ejecutor más alta, el trabajo se ejecuta más tiempo (aproximadamente 3-4 minutos) que el primer caso y luego encontrará un error diferente de anterior que es un contenedor que solicita / usa más memoria que permitido y está siendo asesinado por eso. Aunque me parece extraño ya que la memoria del ejecutor se incrementa y este error ocurre en lugar del error en el primer caso.

Tercer caso

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 11g --executor-memory 1g --num-executors 3 --executor-cores 1 --jars <jar file>

Cualquier ajuste con una memoria del controlador superior a 10 g hará que el trabajo se pueda ejecutar correctamente.

Cuarto caso

/bin/spark-submit --class <class name> --master yarn-cluster --driver-memory 2g --executor-memory 1g --conf spark.yarn.executor.memoryOverhead=1024 --conf spark.yarn.driver.memoryOverhead=1024 --num-executors 3 --executor-cores 1 --jars <jar file>

El trabajo se ejecutará correctamente con esta configuración (memoria del controlador 2g y memoria del ejecutor 1g pero aumentando la carga de memoria del controlador (1g) y la sobrecarga de memoria del ejecutor (1g).

Cualquier ayuda será apreciada y realmente me ayudará con mi comprensión de Spark. Gracias por adelantado.


Todos tus casos usan

--executor-cores 1

Es la mejor práctica ir por encima de 1. Y no superar los 5. De nuestra experiencia y de la recomendación de los desarrolladores de Spark.

Ej. http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/ :

A rough guess is that at most five tasks per executor can achieve full write throughput, so it’s good to keep the number of cores per executor below that number

No puedo encontrar ahora la referencia donde se recomienda ir por encima de 1 núcleo por ejecutor. Pero la idea es que ejecutar múltiples tareas en el mismo ejecutor le da la capacidad de compartir algunas regiones comunes de memoria para que realmente ahorre memoria.

Comience con --executor-cores 2, double --executor-memory (porque --executor-cores también indica cuántas tareas ejecutará concordantemente un ejecutor), y vea lo que hace por usted. Su entorno es compacto en términos de memoria disponible, por lo que ir a 3 o 4 le dará una mejor utilización de la memoria.

Usamos Spark 1.5 y dejamos de usar --executor-cores 1 hace bastante tiempo ya que le daba problemas a GC; también se parece a un error de Spark, porque simplemente dar más memoria no ayudaba tanto como cambiar a tener más tareas por contenedor. Supongo que las tareas en el mismo ejecutor pueden aumentar su consumo de memoria en diferentes momentos, por lo que no desperdicia / no tiene que sobreprovisionar memoria solo para que funcione.

Otra ventaja es que las variables compartidas de Spark (acumuladores y variables de difusión) tendrán solo una copia por ejecutor, no por tarea, por lo que cambiar a varias tareas por ejecutor es un ahorro directo de memoria allí mismo. Incluso si no utiliza las variables compartidas de Spark explícitamente, es muy probable que Spark las cree internamente de todos modos. Por ejemplo, si unes dos tablas a través de Spark SQL, la CBO de Spark puede decidir transmitir una tabla más pequeña (o un marco de datos más pequeño) para hacer que la unión funcione más rápido.

http://spark.apache.org/docs/latest/programming-guide.html#shared-variables