SlideShare une entreprise Scribd logo
1  sur  186
#DevoxxFR
Comprendre et

Maitriser la performance

de vos applications Spark
Raphaël Luta - @raphaelluta
1
#DevoxxFR
« Vas-y fonce ! 

On sait jamais sur un malentendu,
ça peut marcher »
2
#DevoxxFR 3
#DevoxxFR 3
#DevoxxFR 4
Tuning
#DevoxxFR 4
Measure
Tuning
#DevoxxFR 4
Measure
Model
Tuning
#DevoxxFR 4
Measure
ModelHypothesis
Tuning
#DevoxxFR 4
Measure
ModelHypothesis
Adjustment
Tuning
#DevoxxFR
Spark
5
#DevoxxFR
Spark
5
Python
Moteur
Calcul
Distribué
ScalaJava R
#DevoxxFR
Spark
5
SQL
Dataset
MLLib

SparkML
GraphX Streaming
Python
Moteur
Calcul
Distribué
ScalaJava R
#DevoxxFR
Spark
5
SQL
Dataset
MLLib

SparkML
GraphX Streaming
Standalone YARN Mesos Kubernetes
Python
Moteur
Calcul
Distribué
ScalaJava R
#DevoxxFR
Dataframe
Dataset
RDD
Mon profil Spark
6
Raphaël Luta

DataDevSecOps

Freelance
0 %
25 %
50 %
75 %
100 %
Batch Streaming ML GraphX
0 %
25 %
50 %
75 %
100 %
2012 2013 2014 2015 2016 2017 2018 2019
Spark Pig/Hive Autre
Scala
SQL
Python
Java
R
YARN
Standalone
Mesos
Kubernetes
#DevoxxFR
Programme
7
#DevoxxFR
Programme
7
API
#DevoxxFR
Programme
7
API
Modèle
Exécution
#DevoxxFR
Programme
7
API
Modèle
Exécution
Monitoring
#DevoxxFR
Programme
7
API
Modèle
Exécution
Catalyst
Monitoring
#DevoxxFR
Programme
7
API
Modèle
Exécution
Catalyst
Monitoring
Formats
Compression
Parallélisme
Mémoire
S3
UDF ???
#DevoxxFR 8
#DevoxxFR
Programme
9
API
Modèle
Exécution
Catalyst
Monitoring
#DevoxxFR
RDD
Dataframe
Dataset
10
#DevoxxFR
RDD API
11
RDD[T] <=> Seq[T]
#DevoxxFR
Transformations vs Actions
12
RDD[T] => RDD[U]
map

flatMap

filter

union
distinct

groupByKey

reduceByKey

join
…
RDD[T] => _


collect

take

count

foreach

reduce

fold

saveAsTextFile
…

Narrow
Wide
#DevoxxFR
Exemple
sc.textFile("wikipedia")
.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
.saveAsTextFile("wordcount")
13
#DevoxxFR
DATAFRAME API
14
Dataframe <=> Seq[Map[String,Any]]
#DevoxxFR
Exemple
import spark.implicits._
import org.apache.spark.sql.functions._
spark.read.parquet("wikipedia")
.select(explode(split(‘content)) as "word")
.groupBy("word")

.count
.save.parquet("wordcount")
15
#DevoxxFR
DATASET API
16
Dataset[T] <=> Seq[T]
#DevoxxFR
DATASET API
16
Dataset[T] <=> Seq[T]
type Dataframe = Dataset[Row]
#DevoxxFR
Exemple
case class WikiArticle(content: String)
spark.read.parquet("wikipedia")
.as[WikiArticle]
.flatMap(_.content.split(" "))

.groupByKey(_)

.count
.save.parquet("wordcount")
17
#DevoxxFR 18
#DevoxxFR
Programme
19
API
Modèle
Exécution
Catalyst
Monitoring
#DevoxxFR 20 20
#DevoxxFR 20 20
Driver
#DevoxxFR 20 20
Executor
Driver
#DevoxxFR 20 20
Executor
Driver
Task
#DevoxxFR 20 20
Executor
Driver
Task
Stage
#DevoxxFR 20 20
Executor
Driver
Task
Stage
Input
#DevoxxFR 20 20
Executor
Driver
Task
Stage
Stage
Input
#DevoxxFR 20 20
Executor
Driver
Task
Stage
Stage
Shuffle
Input
#DevoxxFR 20 20
Executor
Driver
Task
Stage
Stage
Shuffle
Input
Output
Job
#DevoxxFR
C'est quoi un job
• 1 Action => 1 Job
• Par défaut, 1 seul stage par Job
• 1 transformation "wide" => 1 nouveau stage
21
#DevoxxFR
Exemple découpage
sc.textFile("wikipedia")
.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
.saveAsTextFile("wordcount")
22
#DevoxxFR
JOB1
Exemple découpage
sc.textFile("wikipedia")
.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
.saveAsTextFile("wordcount")
22
#DevoxxFR
JOB1
Exemple découpage
sc.textFile("wikipedia")
.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
.saveAsTextFile("wordcount")
22
STAGE1STAGE2
#DevoxxFR
Rôles du driver
• Gérer le cycle de vie des exécuteurs
• Gérer la répartition des données
• Effectuer le découpage job, stage, task
• Générer et affecter des tâches aux exécuteurs
23
#DevoxxFR
Rôles de l’exécuteur
• Executer les tâches demandées par le driver
• Maintenir un cache de bloc de données
• Gérer l’envoi et la reception des blocs de shuffle
24
#DevoxxFR
Modèles d’execution
• Local
• YARN
• Standalone
• Mesos
• Kubernetes
25
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
mypackage.jar
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
mypackage.jar
spark-defaults.conf
core-site.xml
hdfs-site.xml
yarn-site.xml
...
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
mypackage.jar
spark-defaults.conf
core-site.xml
hdfs-site.xml
yarn-site.xml
...
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
mypackage.jar
spark-defaults.conf
core-site.xml
hdfs-site.xml
yarn-site.xml
...
driver
application
master
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
mypackage.jar
spark-defaults.conf
core-site.xml
hdfs-site.xml
yarn-site.xml
...
driver
application
master
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
mypackage.jar
spark-defaults.conf
core-site.xml
hdfs-site.xml
yarn-site.xml
...
Executor 1
Executor 2
driver
application
master
#DevoxxFR
Spark-submit en action (YARN)
26
spark
submit
YARN RM
Node
Node
spark-submit
--master yarn
--deploy-mode client
--num-executors 2
--executor-cores 4
--executor-memory 8G
--class MyClass
mypackage.jar
mypackage.jar
spark-defaults.conf
core-site.xml
hdfs-site.xml
yarn-site.xml
...
Executor 1
Executor 2
driver
application
master
#DevoxxFR
spark-submit
• Créer la configuration de l’application Spark adaptée
au cluster choisi
• Déploie les ressources vers le cluster
• Lance le driver sur la machine locale (client mode)
ou demande l’execution au cluster manager (cluster
mode)
27
#DevoxxFR
Tips: spark-submit sans jar local
28
#DevoxxFR
Tips: spark-submit sans jar local
spark-submit

