4. 05/11/2019 Spark 4
propose un framework complet et unifié pour répondre aux besoins de
traitements Big Data pour divers jeux de données, divers par leur
nature (texte, graphe, etc.) aussi bien que par le type de source (batch
ou flux temps-réel).
permet à des applications sur clusters Hadoop d’être exécutées jusqu’à
100 fois plus vite en mémoire, 10 fois plus vite sur disque.
permet d’écrire rapidement des applications en Java, Scala ou Python
Introduction
5. 05/11/2019 Spark 5
Hadoop
technologie de traitement de données depuis 10 ans
la solution de choix pour le traitement de gros volumes de données.
MapReduce
Chaque étape d’un workflow de traitement étant constituée d’une phase
de Map et d’une phase de Reduce, il est nécessaire d’exprimer tous les cas
d’utilisation sous forme de patterns MapReduce pour tirer profit de cette
solution.
Les données en sortie de l’exécution de chaque étape doivent être stockées
sur système de fichier distribué avant que l’étape suivante commence.
Cette approche a tendance à être peu rapide à cause de la réplication et du
stockage sur disque.
Hadoop et Spark
6. 05/11/2019 Spark 6
Hadoop nécessite l’intégration de plusieurs outils pour les différents
cas d’utilisation big data (comme Mahout pour le Machine Learning et
Storm pour le traitement par flux).
Si on souhaite mettre en place quelque chose de plus complexe, on doit
enchaîner une série de jobs MapReduce et les exécuter
séquentiellement, chacun de ces jobs présentant une latence élevée et
aucun ne pouvant commencer avant que le précédent n’ait tout-à-fait
terminé.
Hadoop et Spark
7. 05/11/2019 Spark 7
Spark complete l’écosystème Hadoop
Remplace Mapreduce
Plus rapide qu’Hadoop : Tri de 100 To de données
Hadoop MR : 72 minutes avec 2100 nœuds (50400 cores)
Spark : 23 minutes avec 206 nœuds (6592 cores)
Spark peut être intégré avec :
Yarn, Zookeeper, Mesos
HDFS
Cassandra, Elasticsearch, MongoDB, hive
Zeppelin
Hadoop et Spark
9. 05/11/2019 Spark 9
Spark maintient les résultats intermédiaires en mémoire plutôt que sur
disque, ce qui est très utile en particulier lorsqu’il est nécessaire de
travailler à plusieurs reprises sur le même jeu de données. Le moteur
d’exécution est conçu pour travailler aussi bien en mémoire que sur
disque.
Les opérateurs réalisent des opérations externes lorsque la donnée ne
tient pas en mémoire, ce qui permet de traiter des jeux de données plus
volumineux que la mémoire agrégée d’un cluster.
Spark essaye de stocker le plus possible en mémoire avant de basculer
sur disque. Il est capable de travailler avec une partie des données en
mémoire, une autre sur disque.
Les fonctionnalités de Spark
10. 05/11/2019 Spark 10
Les autres fonctionnalités proposées par Spark comprennent :
Des fonctions autres que Map et Reduce
L’évaluation paresseuse des requêtes, ce qui aide à optimiser le workflow
global de traitement
Des APIs concises et cohérentes en Scala, Java et Python
Spark est écrit en Scala et s’exécute sur la machine virtuelle Java (JVM).
Les langages supportés actuellement pour le développement
d’applications sont :
Scala
Java
Python
R
Les fonctionnalités de Spark
11. 05/11/2019 Spark 11
Spark Streaming : traitement temps-réel des données en flux. Il
s’appuie sur un mode de traitement en "micro batch" et utilise pour les
données temps-réel DStream, c’est-à-dire une série de RDD
Spark SQL : permet d’extraire, transformer et charger des données
sous différents formats (JSON, Parquet, base de données)
Spark MLlib : MLlib est une librairie de machine learning qui contient
tous les algorithmes et utilitaires d’apprentissage classiques, comme la
classification, la régression, le clustering …
Spark GraphX : la nouvelle API (en version alpha) pour le traitement et
parallélisation de graphes. GraphX inclut une collection toujours plus
importante d’algorithmes et de builders pour simplifier les tâches
d’analyse de graphes.
L’écosystème Spark
15. 05/11/2019 Spark 15
Apache Spark à une architecture master/slave avec deux demons et un
cluster manager :
Master Daemon – (Master/Driver Process)
Worker Daemon –(Slave Process)
Un cluster spark à un seul Master et un nombre indéterminé de
slaves/Workers.
Architecture
16. 05/11/2019 Spark 16
Le driver est responsable de l’exécution de la fonction main() de
l’application et de créer le SparkContext.
Spark Driver contient plusieurs composants ( DAGScheduler,
TaskScheduler, BackendScheduler, BlockManage) qui sont
responsables de la traduction du code spark en job (ensemble de taches
appelés tasks) qui sera exécute dans le cluster.
Le driver planifie l’exécution des job et négocie les ressources avec le
cluster manager.
Le Driver enregistre les métadatas des RDD et leurs partitions.
Spark Driver
17. 05/11/2019 Spark 17
Un service externe responsable de l’allocation des ressources aux job
lancés par le drivers.
Trois types : Standalone, Mesos et YARN.
Ces types sont diffèrent en terme de scheduling, sécurité, monitoring
Cluster Manager
18. 05/11/2019 Spark 18
L’executor est un agent distribué responsable de l’exécution des taches.
Chaque application spark a son propre process executor.
L’Executors fonctionne tout au long de l’exécution de l’application. On
parle de “Allocation statique des Executors”.
On peut aussi opter pour une allocation dynamique des executors pour
équilibrer les charges de traitement
L’executor lit et écrit les données a partir des sources externes.
L’Executor stocke les résultats des calculs en mémoire, cache ou sur le
disque.
Executor
19. 05/11/2019 Spark 19
Le worker, est un nœud qui permet d’exécuter un programme dans le
cluster. Si un process est lance pour une application, l’application
requiert des executors dans les nœuds workers
Dés que le SparkContext se connecte au cluster manager, il acquière un
executors dans les worker nodes
L’executors travaille indépendamment dans chaque tache et peuvent
interagirent ensemble.
Worker node
20. 05/11/2019 Spark 20
SparkContext permet d’établir une connexion avec le cluster manager.
Peut être utilisé pour créer les RDD et les accumulateurs, et diffuse les
variables dans le cluster.
Il est recommandé d’avoir un seul SparkContext active par JVM, donc on
doit appeler la méthode stop() du SparkContext active avant de créer un
autre.
SparkContext
21. 05/11/2019 Spark 21
Quand un client valide un code spark, le driver traduit le code qui
contient des actions et des transformations en un graphe acyclique
direct logique (DAG).
A cette étape, le driver optimise l’ordre de déroulement des
transformations et convertit le DAG logique en plan d’exécution
physique avec un ensemble d’étapes
Le driver crée des petites unités physique d’exécution (les tasks) pour
chaque étape.
Le driver négocie les ressources avec le cluster manager
Le cluster manager lance les executors dans les nœuds workers au nom
du driver.
A ce moments, le driver envoi les taches au cluster manager en ce
basant sur l’emplacement des données.
Exécution d’un job spark(1)
22. 05/11/2019 Spark 22
Avant l’exécution des taches, ils s’enregistrent avec le driver pour qu’il
puissant les surveiller.
Le Driver planifie aussi les future taches en se basant sur leurs
emplacement en mémoire.
Quand la méthode main du programme driver se termine ou si on
lance la méthode stop () du Spark Context, le driver terminera tout les
executors et libère les ressources du cluster manager.
Exécution d’un job spark(2)
24. 05/11/2019 Spark 24
Spark est puissant car il repose sur des principes peu nombreux et
simples.
Données : RDD (Resilient Distributed Datasets)
Resilient : tolérance aux pannes grâce au DAG. Possibilité de recalcul des
données endommagées
Distributed : données réparties sur plusieurs nœuds worker d’un cluster.
RDD : Principe
26. 05/11/2019 Spark 26
L’objet principal de Spark est le RDD : Resilient Distributed Dataset.
Un dispositif pour traiter une collection de données par des
algorithmes parallèles robustes.
Un RDD ne contient pas vraiment de données, mais seulement un
traitement. Ce traitement n’est effectué que lorsque cela apparaît
nécessaire. On appelle cela l’évaluation paresseuse.
Variables partagées entre des traitements et distribuées sur le cluster de
machines.
Spark fait en sorte que le traitement soit distribué sur le cluster, donc
calculé rapidement, et n’échoue pas même si des machines tombent en
panne.
RDD : Resilient Distributed Dataset
27. 05/11/2019 Spark 27
RDD utilise des opérations mapreduce qui permettent de traiter et de
générer un large volume de données avec un algorithme parallèle et
distribuée.
On peut charger les données a partir de n’importe quelle source et la
convertir en RDD et les stocker en mémoire pour calculer les résultats.
RDD est composé d’un ensemble de partitions. Une partition est une
division logique de données qui est immuable et créée suite a des
transformations d’autre partition existante.
En cas de perte de partition RDD, on peut reprendre les
transformations sur le RDD d’origine au lieu de répliquer les données
sur plusieurs nœuds.
Caractéristique d’un RDD
28. 05/11/2019 Spark 28
Transformations : Comme avec MapReduce, chaque ligne du fichier
constitue un enregistrement. Les transformations appliquées sur le
RDD traiteront chaque ligne séparément. Les lignes du fichier sont
distribuées sur différentes machines pour un traitement parallèle.
Elles créent un nouveau RDD à partir d’un existant.
Actions : ce sont des fonctions qui permettent d’extraire des
informations des RDD, par exemple les afficher sur l’écran ou les
enregistrer dans un fichier.
RDD : Calcul
29. 05/11/2019 Spark 29
Ce sont des méthodes qui s’appliquent à un RDD pour retourner une
valeur ou une collection.
RDD.collect() retourne le contenu du RDD
RDD.count() retourne le nombre d’éléments
RDD.first() retourne le premier élément
RDD.take(n) retourne les n premiers éléments.
RDD.reduce(fonction) Agréger les éléments du RDD en utilisant la fonction
définie (qui prend 2 arguments et retourne 1 résultat). La fonction devrait
être associative et commutative afin de pouvoir être correctement calculée
en parallèle.
longueursLignes.reduce((a, b) => a + b)
RDD.persist() ou RDD.cache() Sauvegarder le RDD en mémoire avant
l’execution (action)
Actions
30. 05/11/2019 Spark 30
Un RDD peut être sauvegardé :
sous forme de fichier texte avec saveAsTextFile(path)
sous forme de SequenceFile Hadoop avec saveAsSequenceFile(path),
dans un format simple en utilisant la sérialisation Java avec
saveAsObjectFile(path).
Actions
31. 05/11/2019 Spark 31
Chacune de ces méthodes retourne un nouveau RDD à partir de celui
qui est concerné.
RDD.map(fonction) chaque appel à la fonction doit retourner une valeur qui
est mise dans le RDD sortant.
val longueursLignes = texteLicence.map(l => l.length)
RDD.flatMap(fonction) chaque item du RDD source peut être transformé en
0 ou plusieurs items ; retourner une séquence plutôt qu’un seul item.
parallelize() partitionner le RDD automatiquement à partir des
caractéristiques du cluster sur lequel les calculs doivent être réalisés.
val RDD = sc.parallelize(Array(1,2,3,4))
RDD.filter(fonction) la fonction retourne un booléen.
linesfilter = texteLicence.filter(line => line.contains("Komal"))
Transformations
32. 05/11/2019 Spark 32
Ces transformations regroupent deux RDD
RDD.distinct() : retourne un seul exemplaire de chaque élément.
RDD = sc.parallelize(Array(1, 2, 3, 4, 6, 5, 4, 3))
RDD.distinct().collect()
RDD1.union(RDD2) : contrairement à son nom, ça retourne la
concaténation et non pas l’union des deux RDD.
Rajouter distinct() pour faire une vraie union.
RDD1 = sc.parallelize(Array(1,2,3,4))
RDD2 = sc.parallelize(Array(6,5,4,3))
RDD1.union(RDD2).collect()
RDD1.intersection(RDD2) : retourne l’intersection des deux RDD.
RDD1.intersection(RDD2).collect()
Transformations ensemblistes
33. 05/11/2019 Spark 33
Spark permet de calculer des jointures entre RDD1={(K1,V1). . . } et
RDD2={(K2,V2). . . } et partageant des clés K identiques.
RDD1.join(RDD2) : retourne toutes les paires (K, (V1, V2)) lorsque V1 et V2
ont la même clé.
RDD1 = sc.parallelize(Array((1,"tintin"),(2,"asterix"),(3,"spirou") ))
RDD2 = sc.parallelize(Array((1,1930),(2,1961),(1,1931),(4,1974) ))
print RDD1.join(RDD2).collect()
Transformations de type jointure
35. 05/11/2019 Spark 35
SparkSQL rajoute une couche simili-SQL au dessus des RDD. Ça
s’appuie sur deux concepts :
DataFrames : des tables SparkSQL : des données sous forme de colonnes
nommées. On peut les construire à partir de fichiers JSON, de RDD ou de
tables Hive.
RDDSchema : la définition de la structure d’un DataFrame. C’est la liste
des colonnes et de leurs types. Un RDDSchema peut être défini à l’aide
d’un fichier JSON.
Il y a des liens entre DataFrame et RDD. Les RDD ne sont que des
données, des n-uplets bruts.
Les DataFrames sont accompagnées d’un schéma.
SparkSQL
36. 05/11/2019 Spark 36
L’API SparkSQL est très complète. Elle comprend plusieurs classes
ayant chacune de nombreuses méthodes :
DataFrame représente une table de données relationnelles
Column représente une colonne d’un DataFrame
Row représente l’un des n-uplets d’un DataFrame
Ces classes permettent d’écrire une requête SQL autrement qu’en SQL,
à l’aide d’appels de méthodes enchaînés.
API SparkSQL
37. 05/11/2019 Spark 37
sqlContext représente le contexte SparkSQL.
Spark SQL fournit SQLContext afin d’encapsuler les fonctions du
monde relationnel dans Spark.
C’est un objet qui possède plusieurs méthodes dont celles qui créent
des DataFrames et celles qui permettent de lancer des requêtes SQL.
Elles retournent un DataFrame contenant les données.
A savoir qu’un DataFrame ainsi créé ne connaît pas les types des
colonnes, seulement leurs noms.
sqlContext
38. 05/11/2019 Spark 38
C’est la classe principale. Elle définit des méthodes à appliquer aux
tables.
Un DataFrame est une collection de données distribuées, organisées en
colonnes nommées.
Ce concept est similaire à une table dans le monde des bases de
données relationnelles.
Les DataFrames peuvent être converties en RDD
Les DataFrames peuvent être créées à partir de différentes sources de
données :
Des RDD existants
Des fichiers de données structurées
Des jeux de données JSON
Des tables HIVE
Des bases de données externes
Classe DataFrame
39. 05/11/2019 Spark 39
Offre une amélioration des performance des RDD grâce a deux
caractéristiques :
Gestion de mémoire personnalisée
Les données sont stockées en mémoire off-heap. Pas de garbage collector.
En connaissant le schéma des données a l’avance et le stockage sous
format binaire on n’aura plus de serialization java couteuse.
Plan d’exécution optimisé
Caractéristique d’un Dataframe
40. 05/11/2019 Spark 40
df = sqlContext.read.json("path") lecture fichier json
Show() : afficher le contenu du fichier
df.printSchema() description schéma du dataframe
df.select(champ) afficher un champ bien déterminé
df.filter(condition) retourne un nouveau DataFrame qui ne contient
que les n-uplets qui satisfont la condition.
resultat = achats.filter($"montant" > 30.0)
Méthodes de DataFrame
41. 05/11/2019 Spark 41
count() retourne le nombre de n-uplets du DataFrame concerné.
distinct() retourne un nouveau DataFrame ne contenant que les n-
uplets distincts
limit(n) retourne un nouveau DataFrame ne contenant que les n
premiers n-uplets
join(autre, condition, type) fait une jointure entre self et autre sur la
condition.
Méthodes de DataFrame
42. 05/11/2019 Spark 42
groupBy(colonnes) regroupe les n-uplets qui ont la même valeur pour
les colonnes qui sont désignées par une chaîne SQL.
Cette méthode retourne un objet appelé GroupedData sur lequel on
peut appliquer les méthodes suivantes :
count() : nombre d’éléments par groupe
avg(colonnes) : moyenne des colonnes par groupe
max(colonnes), min(colonnes) : max et min des colonnes par groupe
sum(colonnes) : addition des colonnes par groupe
tapc = achats.groupBy("idclient").sum("montant")
napc = achats.groupBy("idclient").count()
Agrégation
43. 05/11/2019 Spark 43
sort(colonnes) classe les n-uplets de dataframe selon les colonnes, dans
l’ordre croissant.
Pour classer dans l’ordre décroissant, il faut employer la fonction
sort(desc(colonnes))
Classement
44. 05/11/2019 Spark 44
La fonction %sql dans une SparkSession permet aux applications
d’exécuter une requête SQL et de retourner un DataFrame comme
résultat.
df. registerTempTable(“emp")
val sqlDF = sqlContext.sql("SELECT * FROM people")
sqlDF.show()
%sql
SELECT * FROM emp
Exécution de requêtes SQL
46. 05/11/2019 Spark 46
Système traditionnel de traitement des streaming :
Le flot de données est reçu a partir de différents sources et est envoyé a
un système d’ingestion de données (kafka, kinesis..)
Les données seront traitées en parallèle dans le cluster
Les résultats seront stockés dans une BDNR, hdfs …
Les nœuds worker exécutent des operateurs continues. Chaque operateur
traite un enregistrement à la fois puis l’envoi a un autre operateur de le
pipeline.
Streaming traditionnel
47. 05/11/2019 Spark 47
Inconvénients :
La récupération automatique en cas d’erreur n’ai pas possible a cause de
l’allocation statique des operateurs aux nœuds worker.
Le load balancing entre les nœuds worker peut causer un goulets
d'étranglement nous avons besoin d’une gestion de ressource dynamique
entre les workers.
Combinaison de streaming, traitement batch et traitement interactive
impossible
Analytics avec machine learning et requêtes SQL impossible
Streaming traditionnel
48. 05/11/2019 Spark 48
Au lieu de traiter le flot de données un enregistrement a la fois, spark
découpe les données en micro batch
Spark streaming reçoit les données en parallèle et les charge en
mémoire des workers. Spark exécute des petits taches pour traiter les
micro batch et envoyer le résultat aux autres systèmes.
Contrairement aux systèmes traditionnels, les taches sont réparties
d’une manière dynamique sur les nœuds worker en se basant sur
l’emplacement des données et les ressources nécessaires. Ce qui permet
une meilleure gestion des reprise après un problème d’exécution
Avantage spark streaming
50. 05/11/2019 Spark 50
Discretized Streams : Abstraction de spark streaming, représente un
flux continu de données en entrée.
Séquence continu de RDDs
Initialisé avec une Durée
DStream
52. 05/11/2019 Spark 52
Operations de transformation
Similaire aux RDD
map(), flatMap(), filter(), repartition(numPartitions), union(otherStream),
count(), reduce(), countByValue(), reduceByKey(func, [numTasks]),
join(otherStream, [numTasks]), cogroup(otherStream, [numTasks]),
transform(), updateStateByKey(), Window()
Operations de sortie (Output Operations)
Les données Dstream sont envoyées à un système externe comme une bd
ou un système de fichier en utilisant les opérations de sortie.
print(), saveAsTextFiles(prefix, [suffix]), saveAsObjectFiles(prefix, [suffix]),
saveAsHadoopFiles(prefix, [suffix]), foreachRDD(func)
Operations
53. 05/11/2019 Spark 53
Fenêtre glissante
Réutilise des données d'autres fenêtres
Initialisé avec window length et slide interval
Window operations
54. 05/11/2019 Spark 54
Consiste à définir une variable qui sera mise à jour par l'ensemble des
nœuds du cluster lors de l'exécution de l'action. Cette variable pourra
ensuite être lue sur le driver.
Un accumulateur ne doit jamais être mis à jour dans le cadre d'une
transformation. Spark étant susceptible de rexécuter les
transformations en cas de panne, cela résulterait à une double mise à
jour de la valeur de l'accumulateur.
Ne peuvent être ajoutés que par
des opérations associatives
Peuvent être utilisés pour
implémenter des conteurs ou des
sommes.
Accumulateurs
55. 05/11/2019 Spark 55
Au lieu d’avoir autant de copie des valeurs dans les workers par celle-
ci, il est possible d’utiliser la fonction de broadcast() pour partager en
lecture-seule cette valeur et ainsi n’avoir qu’une copie par nœud géré
par le système.
Cette fonction n’est intéressante que pour partagé de grosses sources
de données à travers les workers
Broadcast Variables
56. 05/11/2019 Spark 56
Bien que l’état initial peut toujours être utilisé pour recalculer les RDDs
suite à un échec, cela peut être couteux surtout si la chaine est longue.
Ainsi, il peut être utile de disposer d’un checkpoint des RDD sur
disque.
En général, les checkpoints sont utiles pour des RDDs qui disposent
d’un graphe contenant des dépendances larges.
Checkpoints
58. 05/11/2019 Spark 58
Proposent des API spécialisées pour simplifier la programmation sur
des graphes.
Nouvelles techniques de partitionnement du graphe, restriction des
types d'opérations qui peuvent être utilisées.
Exploitent la structure graphe pour obtenir des gains en performance
comparative a celles du systèmes de données parallèles (data parallel)
Inconvénient : difficile d’appliquer les différentes étapes d’un pipeline
de traitement sur des graphes (construire/modifier le graphe, calculs
sur plusieurs graphes)
Système graphe parallèle
59. 05/11/2019 Spark 59
Les mêmes données peuvent avoir différentes vues table ou vues
graphes (souvent utile de balancer entre les deux vues)
Les graphes sont au centre de
l’analyse du web
61. 05/11/2019 Spark 61
Les utilisateurs doivent apprendre, déployer et gérer de multiples
systèmes ce qui conduit à des interfaces compliquées à implémenter et
souvent complexes a utiliser et particulièrement inefficace.
D’importants déplacements de données et de duplication à travers le
réseau et le système de fichiers
Réutilisation limité de structures de données internes d’une étape à
l’autre
Difficultés
62. 05/11/2019 Spark 62
Nouvelle API : Attenue la distinction entre les tables et les graphes
Nouveau système qui combine les données parallèles et les graphes
parallèles
Permet aux utilisateurs :
D’exprimer facilement et efficacement le pipeline entier de l’analyse des
graphes
De voir les données à la fois comme collections (RDD) et comme graphe
sans déplacement/duplication
Solution : l’approche unifiée GraphX
66. 05/11/2019 Spark 66
Un multigraphe signifie qu’il peut y avoir plusieurs arêtes partageant
la même source et destination
Chaque sommet a une clé unique VertexId
Chaque arête a l’ID du sommet source et destination
Programmer avec GraphX
67. 05/11/2019 Spark 67
Comme les RDD, les graphes sont :
Non modifiable
Distribués
Résistants aux pannes
VertexRDD
Représente un ensemble de nœuds,
Chaque vertexID doit être unique,
Les attributs des nœuds sont stockées dans un hashmap: permet de faire
les jointure en temps constants entre deux vertexRDD
EdgeRDD
Les arêtes sont organisés en blocs, partitionnées selon une stratégies
(canonicalRandomVertexCut, EdgePArttionID..)
Les attributs sont stockés séparément de la structure d’adjacence afin de
pouvoir les changer facilement
Gestion des graphes
69. 05/11/2019 Spark 69
Reverse : retourne un nouveau graphe en inversant la direction des
arêtes
Subgraph : prend des prédicats sur les sommets et les arêtes et retourne
le graphe contenant les sommets satisfaisants les prédicats et reliés par
les arêtes satisfaisant les prédicats
Mask: retourne un sous-graphe correspondant a l’intersection d’un
graphe donné et d’un graphe masque
groupEdges : pour un multi graphe fusionne les différents arêtes entre
deux sommets en une seule
Operateurs sur structure
70. 05/11/2019 Spark 70
Souvent il est nécessaire de joindre des données de RDD externe avec
des graphe (ajouter d ’autre propriétés a un graphe existant ou copier
des propriétés d’un graphe a un autre)
joinVertices : joint les sommets avec le RDD en entrée et retourne un
nouveau graphe avec les propriétés obtenues en appliquant la fonction
map aux sommets joignant
Operateurs de jointure
73. 05/11/2019 Spark 73
MLlib est une librairie de machine learning qui contient tous les
algorithmes d’apprentissage classiques
Traite la classification, la régression, le clustering, le filtrage
collaboratif, la réduction de dimensions…
Developé par MLbase team dans le laboratoire AMPLab
Plus de 80 contributions par divers organisations
Supporter par Scala, Python, and Java APIs
Librairie MLlib