Configurando Spark en YARN

Habr, ola! Onte en reunión dedicada a Apache Spark, dos rapaces de Rambler&Co, houbo bastantes preguntas dos participantes relacionadas coa configuración desta ferramenta. Decidimos seguir os seus pasos e compartir a nosa experiencia. O tema non é sinxelo, polo que invitámoste a que compartas a túa experiencia nos comentarios, quizais tamén entendamos e usemos algo mal.

Unha pequena introdución sobre como usamos Spark. Temos un programa de tres meses “Especialista en Big Data”, e ao longo do segundo módulo os nosos participantes traballan neste instrumento. En consecuencia, a nosa tarefa, como organizadores, é preparar o clúster para o seu uso neste caso.

A peculiaridade do noso uso é que o número de persoas que traballan simultaneamente en Spark pode ser igual ao de todo o grupo. Por exemplo, nun seminario, cando todos intentan algo ao mesmo tempo e repiten despois do noso profesor. E isto non é moito - ás veces ata 40 persoas. Probablemente non haxa moitas empresas no mundo que se enfronten a tal caso de uso.

A continuación, contarei como e por que seleccionamos certos parámetros de configuración.

Comecemos dende o principio. Spark ten 3 opcións para executarse nun clúster: autónomo, usando Mesos e usando YARN. Decidimos escoller a terceira opción porque tiña sentido para nós. Xa temos un clúster Hadoop. Os nosos participantes xa coñecen ben a súa arquitectura. Imos usar YARN.

spark.master=yarn

Ademais máis interesante. Cada unha destas 3 opcións de despregamento ten 2 opcións de despregamento: cliente e clúster. Baseado documentación e varias ligazóns en Internet, podemos concluír que o cliente é axeitado para o traballo interactivo - por exemplo, a través do portátil Jupyter, e cluster é máis axeitado para solucións de produción. No noso caso, interesounos o traballo interactivo, polo tanto:

spark.deploy-mode=client

En xeral, a partir de agora Spark funcionará dalgún xeito en YARN, pero isto non foi suficiente para nós. Dado que temos un programa sobre o big data, ás veces os participantes non tiñan o suficiente do que se obtivo no marco dun corte uniforme dos recursos. E entón atopamos unha cousa interesante: a asignación dinámica de recursos. En resumo, a cuestión é esta: se tes unha tarefa difícil e o clúster está libre (por exemplo, pola mañá), usar esta opción Spark pode darche recursos adicionais. A necesidade calcúlase alí segundo unha fórmula astuta. Non entraremos en detalles: funciona ben.

spark.dynamicAllocation.enabled=true

Establecemos este parámetro e ao iniciar Spark fallou e non se iniciou. É certo, porque tiña que lelo documentación con máis coidado. Afirma que para que todo estea ben, tamén debes activar un parámetro adicional.

spark.shuffle.service.enabled=true

Por que é necesario? Cando o noso traballo xa non requira tantos recursos, Spark debería devolvelos ao grupo común. A fase que máis tempo consume en case calquera tarefa de MapReduce é a fase Shuffle. Este parámetro permítelle gardar os datos que se xeran nesta fase e liberar os executores en consecuencia. E o executor é o proceso que calcula todo sobre o traballador. Ten un certo número de núcleos de procesador e unha certa cantidade de memoria.

Engadiuse este parámetro. Todo parecía funcionar. Fíxose notar que os participantes recibían máis recursos cando os necesitaban. Pero xurdiu outro problema: nalgún momento, outros participantes espertaron e tamén querían usar Spark, pero alí estaba todo ocupado e estaban descontentos. Pódense entender. Comezamos a mirar a documentación. Resultou que hai unha serie de outros parámetros que se poden usar para influír no proceso. Por exemplo, se o executor está en modo de espera, despois de que tempo se lle poden quitar recursos?

spark.dynamicAllocation.executorIdleTimeout=120s

No noso caso, se os seus executores non fan nada durante dous minutos, devólveos á piscina común. Pero este parámetro non sempre foi suficiente. Estaba claro que a persoa levaba tempo sen facer nada, e non se liberaban recursos. Descubriuse que tamén hai un parámetro especial: despois de que hora seleccionar os executores que conteñan datos en caché. Por defecto, este parámetro era infinito! Corrixímolo.

spark.dynamicAllocation.cachedExecutorIdleTimeout=600s

É dicir, se os teus executores non fan nada durante 5 minutos, dáselles á piscina común. Neste modo, a velocidade de liberación e emisión de recursos para un gran número de usuarios fíxose decente. A cantidade de descontento diminuíu. Pero decidimos ir máis aló e limitar o número máximo de executores por aplicación, esencialmente por participante do programa.

