Diagnostic Spark SQL
Quand l'utiliser
À utiliser lorsque l'utilisateur fournit l'une des combinaisons suivantes :
- Une URL Spark UI / History Server / YARN proxy ;
- Une requête Spark SQL et son
EXPLAIN FORMATTED; - Les logs d'exécution Kyuubi / Spark Driver ;
- Un JSON exporté via
/api/v1/..., ou un event log.
L'objectif n'est pas de "regarder quelques métriques", mais de répondre à :
- À quel niveau cette requête est lente : scan, shuffle, jointure, agrégation, spill, GC, planification, démarrage à froid ;
- Y a-t-il une asymétrie des données (data skew), et sur quel stage / task / fragment SQL ;
- Les problèmes sont-ils liés aux données, aux ressources ou à la configuration ;
- La prochaine étape doit-elle être de modifier le SQL, la configuration, ou d'enrichir les données.
Priorité des entrées
| Entrée | Ce qu'elle permet |
|---|---|
| URL UI + ID d'exécution / heure de soumission + SQL | La plus complète, diagnostic au niveau des tasks |
| Logs d'exécution (contenant app ID et URL UI) + SQL | D'abord analyser les logs, puis accéder à l'UI ; si l'UI n'est pas disponible, dégradation au niveau des stages |
| EXPLAIN FORMATTED | Uniquement analyse de la structure du plan et correspondance avec les fragments SQL |
| event log / History Server | Solution de repli après expiration de l'UI |
Les logs contiennent généralement déjà :
application ID: application_xxx
application web UI: http://host:8088/proxy/application_xxx
L'utilisateur n'a donc pas besoin de coller à nouveau l'URL, mais il faut absolument vérifier si l'URL est accessible.
Workflow
1. Collecter et analyser les entrées
- Extraire des logs : app ID, URL UI, operation ID, timeline des stages/jobs, Final Plan ;
- Extraire du SQL original : noms de tables, conditions de jointure, group by / distinct / window / order by ;
- Extraire de
EXPLAIN FORMATTED: opérateurs, colonnes d'entrée/sortie, conditions de jointure, clés d'agrégation.
2. Localiser l'exécution réelle
- Priorité à l'ID d'exécution ;
- Sinon, faire correspondre le texte SQL + l'heure de soumission dans la liste
/sql; /sqlne retourne par défaut qu'un petit nombre d'enregistrements à partir de offset=0 ; il faut paginer ou détecter par ID ;- En cas de plusieurs candidats, choisir celui dont la description correspond le mieux et dont la date est la plus récente ; si toujours pas unique, demander à l'utilisateur.
3. Récupérer les données d'exécution
Exécuter le script (recommandé). Le scripts/ ci-dessous est relatif au répertoire de cette compétence ; si vous exécutez depuis un autre répertoire, cd d'abord vers le répertoire de la compétence, ou utilisez un chemin absolu.
python scripts/spark_diagnose.py \
--url "http://host:8088/proxy/application_xxx" \
--exec-id 94 \
--sql-file query.sql \
--explain explain.txt \
--log run.log \
--out report.md \
--json report.json
Si l'ID d'exécution est incertain :
python scripts/spark_diagnose.py \
--url "http://host:18080/history/application_xxx/" \
--sql-file query.sql \
--exec-time "2026-11-02T08:06:50Z" \
--out report.md
Paramètres d'authentification :
--cookie "name=value; name2=value2"
--header "X-Token: ..."
--user "user:password"
--kerberos # utilise curl --negotiate
--insecure # ignore la validation TLS, réservé aux certificats auto-signés en interne
Principe de lecture seule : le script n'effectue que des appels GET, n'exécute pas de SQL, n'écrit pas sur le cluster.
4. Interpréter les indicateurs
Le script produit un JSON structuré et du Markdown. Concentrez-vous sur :
- Timeline des stages : temps mural vs
executorRunTimevs délai de démarrage des tâches ; - Distribution des tâches : max/médiane/p95 de duration, records, shuffle bytes ;
- Vrai skew : le nombre d'enregistrements et la durée d'une tâche sont tous deux significativement supérieurs à la médiane ;
- Faux tail : le nombre d'enregistrements est normal, mais
executorDeserializeTimeest élevé, généralement dû à un executor à froid ; - Spill :
memoryBytesSpilled/diskBytesSpilled, ainsi quespill sizedes nœuds du plan ; - Nœuds du plan : Scan, Exchange, Join, Aggregate : output rows / shuffle bytes / duration ;
- Configuration : AQE, seuil skewJoin, nombre de partitions shuffle, seuil de broadcast, allocation dynamique.
5. Rédiger le rapport final
Le script fournit les preuves et les conclusions candidates. La réponse finale doit impérativement être complétée en lien avec la sémantique SQL :
- Correspondance opérateur → fragment SQL ;
- Signification métier des clés chaudes (si elle peut être déduite du SQL / de la logique de création de table) ;
- Priorité des recommandations et bénéfices attendus ;
- Marquage explicite des parties nécessitant une validation externe.
Structure du rapport :
- Conclusion en premier (classée par impact) ;
- Aperçu de l'exécution et timeline ;
- Tableau des preuves de skew/long tail ;
- Correspondance du plan SQL ;
- Configuration et risques ;
- Recommandations ;
- Sources des preuves et limites ;
- Questions nécessitant encore une validation externe.
Règles clés de jugement
Ces règles doivent être respectées pour éviter les erreurs de diagnostic les plus courantes :
-
Le skew se juge sur records et duration, pas uniquement sur shuffle bytes. Une clé chaude hautement compressible (par exemple beaucoup de
item_id=1) peut ne représenter que quelques Mo, mais contenir 60% des enregistrements. -
Distinguer le vrai skew du démarrage à froid. Une tâche lente avec un nombre d'enregistrements normal et un rapport
executorDeserializeTime / durationélevé est due à un executor à froid, pas à un skew. -
L'agrégation partielle peut masquer le skew GROUP BY. Lorsque le plan contient
partial_count/partial_sum, les clés chaudes sont compressées en quelques lignes avant le shuffle ; il faut vérifier si la syntaxe d'agrégation elle-même contourne le skew. -
count(DISTINCT)est une déduplication en deux phases. La clé du premier shuffle contient généralement le champ distinct (par exemple(item_id, buyer_id)), les points chauds sont dispersés ; ne pas juger comme un GROUP BY ordinaire. -
Le skew join AQE est basé sur la taille. Le critère est la taille de la partition après compression par rapport à
skewedPartitionFactor/skewedPartitionThresholdInBytes; une clé chaude compressible peut être inférieure au seuil et ne pas être fractionnée. -
Augmenter le nombre de partitions shuffle ne dilue pas une clé chaude unique. Une clé unique va toujours dans une seule partition ; plus il y a de partitions, plus les autres sont petites, ce qui augmente le rapport max/médiane.
-
Quand le temps mural d'un stage est très supérieur au temps d'exécution des tâches, vérifier d'abord la planification. Regarder
launchTime - submissionTime,minExecutorsde l'allocation dynamique, la file YARN. -
Ne suspecter une expansion de jointure que si le nombre de lignes en sortie est nettement supérieur au nombre de lignes en entrée. Si le nombre de lignes en sortie est égal au nombre de lignes de la table de faits, le problème est généralement la distribution, pas des clés en double.
Limites
- Le contenu réel des données n'est pas visible ; les valeurs spécifiques des clés chaudes nécessitent que l'utilisateur consulte les données ;
- Les files d'attente YARN et les causes lentes d'allocation de conteneurs nécessitent les logs RM/Kyuubi ;
- Les problèmes de code UDF/personnalisé nécessitent le code et les logs des executors ;
- Sans UI/event log, les logs Driver ordinaires ne permettent qu'un diagnostic au niveau des stages ;
- N'exécute pas de SQL, ne modifie pas les données, n'affiche pas les cookies/tokens.
Références
references/endpoints.md: Points de terminaison REST et pagination ;references/metrics.md: Différences de champs et conversion d'unités ;references/heuristics.md: Seuils, plan et jugement des skew.