Lernen Sie Spark in 20 Tagen (0) Erste Schritte mit der einfachsten Version von Spark

Spark ist eine schnelle, vielseitige und skalierbare Big-Data-Analyse-Engine, die in Scala geschrieben ist. Die sogenannte Big-Data-Analyse analysiert und verarbeitet hauptsächlich große Datenmengen. Dies ist eine wesentliche Fähigkeit für aktuelle Karrieren in der Big-Data-Entwicklung.

1. Kurze Einführung

Das Folgende ist eine kurze Einführung in Spark. Nun geht es hauptsächlich darum, wie gut Spark ist. Wenn Sie es nicht sehen möchten, können Sie direkt mit dem zweiten Schritt fortfahren.

Merkmale

1) Schnell: Im Vergleich zu MapReduce von Hadoop sind die speicherbasierten Vorgänge von Spark mehr als 100-mal schneller, und festplattenbasierte Vorgänge sind ebenfalls mehr als 10-mal schneller. Spark implementiert eine effiziente DAG-Ausführungs-Engine, die Datenströme basierend auf dem Speicher effizient verarbeiten kann. Zwischenergebnisse der Berechnungen werden im Speicher gespeichert.

2) Benutzerfreundlichkeit: Spark unterstützt Java-, Python- und Scala-APIs sowie mehr als 80 erweiterte Algorithmen, sodass Benutzer schnell verschiedene Anwendungen erstellen können. Darüber hinaus unterstützt Spark interaktive Python- und Scala-Shells, und es ist sehr praktisch, Spark-Cluster in diesen Shells zu verwenden, um Lösungen für Probleme zu überprüfen.

3) Universell: Spark bietet eine einheitliche Lösung. Spark kann für Stapelverarbeitung, interaktive Abfragen (Spark SQL), Echtzeit-Stream-Verarbeitung (Spark Streaming), maschinelles Lernen (Spark MLlib) und Graph Computing (GraphX) verwendet werden. Diese verschiedenen Verarbeitungsarten können alle nahtlos innerhalb derselben Anwendung verwendet werden. Die einheitliche Lösung von Spark ist sehr attraktiv. Schließlich möchte jedes Unternehmen eine einheitliche Plattform nutzen, um die auftretenden Probleme zu lösen und so die Arbeitskosten für Entwicklung und Wartung sowie die Materialkosten für die Bereitstellung der Plattform zu senken.

4) Kompatibilität: Spark lässt sich problemlos in andere Open-Source-Produkte integrieren. Spark kann beispielsweise Hadoops YARN und Apache Mesos als Ressourcenverwaltung und -planer verwenden und alle von Hadoop unterstützten Daten verarbeiten, einschließlich HDFS, HBase und Cassandra. Dies ist besonders wichtig für Benutzer, die bereits Hadoop-Cluster bereitgestellt haben, da sie die leistungsstarken Verarbeitungsfunktionen von Spark nutzen können, ohne eine Datenmigration durchführen zu müssen. Spark ist außerdem nicht auf Ressourcenverwaltungs- und -planungsprogramme von Drittanbietern angewiesen. Es implementiert Standalone als integriertes Ressourcenverwaltungs- und Planungsframework, was die Schwelle für die Verwendung von Spark weiter senkt und die Bereitstellung und Verwendung von Spark für jedermann sehr einfach macht. Darüber hinaus bietet Spark auch Tools zur Bereitstellung des Spark-Clusters von Standalone auf EC2.

2. Erste Schritte mit Spark in 20 Codezeilen

Hinweis: Die aktuelle Umgebung ist idea + jdk8. Alle Codes in diesem Artikel basieren auf der vorherigen Java-Programmiergrundlage.

1. Glasverpackung

Erstellen Sie zunächst in der Idee ein normales Maven-Projekt, gehen Sie zur POM-Datei des Projekts und führen Sie die Maven-Abhängigkeit ein. Wenn sie eingeführt wurde, besteht keine Notwendigkeit, sie einzuführen.

<dependencies>
        <!-- scala依赖 开始 -->
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-reflect</artifactId>
            <version>2.12.8</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>2.12.8</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-compiler</artifactId>
            <version>2.12.8</version>
            <scope>compile</scope>
        </dependency>

        <!-- scala依赖 结束 -->

        <!-- spark依赖 开始 -->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.12</artifactId>
            <version>2.4.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-mllib_2.12</artifactId>
            <version>2.4.3</version>
        </dependency>

        <!-- spark依赖 结束 -->
    </dependencies>

    <build>
        <plugins>
            <!-- 该插件用于将 Scala 代码编译成 class 文件 -->
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.4.6</version>
                <executions>
                    <execution>
                        <!-- 声明绑定到 maven 的 compile 阶段 -->
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