--master yarn

--deploy-mode cluster

--packages my.fab:spark-job:1.2.2

--class my.fab.JobClass

dummy
28
#DevoxxFR
Tips: spark-submit sans jar local
spark-submit

--master yarn

--deploy-mode cluster

--packages my.fab:spark-job:1.2.2

--class my.fab.JobClass

dummy
...

151 WARN [main] DependencyUtils: Local

jar /Users/raphael/dummy does not exist,

skipping.

...
28
#DevoxxFR 29
#DevoxxFR
Programme
30
API
Modèle
Exécution
Catalyst
Tungsten
Monitoring
#DevoxxFR
Logging
Event History
Metrics
31
#DevoxxFR
Logging
Event History
Metrics
32
#DevoxxFR
Logging
• Log4j ¯_(ツ)_/¯
• Local à chaque machine, puis
consolidé sur HDFS ou S3 par YARN
• En mode client, le log driver n’est
pas consolidé !
33
#DevoxxFR
Logging Tips
• Modifier le template log4j.properties pour ajouter:
• le nom du thread courant
• un timestamp à la milliseconde
Exemple
%d{ISO8601} %p [%t] %c{1}: %m%n
34
#DevoxxFR
Logging
Event History
Metrics
35
#DevoxxFR
Spark Driver
Spark History
36
Schedul
er
Executor

1
Executor

2
Executor

3
#DevoxxFR
Spark Driver
Web UI
Spark History
36
Schedul
er
Executor

1
Executor

2
Executor

3
#DevoxxFR
EventLog
Listener
Storage
Event
Log
hdfs://spark-history/application_125321332_1Spark Driver
Web UI
Spark History
36
Schedul
er
Executor

1
Executor

2
Executor

3
#DevoxxFR
EventLog
Listener
Storage
Event
Log
hdfs://spark-history/application_125321332_1Spark Driver
Web UI
Spark History
36
Schedul
er
Executor

1
Executor

2
Executor

3
Spark
History
Server
#DevoxxFR
Infos dans Event Log
37
Configuration
Quantité de données échangées
Performance détaillée (wall-time et cpu-time) par Task
Plans d’execution
Métriques et accumulators
...
#DevoxxFR
Web UI ❤
38
#DevoxxFR
Définir son SparkListener
class DemoSparkListener extends SparkListener {
override def onStageCompleted(event: SparkListenerStageCompleted) {
val info = event.stageInfo
if (info.completionTime.isDefined) {
val duration = info.completionTime.get - info.submissionTime.get
println(s"Stage ${info.name} succeeded: ${duration} ms")
} else {
println(s"Stage ${info.name} failed: ${info.failureReason.get}")
}
}
}
39
https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.scheduler.SparkListener
#DevoxxFR
Ajouter un Listener
Configuration:
spark.extraListeners
Code:
val demoListener = new DemoSparkListener()
sparkContext.addSparkListener(demoListener)
... do work ...
sparkContext.removeSparkListener(demoListener)
40
#DevoxxFR
Quelques Listeners utiles
41
Sparklint 

https://github.com/groupon/sparklint
Sparklens 

https://github.com/qubole/sparklens
SparkMeasure 

https://github.com/LucaCanali/sparkMeasure
#DevoxxFR
Sparklint
42
#DevoxxFR
Sparklens
43
#DevoxxFR
Logging
Event History
Metrics
44
#DevoxxFR
Metrics & Monitoring
45
Sources
Jvm
Scheduler
HiveSQL
Streaming
...
Sinks Standard
REST API

JMX

CSV

Graphite

Statsd
Ganglia
Sinks Communauté
Prometheus
Elasticsearch
OpenTSDB
InfluxDB
...
#DevoxxFR
Exemple configuration: metrics.properties
driver.source.jvm.class=org.apache.spark.metrics.source.JvmSource

