MetricSign
NL|ENStart free →
Data Observability9 min·

Je Databricks job slaagde voor elke test en mislukte toch om 3 uur ’s nachts

De Databricks community viert indrukwekkende builds. Production clusters interesseert het niet hoe slim je notebook was — het enige wat telt is of je spot instances lang genoeg hebben overleefd om de job af te ronden.

Read this article in English →

Spot instances worden midden in een shuffle teruggevorderd en de foutmelding zegt niets bruikbaars

Elke kostenbesparende Databricks deployment gebruikt spot instances voor worker nodes. AWS trekt ze terug met twee minuten waarschuwing. Azure geeft dertig seconden.

Wanneer een spot node midden in een taak verdwijnt, herprobeert Spark de taak op de overgebleven executors. Dat werkt, totdat de teruggevorderde node shuffle data bevatte waar andere taken van afhankelijk zijn.

De foutmelding die je ziet is FetchFailedException: Failed to connect to host. Niet 'je spot instance is teruggevorderd'. Niet 'probeer on-demand nodes'. Een network fetch fout die eruitziet als een tijdelijke storing. Teams herstarten de job, stoten op hetzelfde reclamation window en proberen het opnieuw.

De oplossing hangt af van de schaal. Voor jobs onder de 2 uur zorgt spark.speculation op true zetten en spot instances met fallback naar on-demand (first_on_demand: 1 in cluster policy) ervoor dat de driver stabiel blijft terwijl worker churn getolereerd wordt. Voor langlopende jobs (alles met grote shuffles of het schrijven van honderden Delta partitions) kosten on-demand workers minder dan drie herpogingen van een job van 4 uur op spot-tarieven.

Databricks heeft in 2024 spot fall-back policies toegevoegd, maar de standaard cluster configuratie gebruikt nog steeds alleen spot voor workers. Als je je job template vóór die update hebt aangemaakt, draai je op de oude standaard. Controleer je cluster policy JSON op aws_attributes.availability of azure_attributes.availability. Als het SPOT of SPOT_WITH_FALLBACK_AZURE zegt, loop je risico. Verander het naar SPOT_WITH_FALLBACK op AWS of ON_DEMAND_AZURE voor kritieke nachtjobs.

Het patroon is voorspelbaar: spot reclamation rates schieten omhoog tijdens kantooruren in de US-East en EU-West regio's wanneer de algemene compute vraag stijgt. Je job om 2 uur EST die maandenlang zonder problemen liep, begint te mislukken wanneer klanten van andere cloudproviders hun ochtend workloads opschalen in overlappende tijdzones.

Autoscaling voegt workers te laat toe en je job raakt de timeout

Databricks autoscaling kijkt naar het aantal openstaande taken en voegt workers toe wanneer de achterstand de capaciteit overschrijdt. Het probleem: een nieuwe node provisionen, libraries installeren en registreren bij de Spark driver duurt 3-7 minuten op AWS en 5-12 minuten op Azure. Voor bursty workloads (jobs die plotseling 10x zoveel executors nodig hebben voor een grote join) arriveren de extra workers nadat de stage al minuten lang met verminderde parallelisme heeft gedraaid.

In development draaide je de job op een interactive cluster dat al warm was met 8 nodes. In productie start de job cluster met min_workers: 2 en max_workers: 20. De eerste stages lopen goed. Dan komt de brede transformatie, Spark plant 200 taken over 2 workers en de autoscaler begint 18 extra nodes aan te vragen. De helft van die aanvragen mislukt omdat de instance pool koud is of de cloudregio capaciteitsproblemen heeft. Je job ploetert door met 6 workers in plaats van 20, duurt drie keer zo lang als verwacht en raakt de timeout_seconds die je hebt ingesteld op basis van de development run.

De foutmelding is Run exceeded timeout of 7200 seconds. Niets wijst op autoscaling als root cause.

Twee aanpakken werken daadwerkelijk. Gebruik ten eerste instance pools met idle instances ingesteld op min_idle_instances: 4. Dit houdt warme nodes beschikbaar en verkort de provisioning tijd tot minder dan 90 seconden. Stel ten tweede autoscale.min_workers dichter bij je werkelijke steady-state behoefte in dan op het minimum. De kosten van 6 idle nodes gedurende 10 minuten voor de job start zijn verwaarloosbaar vergeleken met een mislukte job van 2 uur die volledig opnieuw moet worden gestart.