2. Erstellen Sie einen Datensatz

Erstellen Sie im Projektverzeichnis einen Datenordner zum Speichern von Daten, erstellen Sie eine Word-Datei und geben Sie den folgenden Inhalt ein:

Die nächste Aufgabe besteht darin, mithilfe von Spark-Statistiken die Häufigkeit des Vorkommens jedes Wortes zu analysieren

java~hadoop~java
html~js
java
js~jquery

3. Erstellen Sie die Datei WordCount.scala für die Berechnung. Beachten Sie, dass der Dateityp Objekt ist. Die Reihenfolge bei der Verwendung von Spark ist ungefähr wie folgt

1. Erstellen Sie einen Spark-Kontext

2. Lesen Sie die Datendatei

3. Verarbeiten Sie Daten in geeigneten Formaten

4. Statistische Berechnungen

5. Holen Sie sich die Ergebnisse und speichern Sie sie

Der spezifische Verarbeitungscode lautet wie folgt

object WordCount {
    
    

  def main(args: Array[String]): Unit = {
    
    
    // 第一个参数启动的方式,第二个参数启动任务的名称
    val spark = new SparkContext("local",
      "WordCount")

    // 读取数据,word就是刚创建的文件
    val data = spark.textFile("data/word")

    // 方便计算的格式
    val result = data
      .flatMap(_.split("~")) // 使用~切分每条记录
      .map((_,1)) // java,1 html,1
     .countByKey() // 统计相同key值的数量

    println(result)
  }

}

Abschließend wird die Häufigkeit des Vorkommens jedes Wortes gedruckt.

Dies ist der einfachste Spark-Anwendungsfall

3. Einführung in den Code-Ausführungsprozess

Der obige Code stellt den grundlegendsten Spark-Fallcode dar. Der folgende Inhalt ist eine Einführung in den Ausführungsprozess des obigen Codes.

3.1 Häufige Schlüsselwörter

Bevor wir Spark lernen, sortieren wir zunächst eine Reihe häufig verwendeter Schlüsselwörter, um zu verhindern, dass die Schüler den Artikel nicht verstehen.

RDD

RDD (Resilient Distributed Dataset) wird als verteilter Datensatz bezeichnet. Es handelt sich um die grundlegendste Datenabstraktion in Spark. Es stellt einen unveränderlichen, partitionierbaren Satz dar, dessen Elemente parallel berechnet werden können. Es ist ein grundlegendes Objekt in Spark.

Defekt:

​Unterstützt keine feinkörnigen Schreib- und Aktualisierungsvorgänge (z. B. Webcrawler).
Spark schreibt Daten grobkörnig. Das sogenannte grobkörnig bedeutet, dass Daten stapelweise geschrieben werden (Batch-Schreiben). Das
Lesen von Daten ist jedoch möglich feinkörnig, was bedeutet, dass es in einem Satz geschrieben werden kann. Das Lesen von Streifen (Lesen von Streifen einzeln)
unterstützt keine inkrementellen iterativen Berechnungen, Flink unterstützt sie jedoch.

DAG-gerichteter azyklischer Graph

In einem gerichteten Diagramm ohne Schleife kann kein Scheitelpunkt über mehrere Kanten zum Punkt zurückkehren, sodass das Diagramm keine Schleife hat.
Persönliches Gefühl: In Spark bezieht es sich auf die gegenseitige Konvertierung verschiedener RDDs für Betrieb und Verarbeitung, und schließlich ist das Ergebnis erhalten.

Transformationsoperator

Transformation bezieht sich auf eine Reihe von Methoden zur RDD-Transformation in Spark. Es handelt sich um ein verzögertes Laden, das nicht sofort ausgeführt wird. Es wird nur ausgeführt, wenn ein Aktionsoperator angetroffen wird.

Aktionsoperator

Eine Methode zur Verarbeitung oder Durchführung von Berechnungen

Arbeit