spark.dynamicAllocation.maxExecutors=19

Agora, por suposto, hai persoas insatisfeitas do outro lado: "o clúster está inactivo e só teño 19 executores", pero que podes facer? Necesitamos algún tipo de equilibrio correcto. Non podes facer felices a todos.

E unha pequena historia máis relacionada coas especificidades do noso caso. Dalgunha maneira, varias persoas chegaron tarde a unha lección práctica e, por algún motivo, Spark non comezou por eles. Miramos a cantidade de recursos gratuítos: parece que hai. Spark debería comezar. Afortunadamente, nese momento a documentación xa se engadira ao subcórtex nalgún lugar, e lembramos que cando se lanzou, Spark busca un porto no que comezar. Se o primeiro porto do intervalo está ocupado, móvese ao seguinte en orde. Se é gratuíto, captura. E hai un parámetro que indica o número máximo de intentos para iso. O valor predeterminado é 16. O número é menor que o número de persoas do noso grupo na clase. En consecuencia, tras 16 intentos, Spark deuse por vencido e dixo que non podía comezar. Corriximos este parámetro.

spark.port.maxRetries=50

A continuación falarei sobre algunhas configuracións que non están moi relacionadas coas particularidades do noso caso.

Para iniciar Spark máis rápido, recoméndase arquivar o cartafol jars situado no directorio home SPARK_HOME e poñelo en HDFS. Entón non perderá o tempo cargando estes jarniks polos traballadores.

spark.yarn.archive=hdfs:///tmp/spark-archive.zip

Tamén se recomenda usar kryo como serializador para un funcionamento máis rápido. Está máis optimizado que o predeterminado.

spark.serializer=org.apache.spark.serializer.KryoSerializer

E tamén hai un problema de longa data con Spark que moitas veces falla da memoria. Moitas veces isto ocorre no momento no que os traballadores o calcularon todo e envían o resultado ao condutor. Fixemos este parámetro máis grande para nós. Por defecto, é de 1 GB, fixémolo 3.

spark.driver.maxResultSize=3072

E por último, como sobremesa. Como actualizar Spark á versión 2.1 na distribución de HortonWorks - HDP 2.5.3.0. Esta versión de HDP contén unha versión 2.0 preinstalada, pero unha vez decidimos por nós mesmos que Spark está a desenvolverse de forma bastante activa, e cada nova versión soluciona algúns erros e ofrece funcións adicionais, incluídas para a API de Python, polo que decidimos o que precisa ser feito é unha actualización.

Baixou a versión do sitio web oficial de Hadoop 2.7. Descomprimilo e colócao no cartafol HDP. Instalamos as ligazóns simbólicas segundo fose necesario. Lanzámolo, non comeza. Escribe un erro moi pouco claro.

java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfig

Despois de buscar en Google, descubrimos que Spark decidiu non esperar ata que nacese Hadoop e decidiu usar a nova versión da camisola. Eles mesmos discuten entre eles sobre este tema en JIRA. A solución foi descargar Versión de camiseta 1.17.1. Coloca isto no cartafol jars en SPARK_HOME, comprime de novo e cárgueo en HDFS.

Evitamos este erro, pero xurdiu un novo e bastante simplificado.

org.apache.spark.SparkException: Yarn application has already ended! It might have been killed or unable to launch application master

Ao mesmo tempo, tentamos executar a versión 2.0 - todo está ben. Tenta adiviñar o que está pasando. Miramos os rexistros desta aplicación e vimos algo así:

/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jar

En xeral, por algún motivo hdp.version non se resolveu. Despois de buscar en Google, atopamos unha solución. Debes ir á configuración de YARN en Ambari e engadir un parámetro alí ao sitio personalizado de fíos:

hdp.version=2.5.3.0-37

Esta maxia axudou e Spark despegou. Probamos varios dos nosos portátiles Jupyter. Todo está funcionando. Estamos preparados para a primeira lección de Spark o sábado (mañá)!

DUP. Durante a lección, saíu á luz outro problema. Nalgún momento, YARN deixou de proporcionar contedores para Spark. En YARN foi necesario corrixir o parámetro, que por defecto era 0.2:

yarn.scheduler.capacity.maximum-am-resource-percent=0.8

É dicir, só o 20% dos recursos participaron na distribución dos recursos. Despois de cambiar os parámetros, volvemos cargar YARN. O problema resolveuse e o resto dos participantes tamén puideron executar o contexto de chispa.

Fonte: www.habr.com

Engadir un comentario