Configuració de Spark a YARN

Habr, hola! Ahir a trobada dedicada a Apache Spark, dels nois de Rambler&Co, hi havia moltes preguntes dels participants relacionades amb la configuració d'aquesta eina. Vam decidir seguir els seus passos i compartir la nostra experiència. El tema no és fàcil, així que us convidem a compartir la vostra experiència als comentaris, potser també entenem i utilitzem alguna cosa malament.

Una petita introducció a com fem servir Spark. Tenim un programa de tres mesos "Especialista en Big Data", i al llarg del segon mòdul els nostres participants treballen aquest instrument. En conseqüència, la nostra tasca, com a organitzadors, és preparar el clúster per utilitzar-lo en aquest cas.

La peculiaritat del nostre ús és que el nombre de persones que treballen simultàniament a Spark pot ser igual al de tot el grup. Per exemple, en un seminari, quan tothom intenta alguna cosa al mateix temps i repeteix després del nostre professor. I això no és molt, de vegades fins a 40 persones. Probablement no hi hagi moltes empreses al món que s'enfrontin a aquest cas d'ús.

A continuació, us explicaré com i per què hem seleccionat determinats paràmetres de configuració.

Comencem des del principi. Spark té 3 opcions per executar-se en un clúster: autònom, amb Mesos i amb YARN. Vam decidir triar la tercera opció perquè tenia sentit per a nosaltres. Ja tenim un clúster Hadoop. Els nostres participants ja coneixen bé la seva arquitectura. Fem servir YARN.

spark.master=yarn

A més, més interessant. Cadascuna d'aquestes 3 opcions de desplegament té 2 opcions de desplegament: client i clúster. Basat documentació i diversos enllaços a Internet, podem concloure que el client és adequat per al treball interactiu, per exemple, a través del bloc de notes Jupyter, i el clúster és més adequat per a solucions de producció. En el nostre cas, ens interessava el treball interactiu, per tant:

spark.deploy-mode=client

En general, a partir d'ara Spark funcionarà d'alguna manera a YARN, però això no ens n'hi ha prou. Com que tenim un programa sobre big data, de vegades els participants no en tenien prou amb el que s'obtenia en el marc d'un tall uniforme dels recursos. I després vam trobar una cosa interessant: l'assignació dinàmica de recursos. En resum, la qüestió és la següent: si teniu una tasca difícil i el clúster és gratuït (per exemple, al matí), utilitzar aquesta opció Spark us pot proporcionar recursos addicionals. La necessitat es calcula allà segons una fórmula astuta. No entrarem en detalls: funciona bé.

spark.dynamicAllocation.enabled=true

Vam establir aquest paràmetre i, a l'inici, Spark es va estavellar i no es va iniciar. És cert, perquè l'havia de llegir documentació amb més cura. Afirma que perquè tot estigui bé, també cal que habiliteu un paràmetre addicional.

spark.shuffle.service.enabled=true

Per què és necessari? Quan la nostra feina ja no requereixi tants recursos, Spark hauria de tornar-los a la piscina comuna. L'etapa que consumeix més temps en gairebé qualsevol tasca de MapReduce és l'etapa Shuffle. Aquest paràmetre us permet desar les dades que es generen en aquesta etapa i alliberar els executors en conseqüència. I l'executor és el procés que calcula tot sobre el treballador. Té un cert nombre de nuclis de processador i una certa quantitat de memòria.

S'ha afegit aquest paràmetre. Tot semblava funcionar. Es va fer notar que els participants rebien més recursos quan els necessitaven. Però va sorgir un altre problema: en algun moment altres participants es van despertar i també volien utilitzar Spark, però tot estava ocupat allà i no estaven contents. Es poden entendre. Vam començar a mirar la documentació. Va resultar que encara hi ha una sèrie de paràmetres amb els quals podeu influir en el procés. Per exemple, si l'executor està en mode d'espera, després de quin temps se'n poden treure recursos?

spark.dynamicAllocation.executorIdleTimeout=120s

En el nostre cas, si els vostres marmessors no fan res durant dos minuts, torneu-los a la piscina comuna. Però aquest paràmetre no sempre era suficient. Era evident que la persona feia temps que no feia res, i no s'alliberaven recursos. Va resultar que també hi ha un paràmetre especial: després de quin moment seleccionar els executors que continguin dades a la memòria cau. Per defecte, aquest paràmetre era infinit! Ho vam corregir.

spark.dynamicAllocation.cachedExecutorIdleTimeout=600s

