Spark
JuniorVarför blev mitt Spark-jobb plötsligt långsammare utan kodändringar?
Nio gånger av tio är det inte koden. Det är datan, klustret eller en konfiguration som tyst slutade matcha någon av dem.
Du har inte rört jobbet. DAG:en är identisk. Den senaste driftsättningen var för tre veckor sedan. Ändå tog körningen i natt 40 minuter istället för 12. Det här är ett av de vanligaste ärendena inom data engineering, och det går nästan alltid att spåra till en av tre saker.
1. Datan växte, men konfigurationen gjorde det inte
Antal shuffle-partitioner, executor-minne och broadcast-join-trösklar sätts oftast en gång, under
inledande utveckling, mot vilken datavolym som fanns då. Sex månader senare har samma tabell 4x så många
rader, och samma spark.sql.shuffle.partitions=200 ger nu partitioner som är för stora för att
bekvämt rymmas i minnet, vilket tvingar fram spill till disk vid varje shuffle-steg. Inget i koden ändrades;
antagandet som konfigurationen kodade gjorde det.
Så kontrollerar du det: jämför antal inkommande rader och shuffle-läs-/skrivbytes mellan en nyligen långsam körning och en äldre snabb, i Spark UI:s Stages-flik. Ett stort hopp där, med en ungefär proportionell inbromsning, pekar rakt på detta.
2. En join som brukade vara balanserad är det inte längre
Data skew annonserar inte sig själv — det betyder bara att en handfull partitioner gör 10-100x mer arbete än resten, så väggklockstiden dikteras av den långsammaste tasken, inte den genomsnittliga. En nyckelfördelning som var ungefär jämn vid lansering kan drifta när användningsmönster ändras (en kund, en region, en händelsetyp börjar dominera volymen).
Så kontrollerar du det: i Spark UI:s Stage-detaljvy, sortera tasks efter varaktighet. Ett steg där p50-tasken tar 4 sekunder och den längsta tasken tar 6 minuter är skevt, punkt slut.
3. Klustret är inte klustret du testade på
Autoskalande kluster, spot-instanspooler och delade multi-tenant-kluster kan alla tyst ge ditt jobb färre eller långsammare executorer än förra gången, särskilt vid konkurrens från andra jobb. Detta visar sig som längre väggklockstid med identisk CPU-tid per task — jobbet gör samma mängd arbete, väntar bara längre på resurser för att göra det.
Så kontrollerar du det: jämför antalet faktiskt tilldelade (inte begärda) executorer mellan körningar, och titta på schemaläggningsfördröjning, inte bara taskvaraktighet.
Snabbaste sättet att skilja dem åt: du behöver två saker sida vid sida — din aktuella konfiguration och riktiga mätvärden från körningen som faktiskt skedde. Det är hela idén bakom opti-pipes regelmotor: den läser din eventloggs faktiska task-timing, shuffle-volym och minnesanvändning och kontrollerar det mot dina konfigurerade shuffle-partitioner / executor-minne / instansantal — istället för att du stirrar på Spark UI och gissar vilken av de tre ovan det är.
Se hur det här ser ut i din egen pipeline.
Ladda upp en riktig Spark-eventlogg, en dbt run_results.json eller en Flink-mätexport och få konkreta rekommendationer att godkänna innan de tillämpas — inte ännu en tumregel.