Programmering

Tutorial: Spark-applikationsarkitektur og klynger

Få den fulde bog
Dataanalyse med gnist ved hjælp af Python (Addison-Wesley Data & Analytics-serien) MSRP $ 44,99 Se den

Denne artikel er et uddrag fra Pearson Addison-Wesley-bogen "Data Analytics with Spark Using Python" af Jeffrey Aven. Genoptrykt her med tilladelse fra Pearson © 2018. For mere information, besøg informit.com/aven/infoworld.

Inden du begynder din rejse som Apache Spark-programmør, skal du have en solid forståelse af Spark-applikationsarkitekturen og hvordan applikationer udføres i en Spark-klynge. Denne artikel undersøger nøjagtigt komponenterne i en Spark-applikation, ser på, hvordan disse komponenter fungerer sammen, og ser på, hvordan Spark-applikationer kører på enkeltstående og YARN-klynger.

Anatomi af en gnistapplikation

En Spark-applikation indeholder flere komponenter, som alle findes, uanset om du kører Spark på en enkelt maskine eller på tværs af en klynge på hundreder eller tusinder af noder.

Hver komponent har en specifik rolle i udførelsen af ​​et Spark-program. Nogle af disse roller, såsom klientkomponenterne, er passive under udførelsen; andre roller er aktive i udførelsen af ​​programmet, herunder komponenter, der udfører beregningsfunktioner.

Komponenterne i en Spark-applikation er:

  • føreren
  • mesteren
  • klyngemanageren
  • eksekutørerne

De kører alle på arbejderknudepunkter, også kaldet arbejdere.

Figur 1 viser alle gnistkomponenterne i sammenhæng med en selvstændig gnistapplikation.

Pearson Addison-Wesley

Alle Spark-komponenter - inklusive driver-, master- og eksekveringsprocesser - kører i Java-virtuelle maskiner. En JVM er en runtime-motor på tværs af platforme, der kan udføre instruktioner, der er samlet i Java bytecode. Scala, som Spark er skrevet i, kompileres til bytecode og kører på JVM'er.

Det er vigtigt at skelne mellem Sparks applikationer til runtime-applikationer og de placeringer og nodetyper, de kører på. Disse komponenter kører forskellige steder ved hjælp af forskellige implementeringstilstande, så tænk ikke på disse komponenter i fysisk node eller instans. For eksempel, når der køres Spark på YARN, ville der være flere variationer i figur 1. Imidlertid er alle de afbildede komponenter stadig involveret i applikationen og har de samme roller.

Gnistdriver

Livet for en Spark-applikation starter og slutter med Spark-driveren. Driveren er den proces, som klienter bruger til at indsende ansøgninger i Spark. Chaufføren er også ansvarlig for at planlægge og koordinere udførelsen af ​​Spark-programmet og returnere status og / eller resultater (data) til klienten. Driveren kan fysisk opholde sig på en klient eller på en node i klyngen, som du vil se senere.

SparkSession

Spark-driveren er ansvarlig for at oprette SparkSession. SparkSession-objektet repræsenterer en forbindelse til en Spark-klynge. SparkSession er instantieret i begyndelsen af ​​en Spark-applikation, inklusive de interaktive skaller, og bruges til hele programmet.

Før Spark 2.0 omfattede indgangspunkter for Spark-applikationer SparkContext, der blev brugt til Spark-kerneapplikationer; SQLContext og HiveContext, der bruges med Spark SQL-applikationer; og StreamingContext, der bruges til Spark Streaming-applikationer. SparkSession-objektet introduceret i Spark 2.0 kombinerer alle disse objekter til et enkelt indgangspunkt, der kan bruges til alle Spark-applikationer.

Gennem sine SparkContext- og SparkConf-underordnede objekter indeholder SparkSession-objektet alle de runtime-konfigurationsegenskaber, der er indstillet af brugeren, inklusive konfigurationsegenskaber såsom master, applikationsnavn og antal eksekutører. Figur 2 viser SparkSession-objektet og nogle af dets konfigurationsegenskaber i a pyspark skal.

Pearson Addison-Wesley

SparkSession navn

Objektnavnet for SparkSession-forekomsten er vilkårligt. Som standard navngives SparkSession-instantiering i Spark interaktive skaller gnist. For konsistens instantierer du altid SparkSession som gnist; navnet er dog op til udviklerens skøn.

Koden nedenfor viser, hvordan man opretter en SparkSession i en ikke-interaktiv Spark-applikation, såsom et program, der sendes ved hjælp af gnist-indsende.

fra pyspark.sql importerer SparkSession

gnist = SparkSession.builder \

.master ("gnist: // sparkmaster: 7077") \

.appName ("Min gnistapplikation") \

.config ("spark.submit.deployMode", "klient") \

.getOrCreate ()

