AccueilBlogTest technique Spark avance : Structured Streaming, Delta Lake, optimisation
Guide recrutement data

Test technique Spark avance : Structured Streaming, Delta Lake, optimisation

Au-dela des DataFrames de base, un Data Engineer Spark Senior maitrise le streaming, Delta Lake et l optimisation fine des jobs. C est ce qu on evalue pour les profils qui font tourner Spark en production.

Data Builder·Juin 2025·7 min de lecture·Data Engineer
Sommaire
  1. Structured Streaming
  2. Delta Lake
  3. Optimisation avancee AQE
  4. Spark on Kubernetes
  5. Memoire et GC tuning
  6. Unity Catalog et governance
  7. Grille

Spark batch sur des fichiers CSV, tout le monde sait faire. Ce qu on evalue en entretien Senior, c est le streaming, la gestion des transactions ACID avec Delta Lake et la capacite a diagnostiquer des jobs lents.

1Structured Streaming : traitement en continu

Question discriminante

Quelle est la difference entre le micro-batch et le continuous processing dans Spark Structured Streaming ?

from pyspark.sql import SparkSession from pyspark.sql.functions import window, count spark = SparkSession.builder.appName('streaming').getOrCreate() # Lire depuis Kafka en streaming df = spark.readStream \ .format('kafka') \ .option('kafka.bootstrap.servers', 'kafka:9092') \ .option('subscribe', 'events') \ .load() # Aggregation avec window temporelle result = df \ .selectExpr('CAST(value AS STRING) as event') \ .groupBy(window('timestamp', '5 minutes'), 'event') \ .agg(count('*').alias('cnt')) # Ecriture en Delta Lake query = result.writeStream \ .format('delta') \ .outputMode('complete') \ .option('checkpointLocation', '/checkpoints/events') \ .start('/data/events_aggregated') query.awaitTermination()
  • Micro-batch — par defaut, Spark traite de petits lots a intervalle fixe. Latence de quelques secondes
  • Continuous processing — mode experimental, latence sub-milliseconde, operations limitees
  • Checkpoint — stocke l etat du streaming pour la reprise apres panne. Obligatoire en production
  • Watermark — gerer les evenements en retard (late data) dans les aggregations temporelles

2Delta Lake : ACID pour le data lake

Question discriminante

Quels problemes Delta Lake resout-il par rapport a Parquet classique ?

from delta.tables import DeltaTable # MERGE : upsert ACID delta_table = DeltaTable.forPath(spark, '/data/customers') delta_table.alias('target').merge( updates_df.alias('source'), 'target.customer_id = source.customer_id' ).whenMatchedUpdate(set={ 'name': 'source.name', 'email': 'source.email', 'updated_at': 'source.updated_at' }).whenNotMatchedInsert(values={ 'customer_id': 'source.customer_id', 'name': 'source.name', 'email': 'source.email', 'updated_at': 'source.updated_at' }).execute() # Time Travel : requeter les donnees passees df_yesterday = spark.read.format('delta') \ .option('timestampAsOf', '2025-01-01') \ .load('/data/customers') # OPTIMIZE + ZORDER : ameliorer les perfs de lecture delta_table.optimize().executeZOrderBy('region', 'date')
  • ACID — transactions atomiques. Plus de fichiers corrompus si le job crashe en cours
  • Time Travel — requeter les donnees a n importe quelle version ou timestamp precedent
  • Schema Evolution — ajouter des colonnes sans casser les requetes existantes
  • MERGE — upsert en une seule operation. Essentiel pour les CDC (Change Data Capture)

3Adaptive Query Execution (AQE)

Question discriminante

Qu est-ce que l AQE dans Spark 3+ ? Comment resout-il le probleme du data skew ?

# Activer AQE (actif par defaut dans Spark 3.2+) spark.conf.set('spark.sql.adaptive.enabled', 'true') spark.conf.set('spark.sql.adaptive.coalescePartitions.enabled', 'true') spark.conf.set('spark.sql.adaptive.skewJoin.enabled', 'true') # Pour le skew : diviser automatiquement les partitions desequilibrees spark.conf.set('spark.sql.adaptive.skewJoin.skewedPartitionFactor', '5') spark.conf.set('spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes', '256m')
  • AQE — Spark optimise le plan d execution a la volee, en tenant compte des statistiques reelles des donnees intermediaires
  • Skew join handling — detecte et divise automatiquement les partitions tres lourdes (data skew)
  • Dynamic coalescing — reduit le nombre de partitions shuffle si les donnees sont petites
  • Broadcast join — convertit automatiquement un sort-merge join en broadcast join si une table est petite

