Žargon Sparku pro začátečníky

Tento blog má objasnit některé počáteční potíže při kódování distribuovaných výpočtů Spark pro začátečníky. Kromě naučení se API je třeba se vybavit podrobnostmi o clusteru, aby se co nejlépe využil výkon Sparku.

Výchozím bodem by měl být Přehled režimu clusteru .

A některé časté otázky, které se mohou objevit, jsou:

  1. Stále nemůžete pochopit různé procesy v clusteru Spark Standalone a paralelizmus.
  2. Spustili jste bin\start-slave.sh a zjistili jste, že se spawnul worker, což je vlastně JVM. Je worker proces JVM nebo ne?
  3. Podle výše uvedeného odkazu je executor proces spuštěný pro aplikaci na pracovním uzlu, který spouští úlohy. Executor je také JVM.
  4. Executory jsou na aplikaci. Jaká je tedy role workeru? Koordinuje se s executorem a výsledek sděluje zpět ovladači, nebo ovladač mluví přímo s executorem? Pokud ano, jaký je pak účel workeru?
  5. Jak řídit počet executorů pro aplikaci?
  6. Mohou úlohy uvnitř executoru běžet paralelně? Pokud ano, jak nastavit počet vláken pro executor?
  7. Jaký je vztah mezi workerem, executory a jádry executoru ( – total-executor-cores)?
  8. Co znamená mít více workerů na uzel?

Zopakujme si podrobnosti o režimu Spark Cluster.

Spark používá architekturu master/slave. Jak vidíte na obrázku, má jednoho centrálního koordinátora (Driver), který komunikuje s mnoha distribuovanými pracovníky (executory). Ovladač a každý z vykonavatelů běží ve vlastních procesech Java.

Ovladač je proces, ve kterém běží hlavní metoda. Nejprve převede uživatelský program na úlohy a poté naplánuje úlohy na vykonavatele.

Spark Application – -> Driver – -> List of Tasks – -> Scheduler – -> Executors

EXECUTORS

Executors jsou procesy pracovních uzlů, které mají na starosti spouštění jednotlivých úloh v dané úloze Spark. Jsou spouštěny na začátku aplikace Spark a obvykle běží po celou dobu životnosti aplikace. Po spuštění úlohy odesílají výsledky do ovladače. Poskytují také úložiště RDD v paměti, které uživatelské programy ukládají do mezipaměti prostřednictvím Správce bloků.

Při spuštění se vykonavatelé registrují u ovladače a od té doby komunikují přímo. Pracovníci mají na starosti informovat správce clusteru o dostupnosti svých zdrojů.

V samostatném clusteru získáte jeden vykonavatel na jednoho pracovníka, pokud si nepohrajete se spark.executor.cores a pracovník nemá dostatek jader, aby pojal více než jeden vykonavatel.

  • Samostatný cluster s 5 pracovními uzly (každý uzel má 8 jader) Když spustím aplikaci s výchozím nastavením.
  • Spark lačně získá tolik jader a vykonavatelů, kolik jich plánovač nabízí. Takže nakonec získáte 5 exekutorů s 8 jádry každý.

Následující volby spark-submit umožňují hrát si s počtem exekutorů:

– executor-memory MEM Paměť na exekutor (např. 1000M, 2G) (Výchozí: 1G).

Pouze pro samostatný Spark a YARN:
– executor-cores NUM Počet jader na exekutor. (Výchozí: 1 v režimu YARN nebo všechna dostupná jádra na workeru v samostatném režimu)

Pouze pro YARN:
– num-executors NUM Počet spouštěných executorů (Výchozí: 2). Pokud je zapnuto dynamické přidělování, bude počáteční počet vykonavatelů alespoň NUM.

  • Oznamuje instance 2 workerů jeden pracovní uzel se dvěma pracovními procesy?“

Uzel je stroj a není dobrý důvod spouštět více než jeden worker na stroj. Takže dva pracovní uzly obvykle znamenají dva stroje, každý s jedním pracovním procesem Sparku.

1 uzel = 1 pracovní proces

  • Drží každá instance pracovního uzlu vykonavatele pro konkrétní aplikaci (který spravuje úložiště, úlohu), nebo jeden pracovní uzel drží jeden vykonavatel?

Pracovní uzly drží mnoho vykonavatelů, pro mnoho aplikací. Jedna aplikace má vykonavatele na mnoha pracovních uzlech

