Habr, ciao! Ieri in poi
Una piccola introduzione su come utilizziamo Spark. Abbiamo un programma di tre mesi
La particolarità del nostro utilizzo è che il numero di persone che lavorano contemporaneamente su Spark può essere pari all'intero gruppo. Ad esempio, in un seminario, quando tutti provano qualcosa contemporaneamente e ripetono dopo il nostro insegnante. E questo non è molto, a volte fino a 40 persone. Probabilmente non sono molte le aziende al mondo che si trovano ad affrontare un simile caso d’uso.
Successivamente, ti dirò come e perché abbiamo selezionato determinati parametri di configurazione.
Cominciamo dall'inizio. Spark dispone di 3 opzioni per l'esecuzione su un cluster: autonomo, utilizzando Mesos e utilizzando YARN. Abbiamo deciso di scegliere la terza opzione perché per noi aveva senso. Abbiamo già un cluster Hadoop. I nostri partecipanti conoscono già bene la sua architettura. Usiamo YARN.
spark.master=yarn
Ancora più interessante. Ognuna di queste 3 opzioni di distribuzione ha 2 opzioni di distribuzione: client e cluster. Basato
spark.deploy-mode=client
In generale da ora in poi Spark funzionerà in qualche modo su YARN, ma questo non ci bastava. Poiché abbiamo un programma sui big data, a volte i partecipanti non ne avevano abbastanza di ciò che è stato ottenuto nell'ambito di una suddivisione uniforme delle risorse. E poi abbiamo scoperto una cosa interessante: l'allocazione dinamica delle risorse. In breve, il punto è questo: se hai un compito difficile e il cluster è libero (ad esempio al mattino), utilizzando questa opzione Spark può darti risorse aggiuntive. Lì la necessità viene calcolata secondo una formula astuta. Non entreremo nei dettagli: funziona bene.
spark.dynamicAllocation.enabled=true
Abbiamo impostato questo parametro e all'avvio Spark si è bloccato e non si è avviato. Esatto, perché dovevo leggerlo
spark.shuffle.service.enabled=true
Perché è necessario? Quando il nostro lavoro non richiederà più così tante risorse, Spark dovrebbe restituirle al pool comune. La fase che richiede più tempo in quasi tutte le attività di MapReduce è la fase Shuffle. Questo parametro consente di salvare i dati generati in questa fase e rilasciare di conseguenza gli esecutori. E l'esecutore è il processo che calcola tutto sul lavoratore. Ha un certo numero di core del processore e una certa quantità di memoria.
Questo parametro è stato aggiunto. Tutto sembrava funzionare. È diventato evidente che ai partecipanti venivano effettivamente fornite più risorse quando ne avevano bisogno. Ma è sorto un altro problema: a un certo punto anche altri partecipanti si sono svegliati e volevano usare Spark, ma lì era tutto occupato ed erano insoddisfatti. Possono essere compresi. Abbiamo iniziato a guardare la documentazione. Si è scoperto che esistono numerosi altri parametri che possono essere utilizzati per influenzare il processo. Ad esempio, se l'esecutore è in modalità standby, dopo quanto tempo è possibile prelevarne le risorse?
spark.dynamicAllocation.executorIdleTimeout=120s
Nel nostro caso, se i tuoi esecutori testamentari non fanno nulla per due minuti, restituiscili alla riserva comune. Ma questo parametro non era sempre sufficiente. Era chiaro che la persona non faceva nulla da molto tempo e le risorse non venivano liberate. Si è scoperto che esiste anche un parametro speciale: dopo quanto tempo selezionare gli esecutori che contengono dati memorizzati nella cache. Per impostazione predefinita, questo parametro era infinito! L'abbiamo corretto.
spark.dynamicAllocation.cachedExecutorIdleTimeout=600s
Cioè, se i tuoi esecutori non fanno nulla per 5 minuti, consegnali al pool comune. In questa modalità, la velocità di rilascio ed emissione di risorse per un gran numero di utenti è diventata decente. La quantità di malcontento è diminuita. Ma abbiamo deciso di andare oltre e limitare il numero massimo di esecutori per applicazione, essenzialmente per partecipante al programma.
spark.dynamicAllocation.maxExecutors=19
Ora, ovviamente, dall'altra parte ci sono persone insoddisfatte: "il cluster è inattivo e ho solo 19 esecutori", ma cosa puoi fare? Abbiamo bisogno di una sorta di equilibrio corretto. Non puoi rendere tutti felici.
E ancora una piccola storia relativa alle specificità del nostro caso. In qualche modo, diverse persone erano in ritardo per una lezione pratica e per qualche motivo Spark non è iniziata per loro. Abbiamo esaminato la quantità di risorse gratuite: sembra che ci siano. Dovrebbe iniziare la scintilla. Fortunatamente, a quel punto la documentazione era già stata aggiunta da qualche parte nella sottocorteccia e ci siamo ricordati che all'avvio Spark cerca una porta da cui avviare. Se la prima porta dell'intervallo è occupata, si passa a quella successiva in ordine. Se è gratuito, cattura. E c'è un parametro che indica il numero massimo di tentativi per questo. Il valore predefinito è 16. Il numero è inferiore al numero di persone nel nostro gruppo in classe. Di conseguenza, dopo 16 tentativi, Spark si è arreso e ha detto che non potevo iniziare. Abbiamo corretto questa impostazione.
spark.port.maxRetries=50
Successivamente ti parlerò di alcune impostazioni poco legate alle specificità del nostro caso.
Per avviare Spark più velocemente, si consiglia di archiviare la cartella jars situata nella directory home SPARK_HOME e metterla su HDFS. Quindi non perderà tempo a caricare questi jarnik da parte dei lavoratori.
spark.yarn.archive=hdfs:///tmp/spark-archive.zip
Si consiglia inoltre di utilizzare kryo come serializzatore per un funzionamento più rapido. È più ottimizzato di quello predefinito.
spark.serializer=org.apache.spark.serializer.KryoSerializer
E c'è anche un problema di vecchia data con Spark che spesso si blocca dalla memoria. Spesso ciò accade nel momento in cui gli operai hanno calcolato tutto e inviano il risultato all'autista. Abbiamo ampliato questo parametro per noi stessi. Per impostazione predefinita è 1 GB, ne abbiamo impostati 3.
spark.driver.maxResultSize=3072
E infine come dessert. Come aggiornare Spark alla versione 2.1 sulla distribuzione HortonWorks - HDP 2.5.3.0. Questa versione di HDP contiene una versione 2.0 preinstallata, ma una volta abbiamo deciso da soli che Spark si sta sviluppando abbastanza attivamente e che ogni nuova versione risolve alcuni bug e fornisce funzionalità aggiuntive, inclusa l'API Python, quindi abbiamo deciso cosa deve essere essere fatto è un aggiornamento.
Scaricata la versione dal sito ufficiale per Hadoop 2.7. Decomprimilo e inseriscilo nella cartella HDP. Abbiamo installato i collegamenti simbolici secondo necessità. Lo lanciamo: non si avvia. Scrive un errore molto strano.
java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfig
Dopo aver cercato su Google, abbiamo scoperto che Spark ha deciso di non aspettare la nascita di Hadoop e ha deciso di utilizzare la nuova versione della maglia. Loro stessi discutono tra loro su questo argomento in JIRA. La soluzione era scaricare
Abbiamo aggirato questo errore, ma ne è emerso uno nuovo e piuttosto snello.
org.apache.spark.SparkException: Yarn application has already ended! It might have been killed or unable to launch application master
Allo stesso tempo, proviamo a eseguire la versione 2.0: è tutto ok. Prova a indovinare cosa sta succedendo. Abbiamo esaminato i log di questa applicazione e abbiamo visto qualcosa del genere:
/usr/hdp/${hdp.version}/hadoop/lib/hadoop-lzo-0.6.0.${hdp.version}.jar
In generale, per qualche motivo hdp.version non si risolveva. Dopo aver cercato su Google, abbiamo trovato una soluzione. Devi andare alle impostazioni YARN in Ambari e aggiungere lì un parametro al sito di filati personalizzato:
hdp.version=2.5.3.0-37
Questa magia ha aiutato e Spark è decollato. Abbiamo testato molti dei nostri laptop Jupyter. Tutto funziona. Siamo pronti per la prima lezione di Spark sabato (domani)!
UPD. Durante la lezione è emerso un altro problema. Ad un certo punto, YARN ha smesso di fornire contenitori per Spark. In YARN è stato necessario correggere il parametro, che di default era 0.2:
yarn.scheduler.capacity.maximum-am-resource-percent=0.8
Cioè, solo il 20% delle risorse ha partecipato alla distribuzione delle risorse. Dopo aver modificato i parametri, abbiamo ricaricato YARN. Il problema è stato risolto e anche il resto dei partecipanti è stato in grado di eseguire il contesto Spark.
Fonte: habr.com