Apprenez Spark en 20 jours (0) Premiers pas avec la version la plus simple de Spark

Spark est un moteur d'analyse Big Data rapide, polyvalent et évolutif écrit en Scala. L'analyse dite Big Data analyse et traite principalement de grandes quantités de données. Il s'agit d'une compétence essentielle pour les carrières actuelles en matière de développement Big Data.

1. Brève introduction

Ce qui suit est une brève introduction à Spark. Eh bien, il parle principalement de la qualité de Spark. Si vous ne voulez pas le voir, vous pouvez passer directement à la deuxième étape.

Caractéristiques

1) Rapide : par rapport à MapReduce de Hadoop, les opérations basées sur la mémoire de Spark sont plus de 100 fois plus rapides, et les opérations basées sur le disque dur sont également plus de 10 fois plus rapides. Spark implémente un moteur d'exécution DAG efficace qui peut traiter efficacement les flux de données basés sur la mémoire. Les résultats intermédiaires des calculs sont stockés en mémoire.

2) Facilité d'utilisation : Spark prend en charge les API Java, Python et Scala, ainsi que plus de 80 algorithmes avancés, permettant aux utilisateurs de créer rapidement différentes applications. De plus, Spark prend en charge les shells interactifs Python et Scala, et il est très pratique d'utiliser des clusters Spark dans ces shells pour vérifier les solutions aux problèmes.

3) Universel : Spark fournit une solution unifiée. Spark peut être utilisé pour le traitement par lots, les requêtes interactives (Spark SQL), le traitement de flux en temps réel (Spark Streaming), l'apprentissage automatique (Spark MLlib) et le calcul graphique (GraphX). Ces différents types de traitements peuvent tous être utilisés de manière transparente au sein d’une même application. La solution unifiée de Spark est très attractive : après tout, toute entreprise souhaite utiliser une plateforme unifiée pour résoudre les problèmes qu'elle rencontre, en réduisant les coûts de main d'œuvre de développement et de maintenance ainsi que les coûts matériels de déploiement de la plateforme.

4) Compatibilité : Spark peut être facilement intégré à d’autres produits open source. Par exemple, Spark peut utiliser YARN et Apache Mesos de Hadoop comme gestion des ressources et planificateur, et peut traiter toutes les données prises en charge par Hadoop, notamment HDFS, HBase et Cassandra. Ceci est particulièrement important pour les utilisateurs qui ont déjà déployé des clusters Hadoop, car ils peuvent utiliser les puissantes capacités de traitement de Spark sans effectuer de migration de données. Spark ne s'appuie pas non plus sur la gestion des ressources et les planificateurs tiers. Il implémente Standalone comme cadre intégré de gestion des ressources et de planification, ce qui abaisse encore le seuil d'utilisation de Spark et permet à tout le monde de déployer et d'utiliser Spark très facilement. De plus, Spark fournit également des outils pour déployer le cluster Spark de Standalone sur EC2.

2. Démarrer avec Spark en 20 lignes de code

Remarque : L'environnement actuel est idea + jdk8. Tous les codes de cet article sont basés sur la base de programmation Java précédente.

1. paquet de pot

Tout d'abord, créez un projet maven normal dans idea, accédez au fichier pom du projet et introduisez la dépendance maven. Si elle a été introduite, il n'est pas nécessaire de l'introduire.

<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. Créez un ensemble de données

Créez un dossier de données dans le répertoire du projet pour stocker les données, créez un fichier Word et saisissez le contenu suivant,

La tâche suivante consiste à utiliser les statistiques Spark pour analyser le nombre d'occurrences de chaque mot.

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

3. Créez le fichier WordCount.scala pour le calcul. Notez que le type de fichier est objet. L'ordre d'utilisation de Spark est à peu près le suivant

1. Créer un contexte Spark

2. Lisez le fichier de données

3. Traiter les données dans des formats appropriés

4. Calculs statistiques

5. Obtenez les résultats et enregistrez-les

Le code de traitement spécifique est le suivant

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)
  }

}

Enfin, le nombre d'occurrences de chaque mot est imprimé.

Il s'agit du cas d'utilisation de Spark le plus simple

3. Introduction au processus d'exécution du code