Pracovní uzel může držet více vykonavatelů (procesů), pokud má dostatek procesoru, paměti a úložiště.

  • BTW, Počet vykonavatelů v pracovním uzlu v daném okamžiku zcela závisí na pracovní zátěži clusteru a schopnosti uzlu spustit kolik vykonavatelů.

PROUD VÝKONU APLIKACE

Při odesílání aplikace do clusteru pomocí příkazu spark-submit se interně děje toto:

  1. Samostatná aplikace se spustí a instancuje instanci SparkContext/SparkSession (a teprve poté je možné aplikaci nazvat ovladačem).
  2. Program ovladače požádá správce clusteru o prostředky pro spuštění vykonavatelů.
  3. Správce clusteru spustí vykonavatele.
  4. Proces ovladače probíhá prostřednictvím uživatelské aplikace. V závislosti na akcích a transformacích nad RDD jsou úlohy odesílány vykonavatelům.
  5. Vykonavatelé provádějí úlohy a ukládají výsledky.
  6. Pokud některý pracovník havaruje, jeho úlohy budou odeslány jiným vykonavatelům, aby byly znovu zpracovány. V knize „Learning Spark: Lightning-Fast Big Data Analysis“ se hovoří o Sparku a toleranci poruch:

Spark se automaticky vypořádá s poruchou nebo pomalým strojem tak, že znovu provede poruchové nebo pomalé úlohy. Pokud například dojde k pádu uzlu, na kterém běží oddíl operace map(), Spark ji znovu spustí na jiném uzlu; a i když uzel nespadne, ale je prostě mnohem pomalejší než ostatní uzly, Spark může preventivně spustit „spekulativní“ kopii úlohy na jiném uzlu a převzít její výsledek, pokud skončí.

  1. Pomocí SparkContext.stop() z ovladače nebo v případě ukončení/havárie hlavní metody budou všechny vykonavatele ukončeny a prostředky clusteru uvolněny správcem clusteru.

Pokud se podíváme na provádění z perspektivy Spark přes libovolného správce prostředků pro program, který spojuje dva rdds a provádí nějakou operaci redukce, pak filtr

Následující seznam zachycuje některá doporučení, která je třeba mít na paměti při jejich konfiguraci:

  • Hadoop/Yarn/OS Deamons: Když spustíme aplikaci Spark pomocí správce clusteru, jako je Yarn, bude na pozadí běžet několik démonů, například NameNode, Secondary NameNode, DataNode, JobTracker a TaskTracker. Při zadávání počtu vykonavatelů se tedy musíme ujistit, že ponecháme stranou dostatek jader (~1 jádro na uzel), aby tyto démony mohly hladce běžet.
  • Yarn ApplicationMaster (AM): ApplicationMaster je zodpovědný za vyjednávání zdrojů od ResourceManageru a spolupráci s NodeManagery při spouštění a monitorování kontejnerů a jejich spotřeby zdrojů. Pokud na yarnu spouštíme spark, musíme počítat se zdroji, které by AM potřeboval (~1024 MB a 1 Executor).
  • HDFS Throughput: V případě, že na yarnu spouštíme spark, musíme počítat se zdroji, které by AM potřeboval (~1024 MB a 1 Executor): HDFS klient má problémy s tunami souběžných vláken. Bylo pozorováno, že HDFS dosahuje plné propustnosti zápisu s ~5 úlohami na executor . Proto je dobré udržovat počet jader na vykonavatele pod tímto číslem.
  • MemoryOverhead:

Dvě věci, kterých je třeba si z tohoto obrázku všimnout:

Full memory requested to yarn per executor =
spark-executor-memory + spark.yarn.executor.memoryOverhead.
spark.yarn.executor.memoryOverhead =
Max(384MB, 7% of spark.executor-memory)

Takže pokud požadujeme 20GB na executor, AM ve skutečnosti dostane 20GB + memoryOverhead = 20 + 7% z 20GB = ~23GB paměti pro nás.

  • Spouštění vykonavatelů s příliš velkou pamětí má často za následek nadměrné zpoždění při vybírání odpadu.
  • Spouštění malých vykonavatelů (například s jedním jádrem a jen tolik paměti, kolik je potřeba pro spuštění jedné úlohy) zahazuje výhody, které plynou ze spouštění více úloh v jednom JVM.

Dost teorie… Pojďme na to prakticky…

Nyní uvažujme 10uzlový cluster s následující konfigurací a analyzujme různé možnosti rozložení vykonavatelů-jader-paměti:

