Intro
Un laboratoire Spark local permet d'apprendre rapidement, de tester des idées en toute sécurité et de bâtir des habitudes reproductibles avant de toucher aux systèmes partagés. Dans ce guide vous allez :
- Installer Spark et vérifier le mode local.
- Créer une arborescence de laboratoire propre avec données, journaux et points de contrôle.
- Exécuter des exemples batch et streaming que vous pouvez inspecter.
- Soumettre des jobs programmatiquement et ajouter un test minimal.
À la fin, vous disposerez d'un workflow réutilisable pour le dépannage, l'expérimentation et le développement.
Workflow Overview
Utilisez un flux simple et répétable qui garde les changements petits et visibles :
- Définissez un objectif précis et des critères de succès.
- Préparez les dossiers du laboratoire et les données d'exemple.
- Configurez les valeurs par défaut de Spark pour des exécutions et des logs cohérents.
- Lancez le code en mode local et inspectez l'interface Spark UI.
- Capturez les résultats dans des dossiers de sortie versionnés.
- Ajoutez un petit test pour protéger les transformations critiques.
- Itérez par petites étapes, en changeant une seule chose à la fois.
Cette séparation des étapes réduit le retravail et facilite l'isolation des problèmes.
Local Lab Setup
Prerequisites
- CPU : 4 cœurs
- RAM : 8 Go minimum
- Disque : 10 Go libres
- Java 11 ou 17 (vérifiez avec
java -version) - Python 3.9+ si vous utilisez PySpark
Create the lab folders
mkdir -p ~/labs/spark/data/batch/input
mkdir -p ~/labs/spark/data/batch/output
mkdir -p ~/labs/spark/data/stream/input
mkdir -p ~/labs/spark/logs/events
mkdir -p ~/labs/spark/checkpoints
Install Spark (pre‑built binaries)
- Téléchargez Spark 3.5.1 pré‑construit pour Hadoop 3 depuis l'archive officielle.
- Décompressez‑le, par exemple dans
~/tools/spark-3.5.1-bin-hadoop3. - Définissez les variables d'environnement.
macOS / Linux (bash/zsh)
export SPARK_HOME=~/tools/spark-3.5.1-bin-hadoop3
export PATH="$SPARK_HOME/bin:$PATH"
# Définissez JAVA_HOME sur votre JDK installé
# Exemple macOS :
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
Windows (PowerShell)
setx SPARK_HOME "C:\tools\spark-3.5.1-bin-hadoop3"
setx PATH "%SPARK_HOME%\bin;%PATH%"
# Définissez JAVA_HOME sur le chemin de votre JDK comme variable d'environnement utilisateur ou système
Configure Spark defaults
Copiez le modèle et éditez le fichier de configuration :
cp "$SPARK_HOME/conf/spark-defaults.conf.template" "$SPARK_HOME/conf/spark-defaults.conf"
Ajoutez les lignes suivantes à spark-defaults.conf (remplacez youruser par votre nom d'utilisateur réel) :
spark.eventLog.enabled true
spark.eventLog.dir file:///home/youruser/labs/spark/logs/events
spark.sql.shuffle.partitions 4
Verify the install
spark-shell --version
pyspark --version
Démarrez une session PySpark interactive et faites un test rapide :
pyspark --master local[2]
# Dans le shell :
spark.range(5).show()
# Visitez http://localhost:4040 pour voir la Spark UI tant que le shell est actif.
exit()
Practical Examples
1) Batch aggregation: CSV to Parquet
Préparez un petit CSV avec une valeur manquante à la dernière ligne :
cat > ~/labs/spark/data/batch/input/customers.csv << 'EOF'
customer_id,name,country,spend
1,Alice,US,120.5
2,Bob,DE,95
3,Cara,US,250
4,Dan,FR,40
5,Eve,US,
EOF
Créez batch_example.py :
# batch_example.py
from pyspark.sql import SparkSession
from pyspark.sql import functions as F
from pyspark.sql.functions import col
import argparse
def transform(df):
clean = (
df.filter(col("spend\)).isNotNull())
.withColumn("spend_usd", col("spend\)).cast("double\)
)
agg = (
clean.groupBy("country\)
.agg(
F.count("\*\).alias("customers\)
F.round(F.avg("spend_usd\),
2).alias("avg_spend\))
)
.orderBy("country\)
)
return agg
def main(input_path: str, output_path: str):
spark = SparkSession.builder.appName("batch-agg\)).getOrCreate()
df = (spark.read
.option("header", "true\)
.option("inferSchema", "true\)
.csv(input_path))
result = transform(df)
(result.write
.mode("overwrite\)
.parquet(output_path))
result.show(truncate=False)
spark.stop()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("\-\-input", required=True)
parser.add_argument("\-\-output", required=True)
args = parser.parse_args()
main(args.input, args.output)
Exécutez‑le avec spark-submit :
cd ~/labs/spark
spark-submit \
--master local[4] \
--name batch-agg \
batch_example.py \
--input data/batch/input \
--output data/batch/output/parquet
Inspectez la sortie :
ls -R data/batch/output/parquet
Pendant l'exécution, ouvrez la Spark UI à http://localhost:4040 pour visualiser les DAG et les étapes, et consultez les journaux d'événements dans ~/labs/spark/logs/events.
2) Structured Streaming: file source to console
Créez stream_example.py :
# stream_example.py
from pyspark.sql import SparkSession
from pyspark.sql.functions import window, col, count
spark = (\n SparkSession.builder\n .appName("word-count-stream\)\n .master("local[2]\n .getOrCreate()\)
schema = "ts timestamp, word string"
stream = (\n spark.readStream\n .schema(schema)\n .json("data/stream/input\)
)
counts = (\n stream.withWatermark("ts", "1 minute\)\n .groupBy(window(col("ts\)), "30 seconds\)), col("word\)\n .agg(count("\*\).alias("n\))
)
query = (\n counts.writeStream\n .outputMode("append\)\n .format("console\)\n .option("truncate", "false\)\n .trigger(processingTime="5 seconds\)\n .start()\)
print("Streaming started. Append JSON lines to data/stream/input ...\)
query.awaitTermination()
Démarrez le job streaming :
cd ~/labs/spark
python3 stream_example.py
Dans un autre terminal, ajoutez quelques événements :
cd ~/labs/spark
cat > data/stream/input/batch1.json << 'EOF'
{"ts":"2024-01-01T10:00:00","word":"spark"}
{"ts":"2024-01-01T10:00:10","word":"spark"}
{"ts":"2024-01-01T10:00:20","word":"lab"}
EOF
Vous devriez voir les comptages défiler dans la console. Rendez‑vous sur http://localhost:4040 pour observer les requêtes streaming et les opérations d'état pendant l'exécution.
3) Minimal test for the batch transform
Ajoutez test_batch_example.py :
# test_batch_example.py
import pytest
from pyspark.sql import SparkSession, Row
from batch_example import transform
@pytest.fixture(scope="session\)
def spark():
return (\n SparkSession.builder\n .appName("test-batch-agg\)\n .master("local[2]\n .getOrCreate()\n )
def test_transform_basic(spark):
rows = [
Row(customer_id=1, name="A", country="US", spend=100.0),
Row(customer_id=2, name="B", country="US", spend=50.0),
Row(customer_id=3, name="C", country="DE", spend=70.0),
Row(customer_id=4, name="D", country="US", spend=None),
]
df = spark.createDataFrame(rows)
out = transform(df)
got = {(r["country"], r["customers"], float(r["avg_spend\))) for r in out.collect()}
assert ("DE", 1, 70.0) in got
assert ("US", 2, 75.0) in got
Lancez le test :
pytest -q
Local Pilot Plan
Choisissez une tâche que vous pouvez mesurer et inspecter rapidement :
- Goal : Convertir un petit CSV en Parquet et calculer les moyennes par pays.
- Scope : ≤ 10 Mo de données d'entrée, un dossier de sortie, une fonction de transformation.
- Success criteria :
- Le Parquet de sortie existe avec les colonnes attendues (
country,customers,avg_spend) et un nombre de lignes égal au nombre de pays distincts. - La Spark UI affiche des étapes terminées sans échec.
- Temps d'exécution sous 30 secondes sur votre machine.
- Timebox : 1 à 2 heures, incluant la configuration et un test de base.
Pourquoi ça fonctionne : c'est ciblé, mesurable et facile à inspecter localement. Vous obtenez un retour rapide et pouvez étendre plus tard vers d'autres sources (par exemple, ajouter Kafka ou HDFS une fois le chemin local solide).
Troubleshooting and Tips
- Erreurs Java : Assurez‑vous que
java -versioncorrespond au JDK attendu (11 ou 17). DéfinissezJAVA_HOMEexplicitement. - pyspark introuvable : Vérifiez que
$SPARK_HOME/binest bien dans votrePATH. - Spark UI non disponible : L'UI ne tourne que pendant qu'une application Spark est active. Lancez un shell ou un job, puis visitez
http://localhost:4040. - Conflits de port : Si le port 4040 est occupé, Spark essaiera 4041, 4042, etc. Regardez la sortie du terminal pour le port réel.
- Mémoire : Pour des exécutions locales, essayez
--driver-memory 2g --executor-memory 2get gardezspark.sql.shuffle.partitionspetit (par exemple 4). - Permissions de fichiers : Gardez votre laboratoire sous votre répertoire personnel pour éviter les problèmes de droits.
- Reproductibilité : Fixez la version de Spark, épinglez les versions des packages Python (par exemple via
requirements.txt), et conservez les données d'exemple dans le contrôle de version.
Sujets connexes à explorer ensuite :
- Kafka : remplacez la source de fichiers streaming par une source Kafka dès que vous avez un broker.
- HDFS : pointez les entrées et sorties vers HDFS pour des tests plus volumineux.
- Apache Airflow ou NiFi : orchestrez les jobs une fois votre pilote local stable.
Conclusion
Vous disposez maintenant d'un laboratoire Spark local sûr, de deux exemples pratiques, d'un test minimal et d'un plan pilote clair. Procédez par petites itérations, vérifiez les sorties et les performances dans l'UI et les logs, et n'ajoutez des intégrations comme Kafka, HDFS, Airflow ou NiFi qu'une fois le socle local maîtrisé. Cette approche garde l'apprentissage rapide et les échecs peu coûteux tout en vous préparant au travail à l'échelle de la production.