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.
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.
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()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')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')# 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()| Niveau | Maitrise | Signal GO | NO-GO |
|---|---|---|---|
| Confirme | DataFrame API, Delta Lake basique, partitionnement | A utilise Delta MERGE, sait ce qu est Time Travel, configure les partitions shuffle | N a jamais utilise Delta Lake, ne sait pas ce qu est AQE |
| Senior | Structured Streaming, AQE, Spark on K8s, memory tuning | A deploye un job Spark Streaming, a debug un skew join, a optimise la memoire | N a jamais fait de streaming, ne sait pas diagnostiquer un OOM Spark |
| Lead | Architecture lakehouse, Unity Catalog, standards d equipe | A concu une architecture lakehouse, defini les standards de gouvernance Databricks | Ne peut pas expliquer la difference entre Data Lake et Lakehouse |
Premier entretien gratuit. Rapport GO/NO-GO sous 48h.