Aufgabe: Wenn im Programm ein Aktionsoperator angetroffen wird, wird ein Job gesendet, um die vorherige Reihe von Vorgängen auszuführen. Eine Aufgabe hat mehrere Jobs und die Jobs werden seriell ausgeführt.

Abhängigkeit von Breite und Enge

Wenn der Operator ausgeführt wird, wird das RDD konvertiert. Das vorherige RDD ist das übergeordnete RDD und das nachfolgende untergeordnete RDD. Wenn ein übergeordnetes RDD in ein untergeordnetes RDD eintritt, z. B. den Kartenoperator, wird es zu einer engen Abhängigkeit. Wenn das RDD Eine oder mehrere RDDs können konvertiert und generiert werden, was als große Abhängigkeit bezeichnet wird, z. B. als GroupByKey-Operator

Bühne

Ein Job besteht aus einer oder mehreren Phasen. Jede Phase wird der Reihe nach ausgeführt. Die Aufteilung der Stufen basiert auf Shuffle-Abhängigkeiten.

Aufteilung der Stufen: Spark-Aufgaben bilden einen DAG-gesteuerten azyklischen Graphen basierend auf den Abhängigkeiten zwischen RDDs. Der DAG wird an DAGScheduler übermittelt. DAGScheduler unterteilt den DAG in mehrere Stufen, die voneinander abhängig sind. Die Grundlage für die Aufteilung der Stufen ist die Beziehung zwischen RDDs. Hängt von der Breite ab. Bei großen Abhängigkeiten werden die Phasen unterteilt und jede Phase enthält eine oder mehrere Aufgaben. Diese Aufgaben werden dann in Form von TasksSet zur Ausführung an TaskScheduler übermittelt.

Aufgabe

Die Stufe wird weiterhin in Aufgaben zerlegt. Die Anzahl der Aufgaben ist eigentlich die Parallelität der Stufe, die minimale Ausführungseinheit der Aufgabe. Eine Aufgabe wird letztendlich in Form einer Aufgabe auf dem Executor ausgeführt.

Zusammenfassung der Job-, Phasen- und Aufgabenbeziehungen

Der Job ist durch Aktionsmethoden begrenzt. Wenn eine Aktionsmethode auftritt, wird ein Job ausgelöst.

Stage ist eine Teilmenge von Job, die durch RDD-weite Abhängigkeiten (d. h. Shuffle) begrenzt ist und einmal geteilt wird, wenn Shuffle auftritt.

Die Aufgabe ist eine Teilmenge von Stage, gemessen am Grad der Parallelität (Anzahl der Partitionen). Die Anzahl der Partitionen entspricht der Anzahl der Aufgaben.

Arbeiter

Verwalten Sie den aktuellen Knotenspeicher und die CPU-Auslastung, empfangen Sie vom Master zugewiesene Ressourcenanweisungen und weisen Sie Aufgaben über das ExecutorRunner-Startprogramm zu. Der Worker ähnelt einem Auftragnehmer. Ein Worker-Prozess startet einen oder mehrere Executor-Threads, um eine Topologiekomponente auszuführen ( Auslauf oder Bolzen)

Testamentsvollstrecker

Die Ausführungseinheit der Spark-Aufgabe (Aufgabe) wird auf dem Worker ausgeführt. Tatsächlich handelt es sich um einen JVM-Prozess, eine Sammlung von Rechenressourcen (CPU-Kern, Speicher). Der Speicher und die CPU eines Workers werden von mehreren Executoren gemeinsam genutzt. Wenn die Spark-Anwendung startet, starten die Executoren gleichzeitig und folgen dem gesamten Lebenszyklus. Es gibt zwei Hauptkernfunktionen:
1. Verantwortlich für die Ausführung der Aufgaben, aus denen die Spark-Anwendung besteht, und die Rückgabe der Ergebnisse an den Treiberprozess;
2. Sie stellen In-Memory-Speicher für RDDs bereit, die über ihre eigenen Blockmanager in Benutzerprogrammen zwischengespeichert werden müssen (Blockmanager). RDD wird direkt im Executor-Prozess zwischengespeichert, sodass Aufgaben die zwischengespeicherten Daten vollständig nutzen können, um Vorgänge während der Laufzeit zu beschleunigen.

Partition

Bei der Spark-Datenpartitionierung wird den Partitionen jedes Knotens eine große Datenmenge zur Verarbeitung zugewiesen

Mischen

