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

Comprendre et maîtriser la performance de vos a...

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

rluta

April 17, 2019
Tweet

More Decks by rluta

Other Decks in Technology

Transcript

  1. #DevoxxFR « Vas-y fonce ! 
 On sait jamais sur

    un malentendu, ça peut marcher » 2
  2. #DevoxxFR Spark 5 SQL Dataset MLLib
 SparkML GraphX Streaming Standalone

    YARN Mesos Kubernetes Python Moteur Calcul Distribué Scala Java R
  3. #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
  4. #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
  5. #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
  6. #DevoxxFR JOB 1 Exemple découpage sc.textFile("wikipedia") .flatMap(line => line.split(" "))

    .map(word => (word, 1)) .reduceByKey(_ + _) .saveAsTextFile("wordcount") 22
  7. #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
  8. #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
  9. #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
  10. #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
  11. #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
  12. #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 ...
  13. #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 ...
  14. #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
  15. #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
  16. #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
  17. #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
  18. #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
  19. #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
  20. #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
  21. #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
  22. #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
  23. #DevoxxFR Spark Driver Web UI Spark History 36 Schedul er

    Executor
 1 Executor
 2 Executor
 3
  24. #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
  25. #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
  26. #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 ...
  27. #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
  28. #DevoxxFR Ajouter un Listener Configuration: spark.extraListeners Code: val demoListener =

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


    https://github.com/qubole/sparklens SparkMeasure 
 https://github.com/LucaCanali/sparkMeasure
  30. #DevoxxFR Metrics & Monitoring 45 Sources Jvm Scheduler HiveSQL Streaming

    ... Sinks Standard REST API
 JMX
 CSV
 Graphite
 Statsd Ganglia Sinks Communauté Prometheus Elasticsearch OpenTSDB InfluxDB ...
  31. #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
  32. #DevoxxFR Itinéraire d'une requête SQL 53 Dataset SQL Parsed Plan

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

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

    [nature, count(1)] Project [nature, count] LocalLimit 21 GlobalLimit 21
  36. #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
  37. #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
  38. #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
  39. #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
  40. #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
  41. #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
  42. #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
  43. #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
  44. #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
  45. #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
  46. #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
  47. #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
  48. #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
  49. #DevoxxFR Obtenir les plans 63 Web UI: Onglet SQL ->

    Détails SQL: EXPLAIN [EXTENDED] <QUERY> Dataset: rna.explain(true)
  50. #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
  51. #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
  52. #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
  53. #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
  54. #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
  55. #DevoxxFR Programme 71 API Modèle Exécution Catalyst Monitoring Formats Parallélisme

    Gestion mémoire AWS Joins & Skew Sizing Exécuteurs ???
  56. #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
  57. #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)
  58. #DevoxxFR Output 76 Nombre de fichiers écrits: • Partitions RDD

    (i.e nombre de Tasks) • Partitionnement de la table • Bucketing
  59. #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é !
  60. #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
  61. #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
  62. #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
  63. #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
  64. #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
  65. #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 !
  66. #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
  67. #DevoxxFR 2 types principaux types de join 87 SortMergeJoin Data

    1 Data 2 Sort[key] Sort[key] Merge Data 3
  68. #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
  69. #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
  70. #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
  71. #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
  72. #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
  73. #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
  74. #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
  75. #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
  76. #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
  77. #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.
  78. #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, ...)
  79. #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
  80. #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
  81. #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
  82. #DevoxxFR Les familles 101 CSV
 - universel
 - compact
 -

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

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

    pas de schema
 - parsing compliqué
 JSON
 - inefficace
 - schema limité XML
 - inefficace
 - OOM Formats texte Formats binaires
  85. #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
  86. #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
  87. #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
  88. #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
  89. #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
  90. #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 !
  91. #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
  92. #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)
  93. #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
  94. #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
  95. #DevoxxFR Bonnes pratiques • Privilégiez les formats type Parquet ou

    ORC • Utilisez un Metastore • Privilégiez des exécuteurs multi-core 115
  96. #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
  97. #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
  98. #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