executor.source.jvm.class=org.apache.spark.metrics.source.JvmSource
*.sink.jmx.class=org.apache.spark.metrics.sink.JmxSink
*.sink.elk.class=org.apache.spark.elk.metrics.sink.ElasticsearchSink
*.sink.elk.host=localhost
*.sink.elk.port=9200
*.sink.elk.index=spark
*.sink.elk.period=30
*.sink.elk.unit=seconds

46
#DevoxxFR
Metrics JVM
47
#DevoxxFR
Metrics streaming
48
#DevoxxFR
Metrics streaming
49
#DevoxxFR 50
#DevoxxFR
Programme
51
API
Modèle
Exécution
Catalyst
Monitoring
#DevoxxFR
C'est quoi ?
52
Catalyst:
Moteur d'optimisation des plans d'exécution des requêtes
Dataset & SQL
Tungsten:
Ensemble d'optimisation techniques notamment pour
réduire la pression mémoire et augmenter l'efficacité CPU
#DevoxxFR
Itinéraire d'une requête SQL
53
Dataset
SQL
Parsed
Plan
Analyzed
Plan
Optimized

Plan
Physical

Plan
Task
RDD
DRIVER EXECUTOR
#DevoxxFR
La requête initiale
54
SQL
select nature, count(*) from rna group by nature
Dataset
rna.groupBy('nature).count.show
#DevoxxFR
Parsed Plan
GlobalLimit 21
+- LocalLimit 21
+- Project [cast(nature#19 as string) AS
nature#7284, cast(count#7276L as string) AS count#7285]
+- Aggregate [nature#19], [nature#19, count(1) AS
count#7276L]
+-
Relation[id#10,id_ex#11,siret#12,rup_mi#13,gestion#14,d
ate_creat#15,date_decla#16,date_publi#17,date_disso#18,
nature#19,groupement#20,titre#21,titre_court#22,objet#2
3,objet_social1#24,objet_social2#25,adrs_complement#26,
adrs_numvoie#27,adrs_repetition#28,adrs_typevoie#29,adr
s_libvoie#30,adrs_distrib#31,adrs_codeinsee#32,adrs_cod
epostal#33,... 15 more fields] csv
55
#DevoxxFR
Parsed -> Analyzed
56
Relation [...fields...] csv
Aggregate [nature] [nature, count(1)]
Project [nature, count]
LocalLimit 21
GlobalLimit 21
#DevoxxFR
Parsed -> Analyzed
56
Relation [...fields...] csv id, siret, rup_mi, gestion, nature, ...
Aggregate [nature] [nature, count(1)]
Project [nature, count]
LocalLimit 21
GlobalLimit 21
#DevoxxFR
Parsed -> Analyzed
56
Relation [...fields...] csv id, siret, rup_mi, gestion, nature, ...
nature: String, count: LongAggregate [nature] [nature, count(1)]
Project [nature, count]
LocalLimit 21
GlobalLimit 21
#DevoxxFR
Parsed -> Analyzed
56
Relation [...fields...] csv id, siret, rup_mi, gestion, nature, ...
nature: String, count: Long
nature: String, count: String
Aggregate [nature] [nature, count(1)]
Project [nature, count]
LocalLimit 21
GlobalLimit 21
#DevoxxFR
Parsed -> Analyzed
56
Relation [...fields...] csv id, siret, rup_mi, gestion, nature, ...
nature: String, count: Long
nature: String, count: String
nature: String, count: String
Aggregate [nature] [nature, count(1)]
Project [nature, count]
LocalLimit 21
GlobalLimit 21
#DevoxxFR
Parsed -> Analyzed
56
Relation [...fields...] csv id, siret, rup_mi, gestion, nature, ...
nature: String, count: Long
nature: String, count: String
nature: String, count: String
nature: String, count: String
Aggregate [nature] [nature, count(1)]
Project [nature, count]
LocalLimit 21
GlobalLimit 21
#DevoxxFR
Optimiseur Heuristique
57
Applique des règles heuristiques de transformation du graphe de
dépendance pour accélérer les traitements :
- PartitionPruning
- PredicatePushdown
- ProjectionPushdown
...
+ les règles de l'algèbre relationnel
#DevoxxFR
Partition Pruning
58
rna
year=2018
part-0001
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001
#DevoxxFR
Partition Pruning
58
rna
year=2018
part-0001
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001
select nature, count(*) from rna where year=2018 group by nature
#DevoxxFR
Partition Pruning
58
rna
year=2018
part-0001
select nature, count(*) from rna where year=2018 group by nature
#DevoxxFR
Pushdown Predicate
59
rna
year=2018
part-0001
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001
#DevoxxFR
Pushdown Predicate
59
rna
year=2018
part-0001
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001
select nature, count(*) from rna where type='D' group by nature
#DevoxxFR
Pushdown Predicate
59
rna
year=2018
part-0001
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001
select nature, count(*) from rna where type='D' group by nature
part-0001part-0001 part-0001part-0001part-0001part-0001part-0001part-0001
#DevoxxFR
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001part-0001
Projection Pushdown
60
rna
year=2018
#DevoxxFR
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001part-0001
Projection Pushdown
60
rna
year=2018
select nature, count(*) from rna group by nature
#DevoxxFR
year=2016 year=2017 year=2019
part-0001 part-0001 part-0001part-0001 part-0001part-0001part-0001part-0001 part-0001part-0001part-0001part-0001
Projection Pushdown
60
rna
year=2018
select nature, count(*) from rna group by nature
#DevoxxFR
Optimized Plan
GlobalLimit 21
+- LocalLimit 21
+- Aggregate [nature#19], [nature#19,
cast(count(1) as string) AS count#7285]
+- Project [nature#19]
+-
Relation[id#10,id_ex#11,siret#12,rup_mi#13,gestion#1
4,date_creat#15,date_decla#16,date_publi#17,date_dis
so#18,nature#19,groupement#20,titre#21,titre_court#2
2,objet#23,objet_social1#24,objet_social2#25,adrs_co
mplement#26,adrs_numvoie#27,adrs_repetition#28,adrs_
typevoie#29,adrs_libvoie#30,adrs_distrib#31,adrs_cod
einsee#32,adrs_codepostal#33,... 15 more fields] csv
61
#DevoxxFR
Physical Plan
CollectLimit 21
+- *(2) HashAggregate(keys=[nature#19],
functions=[count(1)], output=[nature#19,
count#7285])
+- Exchange hashpartitioning(nature#19, 200)
+- *(1) HashAggregate(keys=[nature#19],
functions=[partial_count(1)], output=[nature#19,
count#7280L])
+- *(1) FileScan csv [nature#19] Batched:
false, Format: CSV, Location:
InMemoryFileIndex[file:/Users/raphael/tmp/
rna_waldec_20190301.csv], PartitionFilters: [],
PushedFilters: [], ReadSchema: struct<nature:string>
62
#DevoxxFR
Obtenir les plans
63
Web UI:
Onglet SQL -> Détails
SQL:
EXPLAIN [EXTENDED] <QUERY>
Dataset:
rna.explain(true)
#DevoxxFR
Optimiseur par coût
64
Permet d'utiliser les statistiques des sources de données
pour sélectionner le meilleur plan physique parmi tous les
plans possibles.
Principal impact sur les opérations "join"
Optimized

Plan
Physical

Plan Physical

Plan
Physical

Plan
Physical

Plan
Physical

Plan
Physical

Plan
Physical

Plan
Physical

Plan
Physical

Plan
#DevoxxFR
Optimiser par cout
65
Désactivé par défaut
spark.sql.cbo.enabled=true
spark.sql.cbo.joinReorder.enabled=true
Ne fonctionne que sur tables
Nécessite un calcul préalable des statistiques
ANALYZE TABLE mutable COMPUTE STATISTICS
ANALYZE TABLE mutable COMPUTE STATISTICS FOR COLUMNS col1, col2
#DevoxxFR
Dernière étape... codegen !
• Maximise l'efficacité de la structure
InternalRow utilisée pour stocker les
données en mémoire
• Evite le dispatch de méthodes
mégamorphiques
66
#DevoxxFR
Génération de code
67
FileScan
HashAggregate
Exchange
HashAggregate
Limit
Exchange
Code
source
Task
compilée
WholeStage 1
Janino
expressions
codegen
Code
source
Task
compilée
WholeStage 2
#DevoxxFR
Voir le code...
68
Dataset
df.queryExecution.debug.codegen
SQL
EXPLAIN CODEGEN <QUERY>
#DevoxxFR
RDD vs Dataset
69
RDD[MyClass] Dataset[Row] Dataset[MyClass]
Analyse Compilation Runtime Runtime
Optimisation Manuelle
Heuristique

CBO
Heuristique

CBO
Mémoire Objets Java/Scala InternalRow
InternalRow

Objets Java/Scala
Tasks operator initial Inlined codegen Inlined codegen
#DevoxxFR 70
#DevoxxFR
Programme
71
API
Modèle
Exécution
Catalyst
Monitoring
Formats
Parallélisme
Gestion mémoire
AWS
Joins & Skew
Sizing Exécuteurs
???
#DevoxxFR
Histoire de parallélisme
72
#DevoxxFR
Principes
• Nombre de Tasks d'un Stage est égal au nombre de
partitions RDD en fin de stage
• Donc 3 cas possibles:
• Input
• Shuffle
• Output
73
#DevoxxFR
Parallélisme d'Input
74
1 partition par split ou par fichier
Petites partitions concaténées pour être entre:
spark.sql.files.openCostInBytes (4M par défaut)
spark.sql.files.maxSplitBytes (128M par défaut)
#DevoxxFR
Shuffle
75
Un seul paramètre
spark.sql.shuffle.partitions (200 par défaut)
"Bientôt" un support de shuffle adaptatif:
SPARK-9850
#DevoxxFR
Output
76
Nombre de fichiers écrits:
• Partitions RDD (i.e nombre de Tasks)
• Partitionnement de la table
• Bucketing
#DevoxxFR
Exemple
77
200 Partitions sur le dernier stage
1 colonne de partition avec 20 valeurs
=> jusqu'à 200 * 20 fichiers résultats**
**multiplié par nombre de buckets si activé !
#DevoxxFR
Maîtriser le nombre de fichiers
78
Utiliser repartition pour regrouper les données en des groupes ayant
un sens
df.repartition('dpt)

.write

.partitionBy("dpt")

.parquet("my_dataset")
1 seul fichier de sortie par partition sur disque
#DevoxxFR
Comment paramétrer le
driver et les exécuteurs ?
79
#DevoxxFR
2 problèmes à résoudre
80
Déterminer le pool de ressource
optimal CPU/Mem pour l’application
Maximiser l’efficacité du découpage
entre exécutors
#DevoxxFR
Allocation pool
81
Multi-tenant:
Limité par répartition ressources cluster et queueing policy
YARN
Mono-tenant:
Limité par parallélisme des données et des stages
Allocation dynamique permet de simplifier cette gestion au
prix d’une latence de job un peu plus élevée
#DevoxxFR
Allocation dynamique
spark.dynamicAllocation.enabled = true
spark.dynamicAllocation.minExecutors = 5

spark.dynamicAllocation.initialExecutors = 10

spark.dynamicAllocation.maxExecutors = 100
spark.dynamicAllocation.executorIdleTimeout = 30s

spark.dynamicAllocation.cachedExecutorIdleTimeout = 1800s
spark.dynamicAllocation.executorAllocationRatio = 1
spark.dynamicAllocation.schedulerBacklogTimeout = 1s

spark.dynamicAllocation.sustainedSchedulerBacklogTimeout = 1s
spark.shuffle.service.enabled=true
82
#DevoxxFR
Sizing executeurs
83
Moins d’exécuteurs:
- maximise les opportunités de partage de données intra-process
- augmente les temps de full-GC
- (HDFS) peut créer de la contention d’I/O
Plus d’exécuteurs:
- plus de shuffle
- plus simple à allouer par le cluster manager
#DevoxxFR
Heuristique
84
Maximum 6 cores par exécuteur
Affecter la taille mémoire pour maximiser l’utilisation du
noeud. 2 à 4G/core est une bonne base
Laisser des ressources à l'OS
Prendre en compte le YARN memoryOverhead (10% heap par
défaut)
Pour valider, mesurez les différences de performance
entre configurations !
#DevoxxFR
Exemple de sizing
85
m5.12xlarge - 48 cores - 192 GB RAM
1 core pour OS, ~5 à 10% RAM pour OS/Cache disque

-> YARN peut allouer au plus 47 cores et 180 G RAM
On prend 5 cores / executor -> 9 executors soit 20 GB total/
executor

Yarn memoryOverhead = 10 à 15% donc on fixe heap a 18G
—num-executors 9 —executor-cores 5 —executor-memory
18G
#DevoxxFR
Optimiser les joins et le
skew ?
86
#DevoxxFR
2 types principaux types
de join
87
#DevoxxFR
2 types principaux types
de join
87
SortMergeJoin
Data 1 Data 2
Sort[key] Sort[key]
Merge
Data 3
#DevoxxFR
2 types principaux types
de join
87
SortMergeJoin
Data 1 Data 2
Sort[key] Sort[key]
Merge
Data 3
HashJoin
Data 1 Data 2
Hash[key]
Merge
Data 3
#DevoxxFR
Cas d'utilisation
88
SortMergeJoin est le join par défaut mais coûteux dans le cas
général
1 shuffle + 2 sorts
Si Spark détecte qu'un des 2 datasets est "petit", il va utiliser
un BroadcastHashJoin à la place
Si Spark sait que les 2 datasets sont déjà partitionnés de
manière équivalentes (bucket), il va éviter le shuffle
#DevoxxFR
Bucketing
89
Activé uniquement pour les tables (donc via metastore), "pre
shuffle persistant" d'un dataset.
df.repartition(30,'year,'key)

.write

.partitionBy("year")

.bucketBy(30,"key")

.sortBy("key")

.saveAsTable("my_table")
Bucketing accélère group by, join et windowing sur les
colonnes concernées
#DevoxxFR
Skew et ré-équilibrage de charge
90
3 stratégies pour gérer le skew (déséquilibre de données):
- ajouter un sel pour mieux répartir les clés et agréger en 2
étapes
- avoir 2 traitements différents pour la clé dominante et le
reste (typiquement NULL handling)
- accepter le skew si le delta de temps n'est pas trop
important
#DevoxxFR
Sel + Merge
91
#DevoxxFR
Sel + Merge
val df = df1.groupBy(‘id).agg(sum(‘value))
91
#DevoxxFR
Sel + Merge
val df = df1.groupBy(‘id).agg(sum(‘value))
df1.withColumn("salt", (rand()*4) cast "int")

.groupBy(‘id, ’salt).agg(sum(‘value) as "value")

.groupBy(‘id).agg(sum(‘value))
91
#DevoxxFR
Sel + Merge
val df = df1.groupBy(‘id).agg(sum(‘value))
df1.withColumn("salt", (rand()*4) cast "int")

.groupBy(‘id, ’salt).agg(sum(‘value) as "value")

.groupBy(‘id).agg(sum(‘value))
df1.withColumn("salt", when(‘id isNull, (rand()*50)
cast "int").otherwise(1))

.groupBy(‘id, ’salt).agg(sum(‘value) as "value")

.groupBy(‘id).agg(sum(‘value))
91
#DevoxxFR
Gestion Mémoire et OOM
92
#DevoxxFR
Modèle mémoire Exécuteur
93
JVM Native
Reserved - 300M
User Memory
Execution
Storage
Mem
JVM Heap
Memory

Offheap
spark.executor.memory
spark.executor.memoryOverhead spark.memory.fraction
Unified Memory
Total Heap
spark.memory.storageFraction
Storage
Storage + Execution
Unifiedmemory
#DevoxxFR
Spilling
94
Spilling: Quand la zone execution + storage est trop petite
pour tout accueillir, une partie de la mémoire est copiée sur
disque et libérée
Partie exécution n'est jamais spilled, toujours storage
Si le storage est non vide, il ne peut pas être spilled en dessous
du spark.memory.storageFraction
Spark a besoin de maxPartitionSize * executor-cores en
unified memory pour l'execution de toutes les tasks en
parallèle
#DevoxxFR
Gérer la pression sur la Heap
• Regarder les métriques !
• Ajuster le spark.memory.fraction
• Adapter le GC (plutôt G1GC ou ParallelGC)
• Réduire l'utilisation des UDF et opérations Dataset
• Diminuer le poids des structures de données
95
#DevoxxFR
Le cas du memoryOverhead
96
WARN TaskSetManager: Lost task 49.2 in stage
6.0 (TID xxx, xxx.xxx.xxx.compute.internal):
ExecutorLostFailure (executor 16 exited caused by
one of the running tasks) Reason: Container killed
by YARN for exceeding memory limits. 10.4 GB of
10.4 GB physical memory used. Consider boosting
spark.yarn.executor.memoryOverhead.
#DevoxxFR
Le cas du memoryOverhead
97
- JVM Natives pools (Metaspace, Compiler,
Threads stacks, DirectBuffers(nio), etc...)
- Python process (or R)
- Mémoire de libs JNI (xgboost, lightgbm, ...)
#DevoxxFR
Gérer le memoryOverhead
98
#DevoxxFR
Gérer le memoryOverhead
98
Limiter les DirectBuffers

spark.executor.extraJavaOptions=-XX:MaxDirectMemorySize=XXXM

ou

spark.shuffle.io.preferDirectBufs=false
#DevoxxFR
Gérer le memoryOverhead
98
Limiter les DirectBuffers

spark.executor.extraJavaOptions=-XX:MaxDirectMemorySize=XXXM

ou

spark.shuffle.io.preferDirectBufs=false
Limiter et déclarer la RAM pour le process Python

spark.executor.pyspark.memory=XXXM
#DevoxxFR
Gérer le memoryOverhead
98
Limiter les DirectBuffers

spark.executor.extraJavaOptions=-XX:MaxDirectMemorySize=XXXM

ou

spark.shuffle.io.preferDirectBufs=false
Limiter et déclarer la RAM pour le process Python

spark.executor.pyspark.memory=XXXM
Augmenter le memory overhead

spark.executor.memoryOverhead=15% heap
#DevoxxFR
Gérer le memoryOverhead
98
Limiter les DirectBuffers

spark.executor.extraJavaOptions=-XX:MaxDirectMemorySize=XXXM

ou

spark.shuffle.io.preferDirectBufs=false
Limiter et déclarer la RAM pour le process Python

spark.executor.pyspark.memory=XXXM
Augmenter le memory overhead

spark.executor.memoryOverhead=15% heap
#DevoxxFR
Quel format utiliser pour
stocker les données ?
99
#DevoxxFR
Le bon format: un compromis
100
#DevoxxFR
Le bon format: un compromis
100
Expressivité
#DevoxxFR
Le bon format: un compromis
100
Expressivité
Evolutivité
#DevoxxFR
Le bon format: un compromis
100
Expressivité
Evolutivité
Compatibilité
#DevoxxFR
Le bon format: un compromis
100
Expressivité
Evolutivité
Compatibilité




Performance
#DevoxxFR
Le bon format: un compromis
100
Expressivité
Evolutivité
Compatibilité




Performance
Efficacité

#DevoxxFR
Les familles
101
Formats texte Formats binaires
#DevoxxFR
Les familles
101
CSV

- universel

- compact

- pas de schema

- parsing
compliqué

Formats texte Formats binaires
#DevoxxFR
Les familles
101
CSV

- universel

- compact

- pas de schema

- parsing
compliqué

JSON

- inefficace

- schema limité
Formats texte Formats binaires
#DevoxxFR
Les familles
101
CSV

- universel

- compact

- pas de schema

- parsing
compliqué

JSON

- inefficace

- schema limité
XML

- inefficace

- OOM
Formats texte Formats binaires
#DevoxxFR
Les familles
101
CSV

- universel

- compact

- pas de schema

- parsing
compliqué

JSON

- inefficace

- schema limité
XML

- inefficace

- OOM
Parquet

- stockage colonne

- optimisé Spark

- écosystème riche

- schéma évolutif
Formats texte Formats binaires
#DevoxxFR
Les familles
101
CSV

- universel

- compact

- pas de schema

- parsing
compliqué

JSON

- inefficace

- schema limité
XML

- inefficace

- OOM
Parquet

- stockage colonne

- optimisé Spark

- écosystème riche

- schéma évolutif
ORC

- stockage colonne

- optimisé Hive

- indexes

- ACID
Formats texte Formats binaires
#DevoxxFR
Les familles
101
CSV

- universel

- compact

- pas de schema

- parsing
compliqué

JSON

- inefficace

- schema limité
XML

- inefficace

- OOM
Parquet

- stockage colonne

- optimisé Spark

- écosystème riche

- schéma évolutif
ORC

- stockage colonne

- optimisé Hive

- indexes

- ACID
Avro

- stockage record

- très utilisé Kafka

- schéma riche

- RPC
Formats texte Formats binaires
#DevoxxFR
Les compressions
102
Taux

Compression
Débit 

Compression
Débit

Décompression
GZIP ☆☆☆☆ ☆ ☆☆
SNAPPY ☆☆ ☆☆☆☆ ☆☆☆☆
BZIP2 ☆☆☆☆☆ ☆ ☆
LZ4 ☆ ☆☆☆☆☆ ☆☆☆☆☆
ZSTD ☆☆☆ ☆☆☆ ☆☆☆
Un fichier entièrement compressé est non-splittable sauf BZIP2
#DevoxxFR
Compression dans Spark
103
Spark peut lires les fichiers compressés directement mais ne
supporte pas .zip ou .7z
En interne, Spark utilise LZ4 par défaut pour la compression
des shuffles, spills et broadcast.
Pour améliorer les taux de compression:
spark.io.compression.lz4.blockSize=128k ou 256k
#DevoxxFR
Recommandations
104
Parquet+snappy en priorité pour Spark
Privilégiez les formats avec schéma pour la maintenance et
l'évolutivité
Evitez JSON et XML
Attention aux livraisons de gros fichiers compressés !
#DevoxxFR
Spécificités cloud
105
#DevoxxFR
Types d'instances
106
Les instances m.*, c.* ou r.* suffisent dans
la plupart des cas
Surveiller les IO et bande passante réseau
Des SSDs locaux sont utiles pour la
performance
#DevoxxFR
Stockage S3
107
Accès aux méta-données est très long
Pas d'opérations de move native
EMRFS peut introduire des bottlenecks
supplémentaires (chiffrement, cohérence via
dynamoDB)
#DevoxxFR
A suivre de près
108
http://iceberg.incubator.apache.org
#DevoxxFR
En résumé
109
#DevoxxFR 110
Measure
ModelHypothesis
Adjustment
Tuning
#DevoxxFR
Modèle d'exécution
111
#DevoxxFR
Logging
Event History
Metrics
112
#DevoxxFR
Catalyst
113
Dataset
SQL
Parsed
Plan
Analyzed
Plan
Optimized

Plan
Physical

Plan
Task
RDD
Physical

Plan
Physical

Plan
Physical

Plan
Physical

Plan
Physical

Plan
Meta-données
Règles heuristiques
Statistiques
Codegen
Catalog
#DevoxxFR
RDD vs Dataset
114
RDD[MyClass] Dataset[Row] Dataset[MyClass]
Analyse Compilation Runtime Runtime
Optimisation Manuelle
Heuristique

CBO
Heuristique

CBO
Mémoire Objets Java/Scala InternalRow
InternalRow

Objets Java/Scala
Tasks code initial Inlined codegen Inlined codegen
#DevoxxFR
Bonnes pratiques
• Privilégiez les formats type Parquet ou ORC
• Utilisez un Metastore
• Privilégiez des exécuteurs multi-core
115
#DevoxxFR
Bonnes pratiques de code
• Pas de traitement sur le driver
• Pensez utilisation ultérieure du dataset
(partition by, sort by, bucket by)
• Surveiller le nombre de fichiers d'output
• Maximiser le parallélisme des traitements
116
#DevoxxFR
Les limites
• Shuffle est la limite principale de montée en
charge et difficulté de paramétrage
• Efficacité du cache Spark est limitée
• Cost-based Optimizer pas encore universel
117
#DevoxxFR
Pour optimiser Spark, il faut
comprendre vos données 

et son modèle d'exécution
118
#DevoxxFR 119
Merci
@raphaelluta
raphael.luta at aptiwan.com
Crédits Photos
Pascal Mauerhofer
Monica Leonardi
Samuel Scrimshaw
Pascal van de Vendel
Premkumar Masilamani
Maria E. Mayobre

Contenu connexe

Similaire à Comprendre et maîtriser la performance de ses applications Spark

XebiCon'16 : WeScale - DNS as a Service, the OpenStack way. Par Pascal Edoua...
XebiCon'16 : WeScale - DNS as a Service, the OpenStack way.  Par Pascal Edoua...XebiCon'16 : WeScale - DNS as a Service, the OpenStack way.  Par Pascal Edoua...
XebiCon'16 : WeScale - DNS as a Service, the OpenStack way. Par Pascal Edoua...Publicis Sapient Engineering
 
Event sourcing avec Kafka, UPEC
Event sourcing avec Kafka, UPECEvent sourcing avec Kafka, UPEC
Event sourcing avec Kafka, UPECSylia Baraka
 
Realtime Web avec Kafka, Spark et Mesos
Realtime Web avec Kafka, Spark et MesosRealtime Web avec Kafka, Spark et Mesos
Realtime Web avec Kafka, Spark et Mesosebiznext
 
Spark RDD : Transformations & Actions
Spark RDD : Transformations & ActionsSpark RDD : Transformations & Actions
Spark RDD : Transformations & ActionsMICHRAFY MUSTAFA
 
Spark Summit Europe Wrap Up and TASM State of the Community
Spark Summit Europe Wrap Up and TASM State of the CommunitySpark Summit Europe Wrap Up and TASM State of the Community
Spark Summit Europe Wrap Up and TASM State of the CommunityJean-Georges Perrin
 
Lagom framework - Touraine Tech 2018
Lagom framework - Touraine Tech 2018Lagom framework - Touraine Tech 2018
Lagom framework - Touraine Tech 2018Fabrice Sznajderman
 
[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beam
[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beam[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beam
[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beamAlexandre Touret
 
Présentation_Spark.pptx
Présentation_Spark.pptxPrésentation_Spark.pptx
Présentation_Spark.pptxboulonvert
 
[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beam
[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beam[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beam
[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beamAlexandre Touret
 
Spark - An In-Memory Distributed Computing Engine.pptx
Spark - An In-Memory Distributed Computing Engine.pptxSpark - An In-Memory Distributed Computing Engine.pptx
Spark - An In-Memory Distributed Computing Engine.pptxAnass Nabil
 
Université EventSourcing CQRS Devoxx fr 2017
Université EventSourcing CQRS Devoxx fr 2017Université EventSourcing CQRS Devoxx fr 2017
Université EventSourcing CQRS Devoxx fr 2017Emilien Pecoul
 
Methodologie et outils d optimisation php mysql
Methodologie et outils d optimisation php mysqlMethodologie et outils d optimisation php mysql
Methodologie et outils d optimisation php mysqlCodizy
 
De Java à Kotlin - L'histoire d'une migration
De Java à Kotlin - L'histoire d'une migrationDe Java à Kotlin - L'histoire d'une migration
De Java à Kotlin - L'histoire d'une migrationRobin Penea
 
XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services Par Al...
XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services  Par Al...XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services  Par Al...
XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services Par Al...Publicis Sapient Engineering
 
XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...
XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...
XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...Publicis Sapient Engineering
 
2013 01-08-php-maturite
2013 01-08-php-maturite2013 01-08-php-maturite
2013 01-08-php-maturiteRémi Alvado
 
Infrastructure - Monitoring - Cacti
Infrastructure - Monitoring - CactiInfrastructure - Monitoring - Cacti
Infrastructure - Monitoring - CactiFrédéric FAURE
 
Apache solr andré bois-crettez 08
Apache solr   andré bois-crettez 08Apache solr   andré bois-crettez 08
Apache solr andré bois-crettez 08Loïc Descotte
 

Similaire à Comprendre et maîtriser la performance de ses applications Spark (20)

XebiCon'16 : WeScale - DNS as a Service, the OpenStack way. Par Pascal Edoua...
XebiCon'16 : WeScale - DNS as a Service, the OpenStack way.  Par Pascal Edoua...XebiCon'16 : WeScale - DNS as a Service, the OpenStack way.  Par Pascal Edoua...
XebiCon'16 : WeScale - DNS as a Service, the OpenStack way. Par Pascal Edoua...
 
Event sourcing avec Kafka, UPEC
Event sourcing avec Kafka, UPECEvent sourcing avec Kafka, UPEC
Event sourcing avec Kafka, UPEC
 
Realtime Web avec Kafka, Spark et Mesos
Realtime Web avec Kafka, Spark et MesosRealtime Web avec Kafka, Spark et Mesos
Realtime Web avec Kafka, Spark et Mesos
 
Spark RDD : Transformations & Actions
Spark RDD : Transformations & ActionsSpark RDD : Transformations & Actions
Spark RDD : Transformations & Actions
 
Spark Summit Europe Wrap Up and TASM State of the Community
Spark Summit Europe Wrap Up and TASM State of the CommunitySpark Summit Europe Wrap Up and TASM State of the Community
Spark Summit Europe Wrap Up and TASM State of the Community
 
Introduction spark
Introduction sparkIntroduction spark
Introduction spark
 
Lagom framework - Touraine Tech 2018
Lagom framework - Touraine Tech 2018Lagom framework - Touraine Tech 2018
Lagom framework - Touraine Tech 2018
 
[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beam
[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beam[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beam
[orleans-tech-19] Unifiez vos traitements Batch et Streaming avec Apache beam
 
Présentation_Spark.pptx
Présentation_Spark.pptxPrésentation_Spark.pptx
Présentation_Spark.pptx
 
[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beam
[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beam[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beam
[tours-jug19] Unifiez vos traitements Batch et Streaming avec Apache beam
 
Spark - An In-Memory Distributed Computing Engine.pptx
Spark - An In-Memory Distributed Computing Engine.pptxSpark - An In-Memory Distributed Computing Engine.pptx
Spark - An In-Memory Distributed Computing Engine.pptx
 
Université EventSourcing CQRS Devoxx fr 2017
Université EventSourcing CQRS Devoxx fr 2017Université EventSourcing CQRS Devoxx fr 2017
Université EventSourcing CQRS Devoxx fr 2017
 
Methodologie et outils d optimisation php mysql
Methodologie et outils d optimisation php mysqlMethodologie et outils d optimisation php mysql
Methodologie et outils d optimisation php mysql
 
De Java à Kotlin - L'histoire d'une migration
De Java à Kotlin - L'histoire d'une migrationDe Java à Kotlin - L'histoire d'une migration
De Java à Kotlin - L'histoire d'une migration
 
XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services Par Al...
XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services  Par Al...XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services  Par Al...
XebiCon'16 : Choisissez votre style avec Docker & Amazon Web Services Par Al...
 
XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...
XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...
XebiCon'16 : A la découverte de Nomad d'Hashicorp. Par Sergio Dos Santos, Dév...
 
2013 01-08-php-maturite
2013 01-08-php-maturite2013 01-08-php-maturite
2013 01-08-php-maturite
 
Infrastructure - Monitoring - Cacti
Infrastructure - Monitoring - CactiInfrastructure - Monitoring - Cacti
Infrastructure - Monitoring - Cacti
 
Apache solr andré bois-crettez 08
Apache solr   andré bois-crettez 08Apache solr   andré bois-crettez 08
Apache solr andré bois-crettez 08
 
Big sql4meetup
Big sql4meetupBig sql4meetup
Big sql4meetup
 

Comprendre et maîtriser la performance de ses applications Spark