4Spark on Kubernetes

  • spark-submit --master k8s:// — le driver et les executors sont des Pods Kubernetes
  • Avantages — isolation par job, scaling elastique, meilleure utilisation des ressources vs YARN
  • Spot instances — reduire les couts de 60-80% sur les jobs batch en utilisant des noeuds preemptibles
  • Volcano scheduler — scheduler Kubernetes optimise pour les workloads ML/data (gang scheduling)

5Memory et GC tuning

# Configuration memoire Spark spark.conf.set('spark.executor.memory', '8g') spark.conf.set('spark.executor.memoryOverhead', '2g') # memoire off-heap spark.conf.set('spark.sql.shuffle.partitions', '200') # ajuster selon le volume # Preferer G1GC pour les gros heap spark.conf.set('spark.executor.extraJavaOptions', '-XX:+UseG1GC') # Persistance strategique df_heavy.persist(StorageLevel.MEMORY_AND_DISK) # si reutilise plusieurs fois # Nettoyer apres usage df_heavy.unpersist()

6Unity Catalog : gouvernance Databricks

  • Unity Catalog — couche de gouvernance centralisee pour tous les assets Databricks (tables Delta, fichiers, modeles ML, notebooks)
  • 3 niveaux — Catalog > Schema > Table. Remplace le Hive metastore
  • Column-level security — masquer des colonnes selon le role de l utilisateur
  • Data lineage automatique — lineage jusqu a la colonne, integre avec dbt et Spark
from pyspark.sql import SparkSession from pyspark.sql.functions import col, broadcast spark = SparkSession.builder \ .config('spark.sql.adaptive.enabled', 'true') \ .config('spark.sql.adaptive.coalescePartitions.enabled', 'true') \ .config('spark.sql.adaptive.skewJoin.enabled', 'true') \ .getOrCreate() # Broadcast join : diffuser la petite table sur tous les workers result = large_df.join(broadcast(small_df), 'category_id') # Repartition strategique avant un groupBy lourd df_repartitioned = df.repartition(200, col('customer_id')) agg_result = df_repartitioned.groupBy('customer_id').agg({'amount': 'sum'}) # Persist pour reutiliser un DataFrame calcule plusieurs fois df_filtered = df.filter(col('status') == 'completed').persist() count = df_filtered.count() agg = df_filtered.groupBy('region').sum('amount') # Lire le plan d execution result.explain(extended=True) # voir les stages, shuffles, pushdowns
  • AQE (Adaptive Query Execution) - Spark 3.x optimise le plan d execution au runtime. Coalesce les partitions vides, detecte le data skew, choisit broadcast join automatiquement
  • Shuffle partitions - spark.sql.shuffle.partitions=200 par defaut. Regler selon la volumetrie : 1 partition ~128MB de donnees shufflees est un bon point de depart
  • Data skew - une partition 100x plus grosse que les autres = un executor qui bloque tous les autres. Remedies : salting (ajouter du bruit a la cle de join), AQE skewJoin, ou filter + union
  • Catalyst optimizer - Spark convertit les DataFrames en plan logique puis physique optimise. Privilegier les DataFrames sur les RDDs pour profiter de Catalyst
  • Tungsten - moteur d execution memoire de Spark. Serialisation binaire, generation de bytecode. Utilise automatiquement avec les DataFrames

7Grille par niveau

NiveauMaitriseSignal GONO-GO
ConfirmeDataFrame API, Delta Lake basique, partitionnementA utilise Delta MERGE, sait ce qu est Time Travel, configure les partitions shuffleN a jamais utilise Delta Lake, ne sait pas ce qu est AQE
SeniorStructured Streaming, AQE, Spark on K8s, memory tuningA deploye un job Spark Streaming, a debug un skew join, a optimise la memoireN a jamais fait de streaming, ne sait pas diagnostiquer un OOM Spark
LeadArchitecture lakehouse, Unity Catalog, standards d equipeA concu une architecture lakehouse, defini les standards de gouvernance DatabricksNe peut pas expliquer la difference entre Data Lake et Lakehouse

Vous recrutez un Data Engineer Spark ?

Premier entretien gratuit. Rapport GO/NO-GO sous 48h.