És a dir, si els vostres marmessors no fan res durant 5 minuts, doneu-los a la piscina comuna. En aquest mode, la velocitat d'alliberament i emissió de recursos per a un gran nombre d'usuaris s'ha tornat decent. La quantitat de descontentament ha disminuït. Però vam decidir anar més enllà i limitar el nombre màxim d'executors per aplicació, bàsicament per participant del programa.

spark.dynamicAllocation.maxExecutors=19

Ara, per descomptat, hi ha persones insatisfetes a l'altra banda: "el clúster està inactiu i només tinc 19 executors", però què podeu fer necessitem un equilibri correcte? No pots fer feliç a tothom.

I una petita història més relacionada amb les especificitats del nostre cas. D'alguna manera, diverses persones van arribar tard a una lliçó pràctica i, per alguna raó, Spark no va començar per ells. Hem observat la quantitat de recursos gratuïts: sembla que hi és. L'espurna hauria de començar. Afortunadament, en aquell moment la documentació ja s'havia afegit al subcòrtex en algun lloc, i vam recordar que quan es va llançar, Spark busca un port on començar. Si el primer port del rang està ocupat, es mou al següent en ordre. Si és gratuït, captura. I hi ha un paràmetre que indica el nombre màxim d'intents per a això. El valor predeterminat és 16. El nombre és inferior al nombre de persones del nostre grup a classe. En conseqüència, després de 16 intents, Spark es va rendir i va dir que no podia començar. Hem corregit aquest paràmetre.

spark.port.maxRetries=50

A continuació us explicaré algunes configuracions que no estan gaire relacionades amb les particularitats del nostre cas.

Per iniciar l'Spark més ràpidament, es recomana arxivar la carpeta jars situada al directori inicial SPARK_HOME i posar-la a HDFS. Llavors no perdrà temps carregant aquests jarniks pels treballadors.

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

També es recomana utilitzar kryo com a serialitzador per a un funcionament més ràpid. Està més optimitzat que el predeterminat.

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

I també hi ha un problema de llarga data amb Spark que sovint es bloqueja de la memòria. Sovint això passa en el moment en què els treballadors ho han calculat tot i envien el resultat al conductor. Hem augmentat aquest paràmetre per nosaltres mateixos. Per defecte, és d'1 GB, el vam fer 3.

spark.driver.maxResultSize=3072

I per últim, com a postres. Com actualitzar Spark a la versió 2.1 a la distribució HortonWorks - HDP 2.5.3.0. Aquesta versió d'HDP conté una versió 2.0 preinstal·lada, però una vegada vam decidir per nosaltres mateixos que Spark s'està desenvolupant de manera força activa, i cada nova versió corregeix alguns errors a més de proporcionar funcions addicionals, inclosa per a l'API de Python, així que vam decidir què cal fer. fet és una actualització.

S'ha baixat la versió del lloc web oficial per a Hadoop 2.7. Descomprimiu-lo i poseu-lo a la carpeta HDP. Hem instal·lat els enllaços simbòlics segons calia. L'iniciem, no comença. Escriu un error molt estrany.

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

Després de buscar a Google, vam saber que Spark va decidir no esperar fins que naixia Hadoop i va decidir utilitzar la nova versió de la samarreta. Ells mateixos discuteixen entre ells sobre aquest tema a JIRA. La solució va ser descarregar samarreta versió 1.17.1. Col·loqueu-lo a la carpeta jars a SPARK_HOME, torneu-lo a comprimir i pengeu-lo a HDFS.

Vam evitar aquest error, però en va sorgir un de nou i força simplificat.

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

Al mateix temps, intentem executar la versió 2.0: tot està bé. Intenta endevinar què està passant. Vam mirar els registres d'aquesta aplicació i vam veure alguna cosa com això:

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

En general, per algun motiu hdp.version no es va resoldre. Després de buscar a Google, hem trobat una solució. Heu d'anar a la configuració de YARN a Ambari i afegir-hi un paràmetre al lloc personalitzat del fil:

hdp.version=2.5.3.0-37

Aquesta màgia va ajudar i la Spark es va enlairar. Hem provat diversos dels nostres portàtils Jupyter. Tot funciona. Estem preparats per a la primera lliçó de Spark dissabte (demà)!

UPD. Durant la lliçó, va sortir a la llum un altre problema. En algun moment, YARN va deixar de proporcionar contenidors per a Spark. A YARN calia corregir el paràmetre, que per defecte era 0.2:

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

És a dir, només el 20% dels recursos van participar en la distribució dels recursos. Després de canviar els paràmetres, hem tornat a carregar YARN. El problema es va resoldre i la resta de participants també van poder iniciar un context d'espurna.

Font: www.habr.com

Afegeix comentari