Descripción corta
Cuando un contenedor (ejecutor de Spark) se queda sin memoria, YARN lo elimina automáticamente y es posible que recibas el siguiente error:
"Container killed on request" stage failure: Caused by: org.apache.spark.SparkException: Job aborted due to stage failure: Task 2 in stage 3.0 failed 4 times, most recent failure: Lost task 2.3 in stage 3.0 (TID 23, ip-###-###-##-###.compute.internal, executor 4): ExecutorLostFailure (executor 4 exited caused by one of the running tasks) Reason: Container marked as failed: container_1516900607498_6585_01_000008 on host: ip-###-###-##-###.compute.internal. Exit status: 137. Diagnostics: Container killed on request. Exit code is 137»
Resolución
Aumento de la memoria del controlador o el ejecutor
Para aumentar la memoria del contenedor, primero conecta el nodo principal de tu clúster y, a continuación, modifica los parámetros spark.executor.memory o spark.driver.memory en tu archivo de configuración de Spark (spark-defaults.conf).
Clúster en ejecución
Para abrir spark-defaults.conf, ejecuta el siguiente comando:
sudo vim /etc/spark/conf/spark-defaults.conf
Para aumentar la memoria del contenedor, añade o modifica los siguientes parámetros en spark-defaults.conf:
spark.executor.memory 10g
spark.driver.memory 10g
Nota: Sustituye 10g por valores de memoria de acuerdo con los recursos disponibles y los requisitos de carga de trabajo del clúster.
Trabajo único
Cuando ejecutes spark-submit, usa las opciones --executor-memory o --driver-memory para aumentar la memoria.
Ejemplo:
spark-submit
--executor-memory 10g
--driver-memory 10g
...
Nota: Sustituye 10g por valores de memoria adecuados según los recursos disponibles y los requisitos de carga de trabajo del clúster.
Adición de más particiones de Spark
Si no puedes aumentar la memoria del contenedor (por ejemplo, si utilizas maximizeResourceAllocation en el nodo), incrementa la cantidad de particiones de Spark. De este modo, se reduce la cantidad de datos que cada tarea de Spark procesa y la memoria total que usa un único ejecutor.
Para añadir más particiones de Spark, primero conecta el nodo principal de tu clúster y, a continuación, ejecuta los siguientes comandos en el shell de Spark:
val numPartitions = 500
val newDF = df.repartition(numPartitions)
Nota: Sustituye 500 por la cantidad de particiones que se adapte al tamaño de los datos.
Aumento del número de particiones aleatorias
Si el error se produce durante una transformación amplia, por ejemplo, join o groupBy, primero debes conectarte al nodo principal del clúster y, a continuación, añadir más particiones aleatorias. El valor predeterminado es 200.
Clúster en ejecución
Para abrir spark-defaults.conf, ejecuta el siguiente comando:
sudo vim /etc/spark/conf/spark-defaults.conf
Actualiza las particiones aleatorias en tu archivo de configuración:
spark.sql.shuffle.partitions 500
Nota: Sustituye 500 por la cantidad de particiones que se adapte al tamaño de los datos.
Trabajo único
Cuando ejecutes spark-submit, Utiliza la opción --conf spark.sql.shuffle.partitions para agregar más particiones de mezcla.
Ejemplo:
spark-submit
--conf
spark.sql.shuffle.partitions=500
...
Reducción del número de núcleos ejecutores
Al reducir el número de núcleos ejecutores, también se reduce el número máximo de tareas que el ejecutor procesa simultáneamente. De este modo, se reduce la cantidad de memoria que utiliza el contenedor.
Clúster en ejecución
Primero conéctate al nodo principal del clúster y, a continuación, abre el archivo spark-defaults.conf en el nodo principal:
sudo vim /etc/spark/conf/spark-defaults.conf
Para establecer el número de núcleos ejecutores, modifica el parámetro spark.executor.cores:
spark.executor.cores 1
Nota: Sustituye 1 por la cantidad de núcleos ejecutores que necesitas para tu caso de uso.
Trabajo único
Usa la opción --executor-cores para reducir el número de núcleos ejecutores cuando ejecutes spark-submit.
Ejemplo:
spark-submit
--executor-cores 1
...
Aumento del tamaño de la instancia
Cuando el sistema operativo se queda sin memoria, es posible que el sistema operativo oom_reaper también elimine los contenedores YARN. Si esto provoca el error, usa una instancia más grande con más RAM. Para asegurarte de que los contenedores YARN no consuman toda la memoria RAM de Amazon Elastic Compute Cloud (Amazon EC2), reduce yarn.nodemanager.resource.memory-mb.
Revisa los registros de instancias de Amazon EMR para ver el resultado del comando dmesg y determinar si oom_reaper provoca el error. Primero, usa la interfaz de usuario o los registros de YARM Resource Manager para encontrar el nodo principal o de tareas donde se ejecutaba el contenedor YARN eliminado. A continuación, comprueba los registros de estado de la instancia de Amazon EMR en ese nodo antes y después del cierre del contenedor para ver si oom_reaper ha cerrado el proceso.
En el siguiente ejemplo, el kernel (el eliminador de OOM de Linux) elimina el proceso con el id. 36787 que corresponde al YARN container_165487060318_0001_01_000244:
# hows the kernel lookingdmesg | tail -n 25
[ 3910.032284] Out of memory: Kill process 36787 (java) score 96 or sacrifice child
[ 3910.043627] Killed process 36787 (java) total-vm:15864568kB, anon-rss:13876204kB, file-rss:0kB, shmem-rss:0kB
[ 3910.748373] oom_reaper: reaped process 36787 (java), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
Comprueba el uso del disco y la degradación de los nodos
Si las opciones de solución de problemas anteriores no resuelven el error, comprueba el uso del disco y la degradación de los nodos. Usa el indicador df-h en los registros de estado de la instancia para comprobar el uso del disco del clúster y del nodo. Comprueba también el estado del nodo en el panel de control de Amazon Health.
Información relacionada
¿Cómo puedo resolver el error «Container killed by YARN for exceeding memory limits» en Spark en Amazon EMR?
¿Cómo puedo solucionar los errores de fase de los trabajos de Spark en Amazon EMR?