Uit de Stack Overflow 2024 survey blijkt dat slechts 1,9% van de professionele developers Databricks SQL gebruikt, wat betekent dat de meeste Databricks productie workloads Spark jobs zijn die worden beheerd door kleine gespecialiseerde teams. Wanneer de ene engineer die de cluster config heeft afgesteld vertrekt, driften deze instellingen weg.

Databricks productie failure classes en hun oplossingen Spot Reclamation FetchFailedException Shuffle data verloren midden in stage Fix: SPOT_WITH_FALLBACK + first_ Fix: On-demand voor jobs > 2 uur Autoscaling Delay Run exceeded timeout Workers provisioned 3-12 min te laat Fix: Instance pools with min_idl Fix: Set min_workers to steady-s Delta Concurrency ConcurrentAppendException ConcurrentDeleteReadException Fix: idempotent_token on retries Fix: Staging table with atomic s
Databricks productie failure classes en hun oplossingen

Delta concurrent write conflicts escaleren wanneer je de mislukte job herstart

Delta Lake's ACID transacties gebruiken optimistic concurrency control. Twee jobs die tegelijkertijd naar dezelfde tabel schrijven slagen allebei, tenzij hun operaties conflicteren. Een ConcurrentAppendException betekent dat twee commits probeerden bestanden toe te voegen aan dezelfde partition. Een ConcurrentDeleteReadException betekent dat één job bestanden heeft gelezen die een andere job heeft verwijderd (via MERGE of DELETE).

In development draai je één job tegelijk. In productie overlapt de nachtelijke ingestion job met de vertraagd lopende transformatie van de dag ervoor. Of de herstart van de mislukte job van 2 uur botst met de job van 6 uur die dezelfde tabel leest.

En dan wordt het nog erger. Het standaard herstart-gedrag in Databricks Workflows herstart de volledige job vanaf het begin. Als de job bij taak 847 van 900 is mislukt door een tijdelijke spot reclamation, worden bij de herstart alle 900 taken opnieuw uitgevoerd, inclusief de schrijfacties die al naar Delta zijn gecommit. Die schrijfacties conflicteren nu met de gedeeltelijk gecommitte data van de eerste poging.

Voor ConcurrentAppendException is de oplossing partition isolation: zorg dat gelijktijdige writers verschillende partitions als doel hebben door replaceWhere te gebruiken met niet-overlappende predicaten. Voor ConcurrentDeleteReadException tijdens MERGE operaties schakel je spark.databricks.delta.merge.repartitionBeforeWrite.enabled in om het conflict surface op bestandsniveau te verkleinen.

Maar de echte oplossing is architectureel. Herstart schrijf-intensieve jobs niet blind. Gebruik idempotent_token op Databricks job runs (beschikbaar sinds eind 2025) om herstarts veilig te maken, of ontwerp je pipeline met een staging table patroon waarbij elke run naar een uniek pad schrijft en een finale atomaire RENAME het resultaat op zijn plek zet. De herstart overschrijft het staging pad dan zonder schade.

De commit log in _delta_log vertelt je precies welke transactie heeft gecolliseerd en wanneer. Maar alleen als je kijkt voordat de volgende succesvolle run de log compacteert.

Unity Catalog permissions propageren met vertraging die tests nooit blootleggen

Unity Catalog heeft workspace-niveau access controls vervangen door een gecentraliseerde governance laag. Permission grants propageren via een distributed cache. In de praktijk duurt het 30-120 seconden voordat een GRANT SELECT ON TABLE catalog.schema.table TO group effectief is op alle clusters in de workspace.

Je CI/CD pipeline verleent permissions in stap 3 en draait de integratietest in stap 4. In de testomgeving met één cluster is de propagation binnen 5 seconden voltooid. In productie met 40 gelijktijdige clusters duurt het 90 seconden. De test slaagt. De productie job (die na de deployment een nieuw cluster start) stuit op AnalysisException: User does not have permission to SELECT on table.

Dit mislukt met tussenpozen, wat de lastigste soort failure is. Dezelfde job slaagt bij de herstart omdat de permission dan al is gepropageerd. Teams noemen het flaky en voegen een herstart toe. De herstart maskeert het probleem totdat een job twee permission-afhankelijke stappen heeft en de herstart alleen opnieuw uitvoert vanaf de mislukte stap, waarbij de stale permission cache van de eerste stap intact blijft.

De oplossing is een permissions warm-up query. Voer na het verlenen van permissions in je deployment script een SELECT 1 FROM catalog.schema.table LIMIT 1 uit met de service principal die de productie job zal draaien. Wacht tot dit slaagt met een lus van 3 herstarts en 30 seconden backoff. Dit dwingt de permission in de cache van ten minste één cluster, en volgende clusters erven van de metastore cache in plaats van te wachten op volledige propagation.