numlines = spark.sparkContext.textFile ("fil: /// opt / gnist / licenser") \

.tælle()

print ("Det samlede antal linjer er" + str (numlines))

Applikationsplanlægning

En af driverens hovedfunktioner er at planlægge applikationen. Driveren tager applikationsbehandlingsinput og planlægger udførelsen af ​​programmet. Chaufføren tager alt det ønskede transformationer(databehandlingsoperationer) og handlinger (anmoder om output eller beder om at udføre programmer) og opretter en rettet acyklisk graf (DAG) af noder, der hver repræsenterer et transformations- eller beregningstrin.

Regisseret acyklisk graf (DAG)

En DAG er en matematisk konstruktion, der ofte bruges i datalogi til at repræsentere datastrømme og deres afhængighed. DAG'er indeholder hjørner (eller noder) og kanter. Vertices i en dataflydskontekst er trin i procesflowet. Kanter i en DAG forbinder hjørner med hinanden i en rettet retning og på en sådan måde, at det er umuligt at have cirkulære referencer.

En DAG til Spark-applikation består af opgaver og niveauer. En opgave er den mindste enhed af planlægningsarbejde i et Spark-program. Et trin er et sæt opgaver, der kan køres sammen. Stadier er afhængige af hinanden; med andre ord er der sceneafhængigheder.

I en procesplanlægning er DAG'er ikke unikke for Spark. For eksempel bruges de i andre big data-økosystemprojekter, såsom Tez, Drill og Presto til planlægning. DAG'er er grundlæggende for Spark, så det er værd at være fortrolig med konceptet.

Ansøgning orkestrering

Føreren koordinerer også kørslen af ​​etaper og opgaver, der er defineret i DAG. De vigtigste driveraktiviteter involveret i planlægning og drift af opgaver inkluderer følgende:

  • At holde styr på tilgængelige ressourcer til at udføre opgaver.
  • Planlægning af opgaver til at køre “tæt” på dataene, hvor det er muligt (begrebet datalokalitet).

Andre funktioner

Ud over planlægning og orkestrering af udførelsen af ​​et Spark-program er føreren også ansvarlig for at returnere resultaterne fra en applikation. Disse kan være returkoder eller data i tilfælde af en handling, der anmoder om, at data returneres til klienten (for eksempel en interaktiv forespørgsel).

Driveren betjener også applikationsgrænsefladen på port 4040, som vist i figur 3. Denne brugergrænseflade oprettes automatisk; det er uafhængigt af den indsendte kode eller hvordan den blev sendt (det vil sige interaktiv ved hjælp af pysparkeller ikke-interaktiv ved hjælp af gnist-indsende).

Pearson Addison-Wesley

Hvis efterfølgende applikationer startes på den samme vært, anvendes successive porte til applikationsgrænsefladen (for eksempel 4041, 4042 osv.).

Gnistarbejdere og eksekutører

Spark-eksekutører er de processer, som Spark DAG-opgaver kører på. eksekutører reserverer CPU- og hukommelsesressourcer på slaveknudepunkter eller arbejdere i en Spark-klynge. En eksekutor er dedikeret til en bestemt Spark-applikation og afsluttes, når applikationen er færdig. Et Spark-program består normalt af mange eksekutører, der ofte arbejder parallelt.

Typisk har en arbejdsknude - som er vært for eksekutorprocessen - et endeligt eller fast antal eksekutører, der er tildelt til enhver tid. Derfor har en klynge - der er et kendt antal noder - et begrænset antal eksekutører, der er tilgængelige til at køre til enhver tid. Hvis en applikation kræver eksekutører, der overstiger klyngens fysiske kapacitet, er de planlagt til at starte, når andre eksekutører udfylder og frigiver deres ressourcer.

Som tidligere nævnt er JVM'er vært for Spark-eksekutører. JVM til en eksekutor tildeles en bunke, som er et dedikeret hukommelsesrum, hvor du kan gemme og administrere objekter.

Mængden af ​​hukommelse, der er afsat til en JVM-bunke for en eksekutor, indstilles af ejendommen spark.executor.memory eller som --eksekutør-hukommelse argument til pyspark, gnistskal, eller gnist-indsende kommandoer.

Eksekutører gemmer outputdata fra opgaver i hukommelsen eller på disken. Det er vigtigt at bemærke, at arbejdere og eksekutører kun er opmærksomme på de opgaver, der er tildelt dem, mens føreren er ansvarlig for at forstå det komplette sæt opgaver og de respektive afhængigheder, der omfatter en applikation.

Ved at bruge Spark-applikationsgrænsefladen på port 404x af driverværten kan du inspicere eksekutører for applikationen, som vist i figur 4.

Pearson Addison-Wesley

For Spark-uafhængige klyngeimplementeringer udsætter en arbejdsknude en brugergrænseflade på port 8081, som vist i figur 5.