Ein Job ist in mehrere Phasen unterteilt. Wenn große Abhängigkeiten ausgelöst werden, tritt er in die Shuffle-Phase ein. Shuffle ist in die Map-Phase (rot) und die Reduzierungsphase (Schreiben) unterteilt.

Die Anzahl der Aufgaben auf der Kartenseite stimmt mit der Anzahl der Partitionen überein. Die Reduzierungsseite verwendet spark.default.parallelism als Standardkonfiguration. Wenn nicht, wird die Anzahl der letzten RDD-Partitionen als Anzahl der Aufgaben verwendet.

Shuffle ist in HashShuffle und SortShuffle unterteilt

HashShuffle führt einen Hash-Algorithmus für denselben Schlüssel aus und schreibt dabei denselben Schlüssel
in dieselbe Festplattendatei. Jede Festplattendatei gehört nur zu einer Aufgabe der nachgelagerten Stufe, wie viele Aufgaben gibt es in der nächsten Stufe und wie viele Aufgaben Gibt es in der aktuellen Phase? Wie viele Festplattendateien werden für jede Aufgabe erstellt?

Wenn Sie spark.shuffle.consolidateFiles auf „true“ setzen, kann die Optimierung aktiviert werden, und es wird eine „shuffleFileGroup“ angezeigt. Während der Ausführung verwendet jeder Stapel von Aufgaben die „shuffleFileGroup“ wieder, ohne neue Festplattendateien zu erstellen und die Anzahl der Festplattendateien zu reduzieren.

SortShuffe fügt im Vergleich zu HashShuffle eine Sortierverarbeitung hinzu. SortShuffe wird standardmäßig nach Spark 1.2 verwendet. Der Unterschied besteht darin, dass, wenn jede Aufgabe den Shuffle-Vorgang ausführt, zwar mehr temporäre Festplattendateien generiert werden, am Ende jedoch alle temporären Dateien zusammengeführt werden. ) in eine Festplattendatei, und es gibt eine entsprechende Indexdatei

Es gibt zwei Betriebsmodi: Der erste ist der Normalmodus und der zweite der Bypass-Modus (wird eingegeben, wenn die Anzahl der Leseaufgaben kleiner als der Wert des Parameters bypassMergeThreshold ist oder wenn es sich nicht um einen aggregierten Shuffle-Operator handelt).

Die Unterschiede im Bypass-Modus: 1. Der Schreibmechanismus der Festplatte ist unterschiedlich; 2. Es erfolgt keine Sortierung. Da keine Sortierung durchgeführt wird, kann dieser Teil des Leistungsaufwands eingespart werden.

Meister

Verwaltet Cluster und Knoten, beteiligt sich nicht an Berechnungen

Arbeiter

Als Rechenknoten nimmt der Prozess selbst nicht an der Berechnung teil, sondern berichtet an den Master

Verwalten Sie den aktuellen Knotenspeicher und die CPU-Auslastung, empfangen Sie vom Master zugewiesene Ressourcenanweisungen und weisen Sie Aufgaben über das Startprogramm ExecutorRunner zu. Es ähnelt einem Auftragnehmer, verwaltet und weist neue Prozesse zu und führt Berechnungsdienste aus.

Treiber

Die Hauptmethode zum Ausführen des Programms gehört zum Programmeingang. Seine Hauptfunktionen sind 1. Konvertieren des Benutzerprogramms in eine Aufgabe (Job); 2. Beantragen von Ressourcen aus dem Cluster; 3. Verantwortlich für die Planung und Analyse des Jobs ; 4. Generieren Sie die Phase und planen Sie die Aufgabe für den Ausführenden. Vorgesetzter

3.2 Verarbeitungsablauf von 20 Codezeilen

Der Verarbeitungsablauf lässt sich grob in drei Teile unterteilen: Der erste besteht darin, die Aufgabe zu übermitteln, der zweite darin, die entsprechenden Ressourcen zu finden und der zweite darin, die Aufgabe zu planen.

Es gibt viele Möglichkeiten, das Programm zu starten, und die Ausführungsmethode hängt vom Wert von „master“ ab, der beim Erstellen des sparkContext-Objekts übergeben wurde. Sie können die lokale Ausführungsmethode verwenden (im Allgemeinen können Sie diese beim Testen von Code verwenden).

lokal: lokal ausgeführt, ein Prozess, keine Parallelität; lokal[k]: k laufende Prozesse; lokal[*]: Die Anzahl der Prozesse entspricht der Anzahl der CPU-Kerne