Controleer ook de system.access.audit logs. Unity Catalog logt elke permission check. Als je DENIED entries ziet gevolgd door ALLOWED entries voor dezelfde principal en tabel binnen minuten, heb je een propagation timing probleem, geen fout in de configuratie.

De monitoring gap tussen job status en werkelijke data freshness

Databricks Workflows rapporteert job status: succeeded, failed, timed out of cancelled. Wat het niet rapporteert is of de job die slaagde daadwerkelijk de data heeft geproduceerd die je downstream consumenten verwachten.

Een job kan slagen terwijl hij nul rijen schrijft omdat de brontabel leeg was. Hij kan slagen terwijl hij stilletjes 40% van de records negeert door een schema evolution die een niet-nullable kolom naar nullable heeft geconverteerd. Hij kan 90 minuten te laat slagen door de hierboven beschreven autoscaling vertragingen, terwijl elk dashboard dat op die data vertrouwt stale cijfers toont tot en met de ochtendstandup.

De Databricks job run API (/api/2.1/jobs/runs/get) geeft result_state: SUCCESS terug in al deze gevallen. De run duur is beschikbaar, maar er is geen ingebouwde alerting voor 'deze job duurt gewoonlijk 45 minuten en vandaag duurde het 130 minuten'. Je zou dat zelf moeten bouwen door de runs list API op te vragen, een rolling average te berekenen en een drempelwaarde in te stellen.

MetricSign maakt verbinding met je Databricks workspace en volgt job execution patronen. Niet alleen pass/fail, maar ook duration anomalies en vertraagde completions. Wanneer een job die normaal voor 5:15 uur klaar is om 6:30 uur nog loopt, stuurt MetricSign een refresh_delayed signaal voordat de job een timeout krijgt of je stakeholders stale dashboards opmerken. Dat vroege signaal is het verschil tussen consumenten proactief informeren en achteraf uitleggen waarom het rapport van 8 uur de cijfers van gisteren liet zien.

De operationele realiteit voor de meeste Databricks teams: de job is geslaagd, de data klopt niet en niemand weet het totdat iemand een dashboard opent en ziet dat de cijfers niet zijn veranderd. Die kloof tussen job status en data freshness is waar het vertrouwen in productie verslechtert.

Veelgestelde vragen

Waarom mislukt mijn Databricks job met FetchFailedException alleen in productie?+
FetchFailedException treedt typisch op wanneer een Spark executor met shuffle data onbereikbaar wordt. In productie betekent dit doorgaans dat een spot instance is teruggevorderd door de cloudprovider. De foutmelding vermeldt de spot reclamation niet. Het rapporteert een network fetch failure. Controleer de availability instelling van je cluster policy: als die ingesteld is op SPOT zonder fallback, kunnen worker nodes op elk moment worden teruggevorderd. Stel first_on_demand in op ten minste 1 om de driver op een stabiele node te houden en gebruik SPOT_WITH_FALLBACK voor worker nodes op kritieke jobs.
Hoe voorkom ik ConcurrentAppendException bij het herstarten van mislukte Databricks jobs?+
ConcurrentAppendException treedt op wanneer twee transacties tegelijkertijd bestanden proberen toe te voegen aan dezelfde Delta partition. Job herstarts veroorzaken dit wanneer de oorspronkelijke run gedeeltelijk data heeft gecommit voordat hij mislukte en de herstart probeert dezelfde partitions opnieuw te schrijven. Gebruik idempotent_token op job runs om herstarts veilig te maken, of gebruik een staging table patroon waarbij elke run naar een uniek tijdelijk pad schrijft en het resultaat atomair naar de doeltabel verplaatst.
Waarom werken Unity Catalog permissions in tests maar mislukken ze met tussenpozen in productie?+
Unity Catalog permission grants propageren via een distributed cache die 30-120 seconden kan duren om alle clusters in een workspace te bereiken. Testomgevingen met minder clusters zien bijna directe propagation. Productieomgevingen met veel gelijktijdige clusters ervaren vertragingen. Voeg een warm-up query toe na het verlenen van permissions: voer SELECT 1 FROM de doeltabel uit met de productie service principal met herstarts en backoff. Controleer system.access.audit logs op DENIED-then-ALLOWED patronen om propagation timing te bevestigen.

Gerelateerde integraties

Gerelateerde artikelen