Pearson Addison-Wesley

Spark master og cluster manager

Spark-driveren planlægger og koordinerer det sæt opgaver, der kræves for at køre en Spark-applikation. Selve opgaverne køres i eksekutører, som er hostet på arbejdstagernoder.

Masteren og klyngemanageren er de centrale processer, der overvåger, reserverer og fordeler de distribuerede klyngeressourcer (eller containere, i tilfælde af YARN eller Mesos), som eksekutørerne kører på. Masteren og klyngeadministratoren kan være separate processer, eller de kan kombineres i en proces, som det er tilfældet, når Spark køres i standalone-tilstand.

Gnistmester

Spark-master er den proces, der anmoder om ressourcer i klyngen og gør dem tilgængelige for Spark-driveren. I alle implementeringstilstande forhandler masteren ressourcer eller containere med medarbejdernoder eller slavernoder og sporer deres status og overvåger deres fremskridt.

Når Spark køres i standalone-tilstand, serverer Spark-masterprocessen et web-UI på port 8080 på masterværten, som vist i figur 6.

Pearson Addison-Wesley

Spark master versus Spark driver

Det er vigtigt at skelne mellem driverens og masterens kørselsfunktioner. Navnet mestre kan udledes til at betyde, at denne proces regulerer udførelsen af ​​applikationen - men dette er ikke tilfældet. Skibsføreren anmoder simpelthen om ressourcer og stiller disse ressourcer til rådighed for driveren. Selvom mesteren overvåger status og sundhed for disse ressourcer, er den ikke involveret i udførelsen af ​​applikationen og koordineringen af ​​dens opgaver og faser. Det er chaufførens job.

Klyngemanager

Klyngeadministratoren er den proces, der er ansvarlig for overvågning af medarbejdernoder og reserverer ressourcer på disse noder efter anmodning fra masteren. Master gør derefter disse klyngeressourcer tilgængelige for driveren i form af eksekutorer.

Som nævnt tidligere kan klyngeadministratoren være adskilt fra masterprocessen. Dette er tilfældet, når du kører Spark på Mesos eller YARN. I tilfælde af Spark, der kører i standalone-tilstand, udfører masterprocessen også klyngestyringens funktioner. Effektivt fungerer det som sin egen klyngemanager.

Et godt eksempel på cluster manager-funktionen er YARN ResourceManager-processen til Spark-applikationer, der kører på Hadoop-klynger. ResourceManager planlægger, tildeler og overvåger sundheden for containere, der kører på YARN NodeManagers. Spark-applikationer bruger derefter disse containere til at være vært for eksekveringsprocesser såvel som masterprocessen, hvis applikationen kører i clustermode.

Gnist applikationer ved hjælp af den enkeltstående planlægning

I kapitel 2, "Implementering af gnist", forklarede jeg den enkeltstående planlægning som en installationsmulighed for Spark. Der implementerede jeg en fuldt funktionsdygtig multinode Spark standalone-klynge i en af ​​øvelserne i kapitel 2. Som tidligere nævnt udfører Spark-masterprocessen også en cluster manager-funktion i en Spark-klynge, der kører i standalone-tilstand, og styrer tilgængelige ressourcer på klynge og give dem til masterprocessen til brug i en Spark-applikation.

Gnistapplikationer, der kører på YARN

Hadoop er en meget populær og almindelig implementeringsplatform for Spark. Nogle eksperter i branchen mener, at Spark snart vil erstatte MapReduce som den primære behandlingsplatform til applikationer i Hadoop. Gnistapplikationer på YARN deler den samme runtime-arkitektur, men har nogle små forskelle i implementeringen.

ResourceManager som klyngeadministrator

I modsætning til den uafhængige planlægning er klyngeadministratoren i en YARN-klynge YARN ResourceManager. ResourceManager overvåger ressourceforbrug og tilgængelighed på tværs af alle noder i en klynge. Kunder indsender Spark-ansøgninger til YARN ResourceManager. ResourceManager tildeler den første container til applikationen, en særlig container kaldet ApplicationMaster.

ApplicationMaster som Spark master

ApplicationMaster er Spark-masterprocessen. Som masterprocessen gør i andre klyngeimplementeringer, forhandler ApplicationMaster ressourcer mellem applikationsdriveren og klyngemanageren (eller ResourceManager i dette tilfælde); det gør derefter disse ressourcer (containere) tilgængelige for driveren til brug som eksekutorer til at køre opgaver og gemme data til applikationen.

ApplicationMaster forbliver i applikationens levetid.

Implementeringstilstande til Spark-applikationer, der kører på YARN

To implementeringstilstande kan bruges, når du indsender Spark-applikationer til en YARN-klynge: klienttilstand og klyngetilstand. Lad os se på dem nu.

Klienttilstand