Le code ci-dessus est le code de cas Spark le plus basique.Le contenu suivant est une introduction au processus d'exécution du code ci-dessus.

3.1 Mots-clés courants

Avant d'apprendre Spark, nous trions d'abord une série de mots-clés couramment utilisés pour éviter que les étudiants ne comprennent pas l'article.

RDD

RDD (Resilient Distributed Dataset) est appelé un ensemble de données distribuées. Il s'agit de l'abstraction de données la plus élémentaire dans Spark. Il représente un ensemble immuable et partitionnable dont les éléments peuvent être calculés en parallèle. C'est un objet de base dans Spark.

défaut:

​Ne prend pas en charge les opérations d'écriture et de mise à jour à granularité fine (telles que les robots d'exploration Web).
Spark écrit les données de manière grossière. Ce que l'on appelle la granularité grossière signifie l'écriture de données par lots (écriture par lots).
Cependant, la lecture des données est à grain fin, ce qui signifie qu'il peut être écrit en une seule phrase.La lecture des bandes (lecture des bandes une par une)
ne prend pas en charge les calculs itératifs incrémentaux, mais Flink le prend en charge.

Graphique acyclique dirigé DAG

Dans un graphe orienté sans boucles, aucun sommet ne peut revenir au point par plusieurs arêtes, donc le graphe n'a pas de boucles.
Sentiment personnel : dans Spark, cela fait référence à la conversion mutuelle de divers RDD pour l'opération et le traitement, et finalement le résultat est obtenu.

Opérateur de transformation

La transformation de transformation fait référence à une série de méthodes de transformation RDD dans Spark. Il s'agit d'un chargement paresseux et ne sera pas exécuté immédiatement. Il ne sera exécuté que lorsqu'un opérateur d'action est rencontré.

opérateur d'action

Une méthode de traitement ou d’exécution de calculs

emploi

Tâche, lorsqu'un opérateur d'action est rencontré dans le programme, un travail sera soumis pour effectuer la série d'opérations précédente. Une tâche a plusieurs travaux et les travaux sont exécutés en série.

Dépendance à l'égard de la largeur et de l'étroitesse

Lorsque l'opérateur est en cours d'exécution, le RDD sera converti. Le RDD précédent est le RDD parent et le RDD enfant suivant. Lorsqu'un RDD parent entre dans un RDD enfant, tel que l'opérateur de carte, il devient une dépendance étroite. Si le RDD peut transmettre un ou plusieurs RDD qui sont convertis et générés, ce que l'on appelle une dépendance étendue, telle que l'opérateur groupByKey

scène

Un travail contient une ou plusieurs étapes. Chaque étape est exécutée dans l'ordre. La division des étapes est basée sur des dépendances aléatoires.

Division des étapes : les tâches Spark formeront un graphe acyclique dirigé par le DAG basé sur les dépendances entre les RDD. Le DAG sera soumis à DAGScheduler. DAGScheduler divisera le DAG en plusieurs étapes qui dépendent les unes des autres. La base de la division des étapes est la La relation entre les RDD dépend de la largeur. En cas de dépendances étendues, les étapes sont divisées et chaque étape contient une ou plusieurs tâches. Ces tâches sont ensuite soumises à TaskScheduler sous la forme de tâchesSet pour exécution.

Tâche

L'étape continue à être décomposée en tâches. Le nombre de tâches est en fait le parallélisme de l'étape, l'unité minimale d'exécution de la tâche. Une tâche est finalement exécutée sous la forme d'une tâche sur l'exécuteur.

Résumé des relations entre tâches, étapes et tâches

Le Job est limité par les méthodes Action. Lorsque vous rencontrez une méthode Action, un Job est déclenché ;

Stage est un sous-ensemble de Job, délimité par des dépendances à l'échelle de RDD (c'est-à-dire Shuffle), et est divisé une fois lorsque Shuffle est rencontré ;

La tâche est un sous-ensemble de Stage, mesuré par le degré de parallélisme (nombre de partitions). Le nombre de partitions est le même que le nombre de tâches.

ouvrier