**Cluster Config:**
10 Nodes
16 cores per Node
64GB RAM per Node

První přístup: Tiny executors :

Tiny executors v podstatě znamená jeden executor na jádro. Následující tabulka zobrazuje hodnoty našich spar-config params s tímto přístupem:

- `--num-executors` = `In this approach, we'll assign one executor per core`
= `total-cores-in-cluster`
= `num-cores-per-node * total-nodes-in-cluster`
= 16 x 10 = 160
- `--executor-cores` = 1 (one executor per core)
- `--executor-memory` = `amount of memory per executor`
= `mem-per-node/num-executors-per-node`
= 64GB/16 = 4GB

Analýza: S pouze jedním vykonavatelem na jádro, jak jsme uvedli výše, nebudeme moci využít výhod spouštění více úloh v jednom JVM. Také sdílené/kešované proměnné, jako jsou broadcast proměnné a akumulátory, budou replikovány v každém jádře uzlů, což je 16krát. Také nenecháváme dostatečnou režii paměti pro procesy démona Hadoop/Yarn a nepočítáme v ApplicationManageru.

Druhý přístup: Tlusté vykonavatele (jeden vykonavatel na uzel):

Tlusté vykonavatele v podstatě znamenají jeden vykonavatel na uzel. Následující tabulka zobrazuje hodnoty našich parametrů spark-config při tomto přístupu:

- `--num-executors` = `In this approach, we'll assign one executor per node`
= `total-nodes-in-cluster`
= 10
- `--executor-cores` = `one executor per node means all the cores of the node are assigned to one executor`
= `total-cores-in-a-node`
= 16
- `--executor-memory` = `amount of memory per executor`
= `mem-per-node/num-executors-per-node`
= 64GB/1 = 64GB

Analýza: Se všemi 16 jádry na jeden executor se kromě ApplicationManageru a procesů démonů nepočítá, propustnost HDFS to poškodí a bude to mít za následek nadměrný počet výsledků v podobě smetí. Také to není dobré!

Třetí přístup:

Podle doporučení, která jsme probrali výše:

  • Na základě výše uvedených doporučení přiřaďme 5 jader na vykonavatele => – executor-cores = 5 (pro dobrou propustnost HDFS)
  • Ponechme 1 jádro na uzel pro démony Hadoop/Yarn => Počet jader dostupných na uzel = 16-1 = 15
  • Takže, Celkový počet dostupných jader v clusteru = 15 x 10 = 150
  • Počet dostupných vykonavatelů = (celkový počet jader / počet jader na vykonavatele) = 150 / 5 = 30
  • Ponechání 1 vykonavatele pro ApplicationManager => – počet-vykonavatelů = 29
  • Počet vykonavatelů na uzel = 30/10 = 3
  • Paměť na vykonavatele = 64 GB / 3 = 21 GB
  • Započítání režie haldy = 7 % z 21 GB = 3 GB. Takže skutečná – paměť pro vykonavatele = 21-3 = 18GB

Takže doporučená konfigurace je: 29 vykonavatelů, každý 18GB paměti a každý 5 jader!!!

Analýza: Je zřejmé, jak tento třetí přístup našel správnou rovnováhu mezi přístupy Fat vs Tiny. Netřeba dodávat, že dosáhl paralelizmu tlustého exekutoru a nejlepší propustnosti malého exekutoru!!!

Závěr:

Viděli jsme:

  • Několik doporučení, která je třeba mít na paměti při konfiguraci těchto parametrů pro aplikaci typu spark:
  • Započítat prostředky, které by správce aplikace Yarn potřeboval
  • Jak bychom měli ušetřit některá jádra pro procesy Hadoop/Yarn/OS deamon
  • Poznat využití paměti spark-yarn
  • Také jsme vyzkoušeli a analyzovali tři různé přístupy ke konfiguraci těchto parametrů:
  1. Tiny Executors – Jeden executor na jádro
  2. Fat Executors – Jeden executor na uzel
  3. Doporučený přístup – Správná rovnováha mezi Tiny (Vs) Fat ve spojení s doporučeními.

– num-executors, – executor-cores a – executor-memory.. tyto tři parametry hrají velmi důležitou roli ve výkonu Sparku, protože řídí množství procesorové & paměti, kterou dostane vaše aplikace Spark. Proto je pro uživatele velmi důležité pochopit správný způsob jejich konfigurace. Doufám, že vám tento blog pomohl získat tento pohled…

.