I klienttilstand kører driverprocessen på den klient, der indsender applikationen. Det er i det væsentlige ustyret; hvis driverværten mislykkes, mislykkes applikationen. Klienttilstand understøttes for begge interaktive shell-sessioner (pyspark, gnistskalog så videre) og ikke-interaktiv ansøgning (gnist-indsende). Koden nedenfor viser, hvordan man starter en pyspark session ved hjælp af klientimplementeringstilstand.

$ SPARK_HOME / bin / pyspark \

--mester garn-klient \

--num-eksekutorer 1 \

--driverhukommelse 512m \

--eksekutør-hukommelse 512m \

- eksekutorkerner 1

# ELLER

$ SPARK_HOME / bin / pyspark \

--mester garn \

--deploy-mode klient \

--num-eksekutorer 1 \

--driverhukommelse 512m \

--eksekutør-hukommelse 512m \

- eksekutorkerner 1

Figur 7 giver en oversigt over et Spark-program, der kører på YARN i klienttilstand.

Pearson Addison-Wesley

Trinene vist i figur 7 er:

  1. Klienten sender et Spark-program til klyngeadministratoren (YARN ResourceManager). Driverprocessen, SparkSession og SparkContext oprettes og køres på klienten.
  2. ResourceManager tildeler en ApplicationMaster (Spark master) til applikationen.
  3. ApplicationMaster anmoder om, at containere bruges til eksekutører fra ResourceManager. Med de tildelte containere gyter eksekutørerne.
  4. Chaufføren, der er placeret på klienten, kommunikerer derefter med eksekutørerne til marskalbehandling af opgaver og faser i Spark-programmet. Chaufføren returnerer status, resultater og status til klienten.

Klientimplementeringstilstanden er den enkleste tilstand at bruge. Det mangler dog den krævede fleksibilitet til de fleste produktionsapplikationer.

Klyngetilstand

I modsætning til klientimplementeringstilstand, med et Spark-program, der kører i YARN Cluster-tilstand, kører selve driveren på klyngen som en underproces af ApplicationMaster. Dette giver modstandsdygtighed: Hvis ApplicationMaster-processen, der hoster driveren, mislykkes, kan den geninstalleres på en anden knude i klyngen.

Koden nedenfor viser, hvordan man indsender en ansøgning ved hjælp af gnist-indsende og implementeringstilstanden YARN-klynge. Da driveren er en asynkron proces, der kører i klyngen, understøttes klyngetilstand ikke til de interaktive shell-applikationer (pyspark og gnistskal).

$ SPARK_HOME / bin / gnist-indsende \

- master garn-klynge \

--num-eksekutorer 1 \

--driverhukommelse 512m \

--eksekutør-hukommelse 512m \

- eksekutorkerner 1

$ SPARK_HOME / eksempler / src / main / python / pi.py 10000

# ELLER

--mester garn \

--deploy-mode klynge \

--num-eksekutorer 1 \

--driverhukommelse 512m \

--eksekutør-hukommelse 512m \

- eksekutorkerner 1

$ SPARK_HOME / eksempler / src / main / python / pi.py 10000

Figur 8 giver en oversigt over et Spark-program, der kører på YARN i klyngetilstand.

Pearson Addison-Wesley

Trinene vist i figur 8 er:

  1. Klienten, en brugerproces, der påberåber sig gnist-indsende, sender en Spark-applikation til klyngemanageren (YARN ResourceManager).
  2. ResourceManager tildeler en ApplicationMaster (Spark master) til applikationen. Driverprocessen oprettes på samme klyngenode.
  3. ApplicationMaster anmoder containere til eksekutører fra ResourceManager. eksekutører er skabt i de containere, der er tildelt ApplicationMaster af ResourceManager. Chaufføren kommunikerer derefter med eksekutørerne for at behandle opgaver og faser i Spark-programmet.
  4. Driveren, der kører på en node i klyngen, returnerer klienten status, resultater og status.

Spark-applikationsweb-brugergrænsefladen, som vist tidligere, er tilgængelig fra ApplicationMaster-værten i klyngen; et link til denne brugergrænseflade er tilgængelig fra YARN ResourceManager UI.

Lokal tilstand igen

I lokal tilstand kører driveren, masteren og eksekutøren alle i en enkelt JVM. Som nævnt tidligere i dette kapitel er dette nyttigt til udvikling, enhedstest og fejlretning, men det har begrænset brug til at køre produktionsapplikationer, fordi det ikke distribueres og ikke skaleres. Desuden udføres ikke mislykkede opgaver i et Spark-program, der kører i lokal tilstand, som standard igen. Du kan dog tilsidesætte denne adfærd.

Når du kører Spark i lokal tilstand, er applikationsgrænsefladen tilgængelig på // localhost: 4040. Master- og arbejder-UI'erne er ikke tilgængelige, når de kører i lokal tilstand.