Foto's lijken fris, totdat ze dat niet meer zijn.
Elke query-gebaseerde connector die gegevens leest uit een Databricks Delta-tabel, werkt met een snapshot. Deze snapshot is een consistente weergave van de tabel op een specifieke Delta-logversie. De connector opent een sessie, bepaalt de meest recente versie, leest de Parquet-bestanden waarnaar die versie verwijst en retourneert de resultaatset. Dit is de isolatiegarantie die Delta Lake biedt, en het werkt goed – totdat het lezen te lang duurt.
Het probleem doet zich voor in een specifieke volgorde. Een connector begint met het lezen van versie 47 van een tabel. Het lezen verloopt traag, mogelijk omdat de tabel groot is, het datawarehouse onder druk staat of de pagineringslogica van de connector zelf extra overhead veroorzaakt. Terwijl het lezen bezig is, schrijft een upstream-pipeline nieuwe gegevens, waardoor de tabel wordt bijgewerkt naar versie 52. Een VACUUM-bewerking wordt volgens schema uitgevoerd en verwijdert Parquet-bestanden waarnaar binnen het bewaarvenster geen enkele versie meer verwijst. Als de bestanden van versie 47 worden opgeschoond voordat de connector klaar is met lezen, mislukt het lezen met een FileNotFoundException of, in sommige JDBC/ODBC-connector implementaties, wordt een afgekorte resultaatset zonder foutmelding aan de aanroeper getoond.
De standaardwaarde voor delta.deletedFileRetentionDuration is 7 dagen. Dat klinkt ruim. Maar connector taken die volgens een schema worden uitgevoerd – bijvoorbeeld een Power BI dataset die elke 30 minuten wordt vernieuwd op basis van een Databricks SQL-datawarehouse – bepalen niet wanneer VACUUM wordt uitgevoerd. Als een beheerder of een onderhoudstaak agressief opschoont met een kortere bewaartijd, verdwijnt de veiligheidsmarge. De connector weet pas dat de snapshot bestanden zijn verwijderd wanneer hij ze probeert te lezen.
VERSION AS OF faalt stilzwijgend in connector contexten.
Met Delta Lake time travel kunt je de syntaxen VERSION AS OF en TIMESTAMP AS OF gebruiken voor expliciete toegang tot momentopnamen. Deze zijn krachtig voor ad-hoc analyses en reproduceerbare query's. Maar wanneer een query-gebaseerde connector time travel gebruikt, verschuift de kans op fouten van 'lezen kan mislukken' naar 'lezen kan slagen met verouderde gegevens en niemand merkt het'.
Neem bijvoorbeeld een connector die is geconfigureerd met een query zoals SELECT * FROM sales_facts VERSION AS OF 100. Deze query is ingesteld toen versie 100 actueel was. Weken later is de tabel bijgewerkt naar versie 340. De connector retourneert nog steeds versie 100, zonder enige fout of waarschuwing. De gebruikers van het dashboard zien gegevens die intern consistent zijn, maar weken achterlopen op de werkelijkheid.
Dit gebeurt vaker dan zou moeten, met name in partnerconnectorconfiguraties waar de query is ingebed in een verbindingsreeks of een opgeslagen querydefinitie die niet opnieuw wordt gebruikt. De discussie op het Databricks-communityforum over dit onderwerp benadrukt precies deze verwarring: gebruikers verwachten dat de connector zich gedraagt als een live query, maar de snapshot-semantiek betekent dat deze precies retourneert wat is opgevraagd, zelfs wanneer dat niet langer nuttig is.
De standaardwaarde van 30 dagen voor delta.logRetentionDuration zorgt voor nog een extra probleem. Zodra de logvermelding voor versie 100 verloopt, mislukt de query met een AnalysisException: Cannot time travel Delta table to version 100. Op dat moment loopt de connector volledig vast, maar de wekenlange stille veroudering was de werkelijke oorzaak van de problemen.
Voor connectors die geen expliciete time travel gebruiken, maar wel queryplannen of verbindingsmetadata cachen, bestaat een vergelijkbaar probleem. Sommige JDBC-stuurprogramma's cachen de opgeloste snapshot versie op het moment van verbinding maken. Als de verbindingspool een verouderde verbinding hergebruikt, lezen volgende query's uit de oude snapshot zonder de huidige versie opnieuw op te lossen.
De optie 'Datafeed wijzigen' lost het verbindingsprobleem niet op.
De Change Data Feed (CDF) van Delta Lake is de aanbevolen methode voor incrementele verwerking. Schakel deze in met ALTER TABLE SET TBLPROPERTIES (delta.enableChangeDataFeed = true) en je krijgt tracking van wijzigingen op rijniveau met de metadatakolommen _change_type, _commit_version en _commit_timestamp. Gebruikers van Structured Streaming kunnen readChangeFeed gebruiken om alleen nieuwe wijzigingen te verwerken.
Maar query-gebaseerde connectors — de JDBC/ODBC-verbindingen die worden gebruikt door Power BI, Tableau en aangepaste ETL-scripts — ondersteunen geen Structured Streaming. Ze voeren SQL-query's uit en lezen resultaatsets. CDF is voor hen alleen beschikbaar via batch query's zoals SELECT * FROM table_changes('sales_facts', 45, 52), waarbij de connector zijn eigen hoogste waarde moet bijhouden: de laatst succesvol gelezen versie.
Dit is waar de meeste implementaties mislukken. De connector heeft duurzaam statusbeheer nodig voor dat watermerk. Als de connector crasht na het lezen van wijzigingen, maar voordat het nieuwe watermerk is opgeslagen, leest hij de gegevens opnieuw (dupliceert ze) of slaat hij een stap over (gegevensverlies). Als het watermerk verwijst naar een versie die is verwijderd, mislukt de CDF-query met een foutmelding dat de versie niet beschikbaar is.
Uit de Stack Overflow Developer Survey van 2024 blijkt dat Databricks SQL door 1,9% van alle respondenten wordt gebruikt. Dat is een kleine, maar groeiende gebruikersgroep, en veel van deze gebruikers verbinden Databricks met downstream-tools via precies deze query-gebaseerde patronen. De connectorlaag is de zwakste schakel in de pipeline, maar tegelijkertijd ook de minst gecontroleerde. Databricks toont de querygeschiedenis in de SQL Warehouse UI, maar fouten aan de connector zijde – time-outs, gedeeltelijke leesbewerkingen, verouderde watermerken – blijven buiten die zichtbaarheid.
CDF heeft bovendien een beperking die teams vaak verrast: alleen wijzigingen die na de activering zijn aangebracht, worden geregistreerd. Als je CDF inschakelt voor een bestaande tabel en een connector probeert wijzigingen te lezen van vóór de inschakeling, retourneert de query niets. De connector meldt succes met nul rijen en de downstreamtabel blijft leeg.
Clusterautomatische beëindiging verbreekt langlopende leesbewerkingen.
Databricks-clusters en SQL-datawarehouses hebben een automatische stopfunctie. Interactieve clusters stoppen standaard na 120 minuten inactiviteit. SQL-datawarehouses kunnen worden geconfigureerd tot 5 minuten. Een query-gebaseerde connector die een sessie opent, een grote leesbewerking start en vervolgens pauzeert – in afwachting van de client die door de resultaten bladert – kan merken dat het cluster halverwege de overdracht wordt beëindigd.
De ervaring van de connector hangt af van de implementatie. Goed ontworpen JDBC-drivers detecteren de verbroken verbinding en gooien een IOException. Eenvoudigere HTTP-gebaseerde connectors ontvangen mogelijk een gedeeltelijke respons en beschouwen deze als volledig. De Databricks SQL-connector voor Python gebruikt bijvoorbeeld Arrow-gebaseerde resultaatsets die in stukken worden opgehaald uit cloudopslag. Als het datawarehouse wordt afgesloten nadat het resultaat is gegenereerd, maar voordat de client alle stukken heeft gedownload, krijgt de client een afgekorte dataset.
De oplossing lijkt eenvoudig: verhoog de time-out voor de automatische stop. Maar dat kost geld. Een SQL-datawarehouse dat 24/7 draait met een gemiddelde omvang kan gemakkelijk meer dan $ 2.000 per maand aan DBU-kosten met zich meebrengen. Teams stellen agressieve automatische stopbeleidsregels in om de kosten te beheersen en vragen zich vervolgens af waarom hun connector taken 's nachts onvolledige gegevens produceren.
Een robuustere aanpak is om de query-uitvoering los te koppelen van het verwerken van de resultaten. Gebruik CREATE TABLE AS SELECT of INSERT OVERWRITE om de query van de connector te materialiseren in een stagingtabel, waarna de connector de gegevens uit die stagingtabel leest. Het compute-cluster hoeft alleen actief te blijven voor de schrijfbewerking, niet voor de trage download van de client. De stagingtabel is een stabiele Delta-snapshot die niet wordt beïnvloed door het VACUUM-schema van de brontabel.
Dit patroon voegt complexiteit toe — een extra tabel om te beheren, een extra taak om in te plannen, een extra factor die kan falen — maar het elimineert de twee meest voorkomende faalmodi van connectors: het beëindigen van het cluster tijdens het lezen en het opschonen van snapshot bestanden.
Door de versieverschillen te monitoren, worden verouderde versies vroegtijdig opgespoord.
Het operationele signaal dat ertoe doet, is het verschil tussen de momentopnameversie die een connector daadwerkelijk heeft gelezen en de huidige versie van de brontabel. Delta Lake geeft dit weer via DESCRIBE HISTORY table_name, die elke commitversie retourneert met de bijbehorende tijdstempel en bewerkingstype. De huidige versie is de maximale versie.
Als je connector job de versie die is gebruikt registreert (via het Delta-logboek of een query zoals SELECT MAX(_commit_version) FROM table_changes(...)), kunt je de achterstand berekenen: huidige versie min de gebruikte versie. Een achterstand van nul betekent dat de connector de meest recente gegevens heeft gelezen. Een achterstand van 5 kan normaal zijn als de tabel regelmatig kleine schrijfbewerkingen ondergaat. Een achterstand van 200 betekent dat er dagen geleden iets mis is gegaan en niemand het heeft gemerkt.
De meeste teams monitoren dit niet. De connector job slaagt of faalt, en succes wordt beschouwd als 'gegevens zijn actueel'. Deze aanname is de hoofdoorzaak van verouderde dashboard incidenten die uren duren om te diagnosticeren, omdat elk systeem groen rapporteert.
MetricSign monitort de uitvoering van Databricks-taken en kan detecteren wanneer downstream-verversingstaken zijn voltooid, maar de gegenereerde gegevens niet daadwerkelijk zijn bijgewerkt. Het signaal refresh_delayed wordt niet geactiveerd bij een mislukte taak – die zijn eenvoudig te detecteren – maar bij een succesvolle taak waarbij de resulterende gegevens ouder zijn dan verwacht. Dat is de kloof tussen 'de pipeline is uitgevoerd' en 'de pipeline heeft actuele gegevens geleverd', en dat is precies waar de veroudering van de snapshot-connector zich schuilhoudt.
Voor teams die de versiekloof niet direct kunnen meten, werkt een eenvoudigere proxy: houd de maximale tijdstempel bij van een bekende, monotoon stijgende kolom in de doeltabel. Als die tijdstempel niet meer oploopt bij opeenvolgende connector uitvoeringen, leest de connector verouderde snapshots. Stel een waarschuwingsdrempel in op basis van de normale schrijffrequentie van je tabel, en je detecteert het probleem voordat een stakeholder een dashboard opent en de cijfers van afgelopen dinsdag ziet.