Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Comprendre et maîtriser la performance de vos applications Spark

Fd4bf5fc86743ad04609e94ac4e11d00?s=47 rluta
April 17, 2019

Comprendre et maîtriser la performance de vos applications Spark

Support de présentation pour l'université Spark que j'ai animé à Devoxx France 2019

Fd4bf5fc86743ad04609e94ac4e11d00?s=128

rluta

April 17, 2019
Tweet

More Decks by rluta

Other Decks in Technology

Transcript

  1. #DevoxxFR Comprendre et
 Maitriser la performance
 de vos applications Spark

    Raphaël Luta - @raphaelluta 1
  2. #DevoxxFR « Vas-y fonce ! 
 On sait jamais sur

    un malentendu, ça peut marcher » 2
  3. #DevoxxFR 3

  4. #DevoxxFR 3

  5. #DevoxxFR 4 Tuning

  6. #DevoxxFR 4 Measure Tuning

  7. #DevoxxFR 4 Measure Model Tuning

  8. #DevoxxFR 4 Measure Model Hypothesis Tuning

  9. #DevoxxFR 4 Measure Model Hypothesis Adjustment Tuning

  10. #DevoxxFR Spark 5

  11. #DevoxxFR Spark 5 Python Moteur Calcul Distribué Scala Java R

  12. #DevoxxFR Spark 5 SQL Dataset MLLib
 SparkML GraphX Streaming Python

    Moteur Calcul Distribué Scala Java R
  13. #DevoxxFR Spark 5 SQL Dataset MLLib
 SparkML GraphX Streaming Standalone

    YARN Mesos Kubernetes Python Moteur Calcul Distribué Scala Java R
  14. #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
  15. #DevoxxFR Programme 7

  16. #DevoxxFR Programme 7 API

  17. #DevoxxFR Programme 7 API Modèle Exécution

  18. #DevoxxFR Programme 7 API Modèle Exécution Monitoring

  19. #DevoxxFR Programme 7 API Modèle Exécution Catalyst Monitoring

  20. #DevoxxFR Programme 7 API Modèle Exécution Catalyst Monitoring Formats Compression

    Parallélisme Mémoire S3 UDF ???
  21. #DevoxxFR 8

  22. #DevoxxFR Programme 9 API Modèle Exécution Catalyst Monitoring

  23. #DevoxxFR RDD Dataframe Dataset 10

  24. #DevoxxFR RDD API 11 RDD[T] <=> Seq[T]

  25. #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
  26. #DevoxxFR Exemple sc.textFile("wikipedia") .flatMap(line => line.split(" ")) .map(word => (word,

    1)) .reduceByKey(_ + _) .saveAsTextFile("wordcount") 13
  27. #DevoxxFR DATAFRAME API 14 Dataframe <=> Seq[Map[String,Any]]

  28. #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
  29. #DevoxxFR DATASET API 16 Dataset[T] <=> Seq[T]

  30. #DevoxxFR DATASET API 16 Dataset[T] <=> Seq[T] type Dataframe =

    Dataset[Row]
  31. #DevoxxFR Exemple case class WikiArticle(content: String) spark.read.parquet("wikipedia") .as[WikiArticle] .flatMap(_.content.split(" "))


    .groupByKey(_)
 .count .save.parquet("wordcount") 17
  32. #DevoxxFR 18

  33. #DevoxxFR Programme 19 API Modèle Exécution Catalyst Monitoring

  34. #DevoxxFR 20 20

  35. #DevoxxFR 20 20 Driver

  36. #DevoxxFR 20 20 Executor Driver

  37. #DevoxxFR 20 20 Executor Driver Task

  38. #DevoxxFR 20 20 Executor Driver Task Stage

  39. #DevoxxFR 20 20 Executor Driver Task Stage Input

  40. #DevoxxFR 20 20 Executor Driver Task Stage Stage Input

  41. #DevoxxFR 20 20 Executor Driver Task Stage Stage Shuffle Input

  42. #DevoxxFR 20 20 Executor Driver Task Stage Stage Shuffle Input

    Output Job
  43. #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
  44. #DevoxxFR Exemple découpage sc.textFile("wikipedia") .flatMap(line => line.split(" ")) .map(word =>

    (word, 1)) .reduceByKey(_ + _) .saveAsTextFile("wordcount") 22
  45. #DevoxxFR JOB 1 Exemple découpage sc.textFile("wikipedia") .flatMap(line => line.split(" "))

    .map(word => (word, 1)) .reduceByKey(_ + _) .saveAsTextFile("wordcount") 22
  46. #DevoxxFR JOB 1 Exemple découpage sc.textFile("wikipedia") .flatMap(line => line.split(" "))

    .map(word => (word, 1)) .reduceByKey(_ + _) .saveAsTextFile("wordcount") 22 STAGE 1 STAGE 2
  47. #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
  48. #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
  49. #DevoxxFR Modèles d’execution • Local • YARN • Standalone •

    Mesos • Kubernetes 25
  50. #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
  51. #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
  52. #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 ...
  53. #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 ...
  54. #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
  55. #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
  56. #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
  57. #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
  58. #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
  59. #DevoxxFR Tips: spark-submit sans jar local 28

  60. #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
  61. #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
  62. #DevoxxFR 29

  63. #DevoxxFR Programme 30 API Modèle Exécution Catalyst Tungsten Monitoring

  64. #DevoxxFR Logging Event History Metrics 31

  65. #DevoxxFR Logging Event History Metrics 32

  66. #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
  67. #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
  68. #DevoxxFR Logging Event History Metrics 35

  69. #DevoxxFR Spark Driver Spark History 36 Schedul er Executor
 1

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

    Executor
 1 Executor
 2 Executor
 3
  71. #DevoxxFR EventLog Listener Storage Event Log hdfs://spark-history/application_125321332_1 Spark Driver Web

    UI Spark History 36 Schedul er Executor
 1 Executor
 2 Executor
 3
  72. #DevoxxFR EventLog Listener Storage Event Log hdfs://spark-history/application_125321332_1 Spark Driver Web

    UI Spark History 36 Schedul er Executor
 1 Executor
 2 Executor
 3 Spark History Server
  73. #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 ...
  74. #DevoxxFR Web UI ❤ 38

  75. #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
  76. #DevoxxFR Ajouter un Listener Configuration: spark.extraListeners Code: val demoListener =

    new DemoSparkListener() sparkContext.addSparkListener(demoListener) ... do work ... sparkContext.removeSparkListener(demoListener) 40
  77. #DevoxxFR Quelques Listeners utiles 41 Sparklint 
 https://github.com/groupon/sparklint Sparklens 


    https://github.com/qubole/sparklens SparkMeasure 
 https://github.com/LucaCanali/sparkMeasure
  78. #DevoxxFR Sparklint 42

  79. #DevoxxFR Sparklens 43

  80. #DevoxxFR Logging Event History Metrics 44

  81. #DevoxxFR Metrics & Monitoring 45 Sources Jvm Scheduler HiveSQL Streaming

    ... Sinks Standard REST API
 JMX
 CSV
 Graphite
 Statsd Ganglia Sinks Communauté Prometheus Elasticsearch OpenTSDB InfluxDB ...
  82. #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
  83. #DevoxxFR Metrics JVM 47

  84. #DevoxxFR Metrics streaming 48

  85. #DevoxxFR Metrics streaming 49

  86. #DevoxxFR 50

  87. #DevoxxFR Programme 51 API Modèle Exécution Catalyst Monitoring

  88. #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
  89. #DevoxxFR Itinéraire d'une requête SQL 53 Dataset SQL Parsed Plan

    Analyzed Plan Optimized
 Plan Physical
 Plan Task RDD DRIVER EXECUTOR
  90. #DevoxxFR La requête initiale 54 SQL select nature, count(*) from

    rna group by nature Dataset rna.groupBy('nature).count.show
  91. #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
  92. #DevoxxFR Parsed -> Analyzed 56 Relation [...fields...] csv Aggregate [nature]

    [nature, count(1)] Project [nature, count] LocalLimit 21 GlobalLimit 21
  93. #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
  94. #DevoxxFR Parsed -> Analyzed 56 Relation [...fields...] csv id, siret,

    rup_mi, gestion, nature, ... nature: String, count: Long Aggregate [nature] [nature, count(1)] Project [nature, count] LocalLimit 21 GlobalLimit 21
  95. #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
  96. #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
  97. #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
  98. #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
  99. #DevoxxFR Partition Pruning 58 rna year=2018 part-0001 year=2016 year=2017 year=2019

    part-0001 part-0001 part-0001
  100. #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
  101. #DevoxxFR Partition Pruning 58 rna year=2018 part-0001 select nature, count(*)

    from rna where year=2018 group by nature
  102. #DevoxxFR Pushdown Predicate 59 rna year=2018 part-0001 year=2016 year=2017 year=2019

    part-0001 part-0001 part-0001
  103. #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
  104. #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-0001 part-0001 part-0001 part-0001 part-0001 part-0001 part-0001 part-0001
  105. #DevoxxFR year=2016 year=2017 year=2019 part-0001 part-0001 part-0001 part-0001 Projection Pushdown

    60 rna year=2018
  106. #DevoxxFR year=2016 year=2017 year=2019 part-0001 part-0001 part-0001 part-0001 Projection Pushdown

    60 rna year=2018 select nature, count(*) from rna group by nature
  107. #DevoxxFR year=2016 year=2017 year=2019 part-0001 part-0001 part-0001 part-0001 part-0001 part-0001

    part-0001 part-0001 part-0001 part-0001 part-0001 part-0001 Projection Pushdown 60 rna year=2018 select nature, count(*) from rna group by nature
  108. #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
  109. #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
  110. #DevoxxFR Obtenir les plans 63 Web UI: Onglet SQL ->

    Détails SQL: EXPLAIN [EXTENDED] <QUERY> Dataset: rna.explain(true)
  111. #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
  112. #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
  113. #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
  114. #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
  115. #DevoxxFR Voir le code... 68 Dataset df.queryExecution.debug.codegen SQL EXPLAIN CODEGEN

    <QUERY>
  116. #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
  117. #DevoxxFR 70

  118. #DevoxxFR Programme 71 API Modèle Exécution Catalyst Monitoring Formats Parallélisme

    Gestion mémoire AWS Joins & Skew Sizing Exécuteurs ???
  119. #DevoxxFR Histoire de parallélisme 72

  120. #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
  121. #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)
  122. #DevoxxFR Shuffle 75 Un seul paramètre spark.sql.shuffle.partitions (200 par défaut)

    "Bientôt" un support de shuffle adaptatif: SPARK-9850
  123. #DevoxxFR Output 76 Nombre de fichiers écrits: • Partitions RDD

    (i.e nombre de Tasks) • Partitionnement de la table • Bucketing
  124. #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é !
  125. #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
  126. #DevoxxFR Comment paramétrer le driver et les exécuteurs ? 79

  127. #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
  128. #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
  129. #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
  130. #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
  131. #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 !
  132. #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
  133. #DevoxxFR Optimiser les joins et le skew ? 86

  134. #DevoxxFR 2 types principaux types de join 87

  135. #DevoxxFR 2 types principaux types de join 87 SortMergeJoin Data

    1 Data 2 Sort[key] Sort[key] Merge Data 3
  136. #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
  137. #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
  138. #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
  139. #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
  140. #DevoxxFR Sel + Merge 91

  141. #DevoxxFR Sel + Merge val df = df1.groupBy(‘id).agg(sum(‘value)) 91

  142. #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
  143. #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
  144. #DevoxxFR Gestion Mémoire et OOM 92

  145. #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 Unified memory
  146. #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
  147. #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
  148. #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.
  149. #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, ...)
  150. #DevoxxFR Gérer le memoryOverhead 98

  151. #DevoxxFR Gérer le memoryOverhead 98 Limiter les DirectBuffers
 spark.executor.extraJavaOptions=-XX:MaxDirectMemorySize=XXXM
 ou


    spark.shuffle.io.preferDirectBufs=false
  152. #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
  153. #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
  154. #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
  155. #DevoxxFR Quel format utiliser pour stocker les données ? 99

  156. #DevoxxFR Le bon format: un compromis 100

  157. #DevoxxFR Le bon format: un compromis 100 Expressivité

  158. #DevoxxFR Le bon format: un compromis 100 Expressivité Evolutivité

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

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

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

    
 
 Performance Efficacité

  162. #DevoxxFR Les familles 101 Formats texte Formats binaires

  163. #DevoxxFR Les familles 101 CSV
 - universel
 - compact
 -

    pas de schema
 - parsing compliqué
 Formats texte Formats binaires
  164. #DevoxxFR Les familles 101 CSV
 - universel
 - compact
 -

    pas de schema
 - parsing compliqué
 JSON
 - inefficace
 - schema limité Formats texte Formats binaires
  165. #DevoxxFR Les familles 101 CSV
 - universel
 - compact
 -

    pas de schema
 - parsing compliqué
 JSON
 - inefficace
 - schema limité XML
 - inefficace
 - OOM Formats texte Formats binaires
  166. #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
  167. #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
  168. #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
  169. #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
  170. #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
  171. #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 !
  172. #DevoxxFR Spécificités cloud 105

  173. #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
  174. #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)
  175. #DevoxxFR A suivre de près 108 http://iceberg.incubator.apache.org

  176. #DevoxxFR En résumé 109

  177. #DevoxxFR 110 Measure Model Hypothesis Adjustment Tuning

  178. #DevoxxFR Modèle d'exécution 111

  179. #DevoxxFR Logging Event History Metrics 112

  180. #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
  181. #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
  182. #DevoxxFR Bonnes pratiques • Privilégiez les formats type Parquet ou

    ORC • Utilisez un Metastore • Privilégiez des exécuteurs multi-core 115
  183. #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
  184. #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
  185. #DevoxxFR Pour optimiser Spark, il faut comprendre vos données 


    et son modèle d'exécution 118
  186. #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