Gérez la mémoire actuelle du nœud et l'utilisation du processeur, recevez les instructions de ressources allouées par le maître et allouez des tâches via le programme de démarrage ExecutorRunner. Le travailleur est similaire à un entrepreneur. Un processus de travail démarrera un ou plusieurs threads d'exécution pour exécuter un composant de topologie ( Bec ou Boulon)

Exécuteur

L'unité d'exécution de la tâche Spark (tâche) s'exécute sur le travailleur. En fait, il s'agit d'un processus JVM, un ensemble de ressources informatiques (cœur de processeur, mémoire). La mémoire et le processeur d'un travailleur sont partagés par plusieurs exécuteurs. Lorsque l'application Spark démarre, les exécuteurs démarrent en même temps et suivent tout le cycle de vie. Il existe deux fonctions principales :
1. Responsables de l'exécution des tâches qui composent l'application Spark et du renvoi des résultats au processus du pilote ;
2. Ils fournissent un stockage en mémoire pour les RDD qui nécessitent une mise en cache dans les programmes utilisateur via leurs propres gestionnaires de blocs. (Gestionnaire de blocs). RDD est mis en cache directement dans le processus Executor, afin que les tâches puissent utiliser pleinement les données mises en cache pour accélérer les opérations pendant l'exécution.

cloison

Partitionnement des données Spark, une grande quantité de données est allouée aux partitions de chaque nœud pour le traitement

mélanger

Un travail est divisé en plusieurs étapes. Lorsque de larges dépendances sont déclenchées, il entre dans l'étape de lecture aléatoire. La lecture aléatoire est divisée en une étape de mappage (rouge) et une étape de réduction (écriture).

Le nombre de tâches côté carte est cohérent avec le nombre de partitions. Le côté réduction utilise spark.default.parallelism comme configuration par défaut. Sinon, le nombre de dernières partitions RDD est utilisé comme nombre de tâches.

la lecture aléatoire est divisée en HashShuffle et SortShuffle

HashShuffle, exécute un algorithme de hachage sur la même clé, écrivant ainsi la même clé
dans le même fichier disque, et chaque fichier disque n'appartient qu'à une seule tâche de l'étape en aval, combien de tâches y a-t-il dans l'étape suivante et combien de tâches y en a-t-il à l'étape actuelle ? Combien de fichiers disque sont créés pour chaque tâche.

Définir spark.shuffle.consolidateFiles sur true peut permettre l'optimisation, et un shuffleFileGroup apparaîtra. Lors de l'exécution, chaque lot de tâches réutilisera le shuffleFileGroup, sans créer de nouveaux fichiers disque et sans réduire le nombre de fichiers disque.

SortShuffe ajoute un traitement de tri par rapport à HashShuffle. SortShuffe est utilisé par défaut après Spark 1.2. La différence est que lorsque chaque tâche effectue l'opération de lecture aléatoire, même si davantage de fichiers de disque temporaires seront générés, tous les fichiers temporaires seront finalement fusionnés. ) dans un fichier disque, et il existe un fichier d'index correspondant

Il existe deux modes de fonctionnement, le premier est le mode normal et le second est le mode bypass (entré lorsque le nombre de tâches de lecture est inférieur à la valeur du paramètre bypassMergeThreshold, ou lorsqu'il ne s'agit pas d'un opérateur de lecture aléatoire)

Les différences en mode contournement : 1. Le mécanisme d'écriture du disque est différent ; 2. Il ne trie pas. Puisqu’aucun tri n’est effectué, cette partie de la surcharge de performances peut être économisée.

maître

Gère les clusters et les nœuds, ne participe pas aux calculs

ouvrier

Nœud de calcul, le processus lui-même ne participe pas au calcul, et rend compte au maître

Gérez la mémoire actuelle du nœud et l'utilisation du processeur, recevez les instructions de ressources allouées par le maître et allouez les tâches via le programme de démarrage ExecutorRunner. Il est similaire à un entrepreneur, gère et alloue de nouveaux processus et exécute des services de calcul.

Conducteur

La principale méthode d'exécution du programme appartient à l'entrée du programme. Ses principales fonctions sont 1. Convertir le programme utilisateur en tâche (travail); 2. Demander des ressources du cluster; 3. Responsable de la planification et de l'analyse du travail. 4. Générer une étape et planifier la tâche à l'exécuteur.

3.2 Flux de traitement de 20 lignes de code

Le flux de traitement peut être grossièrement divisé en trois parties : la première consiste à soumettre la tâche, la seconde à trouver les ressources correspondantes et la seconde à planifier la tâche.

Il existe de nombreuses façons de démarrer le programme et la méthode d'exécution dépend de la valeur de master transmise lors de la création de l'objet sparkContext. Vous pouvez utiliser la méthode d'exécution locale (vous pouvez généralement l'utiliser lors du test du code),