Zusätzlich zum lokalen Start können Sie zum Starten auch den Clustermodus verwenden. Es gibt drei allgemeine Methoden, und die am häufigsten verwendete ist YARN.

Startmodus Merkmale Methode
Standalone-Standalone-Modus Nativer einfacher Cluster mit vollständigen Diensten Funke://
Apache Mesos Verteiltes Ressourcenmanagement-Framework mesos://
Hadoop-GARN Der einheitliche Ressourcenverwaltungsmechanismus läuft auf Garn [Anmerkung 1] und ist je nach Treiberstandort in Garn-Client und Garn-Cluster unterteilt. Garn-Client: Laufwerk wird lokal ausgeführt, Arbeit wird auf dem YRAN-Cluster ausgeführt. Verwenden Sie beim Bereitstellen den Client im Deploy-Modus. Garn-Cluster: Treiber und Arbeit befinden sich beide im Cluster. Verwenden Sie beim Bereitstellen den Cluster im Deploy-Modus

Hinweis 1: YARN, Hadoop-Ressourcenmanager, ist ein allgemeines Ressourcenverwaltungssystem, das eine einheitliche Ressourcenverwaltung und -planung für Anwendungen der oberen Schicht bereitstellen kann. Seine Einführung hat dem Cluster neue Vorteile in Bezug auf Auslastung, einheitliches Ressourcenmanagement und Datenaustausch gebracht . Riesige Vorteile.

In unserem obigen Code verwenden wir local, was lokal ist

val spark = new SparkContext("local","WordCount")

​ 1. Scannen Sie bei der Ausführung hier die abhängigen Dateien und JAR-Pakete, beginnen Sie mit der Generierung von SparkContext, initialisieren Sie die Treiberseite und bereiten Sie den Executor vor. Zuerst startet der Treiber und registriert die Anwendung beim Master. Der Master findet sie anhand der Ressourcenanforderungen des übermittelten Skripts. Interne Ressourcen können mindestens einen Executor aller Worker starten und dann Executors unter diesen Workern zuweisen. Nachdem der Executor auf dem Worker gestartet wurde, wird er umgekehrt beim Treiber registriert. Nachdem alle Executors registriert sind, Die Umgebung wird initialisiert und die Aufgabenausführung beginnt.

2. Der Treiber beginnt mit der Ausführung der Hauptfunktion und erstellt das DAG-Diagramm. Nach Abschluss der Erstellung wird das DAG-Diagramm an DAGScheduler übermittelt. DAGScheduler (DAG-Scheduler) beginnt mit der Aufteilung der Phasen und beginnt mit der Aufteilung der Phasen gemäß dem Aktionsoperator . Im obigen Code

.countByKey()

Die Methode gehört zum Aktionsoperator. Wenn diese Zeile ausgeführt wird, wird die obige Aufgabe in eine Stufe unterteilt. Die Stufen haben sequentielle Abhängigkeiten, und dann wird das TaskSet in der Stufe an den TaskScheduler gesendet.

3. TaskScheduler (Aufgabenplaner) erhält alle Aufgaben von TaskSet (Aufgabensatz). Die Aufteilung der Aufgaben erfolgt nach breiten und engen Abhängigkeiten, die aus den folgenden zwei Codezeilen bestehen.

.flatMap(_.split("~")) // 使用~切分每条记录
.map((_,1)) // java,1 html,1

Die oben genannten Operatoren haben alle eine 1:1-Beziehung zum übergeordneten RDD, sodass es sich bei allen um enge Abhängigkeiten handelt.

Große Abhängigkeiten gehören zu mehreren RDDs zur Integration und Aufteilung, und das Auslösen von Shuffle erfordert eine Netzwerkübertragung, die leicht Ressourcen verbraucht.

​ 4. Als nächstes senden Sie alle Aufgaben, Daten und laufenden Codes an den Executor. Der Executor stellt die Aufgaben zur Ausführung in den Thread-Pool und gibt die Ausführungsergebnisse an den TaskScheduler zurück. Der TaskScheduler gibt die Ergebnisse dann an den DAGScheduler zurück bis alle Aufgaben abgeschlossen sind. Geben Sie alle Ressourcen frei

おすすめ

転載: blog.csdn.net/lihao1107156171/article/details/126403591