local : exécuté localement, un processus, pas de parallélisme ; local[k] : k processus en cours d'exécution ; local[*] : le nombre de processus est égal au nombre de cœurs de processeur

En plus du démarrage local, vous pouvez également utiliser le mode cluster pour démarrer. Il existe trois méthodes générales, et la plus couramment utilisée est YARN.

Mode de démarrage Caractéristiques méthode
Mode autonome autonome Cluster simple natif avec services complets étincelle://
Apache Mesos Cadre de gestion des ressources distribuées mésos://
FIL Hadoop Fonctionnant sur Yarn [Note 1], le mécanisme de gestion unifié des ressources est divisé en client Yarn et en cluster Yarn en fonction de l'emplacement du pilote. client Yarn : Drive s'exécute localement, Work s'exécute sur le cluster YRAN, utilisez le client –deploy-mode lors du déploiement ; cluster Yarn : Driver et Work sont tous deux sur le cluster, utilisez le cluster –deploy-mode lors du déploiement

Remarque 1 : YARN, Hadoop Resource Manager, est un système général de gestion des ressources qui peut fournir une gestion et une planification unifiées des ressources pour les applications de couche supérieure. Son introduction a apporté de nouveaux avantages au cluster en termes d'utilisation, de gestion unifiée des ressources et de partage de données. Des avantages énormes.

Dans notre code ci-dessus, nous utilisons local, qui est local

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

​ 1. Lors de l'exécution ici, analysez les fichiers dépendants et les packages jar, commencez à générer SparkContext, initialisez le côté pilote et préparez l'exécuteur. Tout d'abord, le pilote démarre et enregistre l'application auprès du maître. Le maître la trouve en fonction de la ressource. exigences du script soumis. Les ressources internes peuvent démarrer au moins un exécuteur de tous les travailleurs, puis répartir les exécuteurs parmi ces travailleurs. Une fois l'exécuteur sur le travailleur démarré, il s'enregistrera de manière inversée auprès du pilote. Une fois tous les exécuteurs enregistrés, le L'environnement est initialisé et l'exécution de la tâche commence.

2. Le pilote commence à exécuter la fonction principale et construit le graphe DAG. Une fois la construction terminée, le graphe DAG est soumis à DAGScheduler. DAGScheduler (planificateur DAG) commence à diviser les étapes et commence à diviser les étapes en fonction de l'opérateur Action. . Dans le code ci-dessus

.countByKey()

La méthode appartient à l'opérateur Action. Lorsque cette ligne est exécutée, la tâche ci-dessus sera divisée en une étape. Les étapes ont des dépendances séquentielles, puis le TaskSet de l'étape sera envoyé au TaskScheduler.

3. TaskScheduler (planificateur de tâches) obtient toutes les tâches de TaskSet (ensemble de tâches).La division des tâches est traitée selon des dépendances larges et étroites, qui sont les deux lignes de code suivantes.

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

Les opérateurs ci-dessus ont tous une relation 1-1 avec le RDD parent, ils constituent donc tous des dépendances étroites.

De larges dépendances appartiennent à plusieurs RDD pour l'intégration et le fractionnement, et le déclenchement du shuffle implique une transmission réseau, qui consomme facilement des ressources.

4. Ensuite, toutes les tâches, données et codes en cours d'exécution sont envoyés à l'exécuteur. L'exécuteur place les tâches dans le pool de threads pour exécution et renvoie les résultats de l'exécution au TaskScheduler. Le TaskScheduler renvoie ensuite les résultats au DAGScheduler jusqu'à ce que toutes les tâches soient terminées. Libérer toutes les ressources

Je suppose que tu aimes

Origine blog.csdn.net/lihao1107156171/article/details/126403591
conseillé
Classement