Passa al contenuto principale

Immersione in Delta Lake: analisi del log delle transazioni

Diving Into Delta Lake: Unpacking The Transaction Log

Pubblicato: 21 agosto 2019

Prodotto10 min di lettura

Logo di Delta Lake.
Il log delle transazioni è fondamentale per comprendere Delta Lake perché è il filo conduttore che attraversa molte delle sue funzionalità più importanti, tra cui le transazioni ACID, la gestione scalabile dei metadati, il time travel e altro ancora. In questo articolo, esploreremo cos'è il log delle transazioni di Delta Lake, come funziona a livello di file e come offre un'elegante soluzione al problema di più letture e scritture simultanee.

Cos'è il log delle transazioni di Delta Lake?

Il log delle transazioni di Delta Lake (noto anche come DeltaLog) è un record ordinato di ogni transazione che è stata eseguita su una tabella Delta Lake dalla sua creazione.

A cosa serve il log delle transazioni?

Unica fonte di verità

Delta Lake è basato su Apache Spark™ per consentire a più lettori e scrittori di una determinata tabella di lavorare contemporaneamente sulla tabella. Per mostrare agli utenti visualizzazioni corrette dei dati in ogni momento, il log delle transazioni di Delta Lake funge da unica fonte di verità, ovvero il repository centrale che tiene traccia di tutte le modifiche apportate dagli utenti alla tabella.

Quando un utente legge una tabella Delta Lake per la prima volta o esegue una nuova query su una tabella aperta che è stata modificata dall'ultima volta che è stata letta, Spark controlla il log delle transazioni per vedere quali nuove transazioni sono state pubblicate nella tabella, quindi aggiorna la tabella dell'utente finale con tali nuove modifiche. Ciò garantisce che la versione di una tabella di un utente sia sempre sincronizzata con il record master a partire dalla query più recente e che gli utenti non possano apportare modifiche divergenti e in conflitto a una tabella.

L'implementazione dell'atomicità su Delta Lake

Una delle quattro proprietà delle transazioni ACID, l'atomicità, garantisce che le operazioni (come INSERT o UPDATE) eseguite sul tuo data lake vengano completate completamente oppure non vengano completate affatto. Senza questa proprietà, è fin troppo facile che un guasto hardware o un bug software causino la scrittura parziale dei dati in una tabella, causando dati disordinati o danneggiati.

Il log delle transazioni è il meccanismo attraverso il quale Delta Lake è in grado di offrire la garanzia di atomicità. A tutti gli effetti, se non è registrato nel log delle transazioni, non è mai successo. Registrando solo le transazioni che vengono eseguite completamente e utilizzando tale record come unica fonte di verità, il log delle transazioni di Delta Lake consente agli utenti di ragionare sui propri dati e di avere la tranquillità della sua fondamentale affidabilità, su scala di petabyte.

Come funziona il log delle transazioni?

Suddivisione delle transazioni in commit atomici

Ogni volta che un utente esegue un'operazione per modificare una tabella (come INSERT, UPDATE o DELETE), Delta Lake suddivide tale operazione in una serie di passaggi discreti composti da una o più delle azioni seguenti.

  • Aggiungi file: aggiunge un file di dati.
  • Rimuovi file: rimuove un file di dati.
  • Aggiorna metadati: aggiorna i metadati della tabella (ad esempio, modifica del nome, dello schema o del partizionamento della tabella).
  • Imposta transazione: registra che un processo di streaming strutturato ha eseguito il commit di un micro-batch con l'ID specificato.
  • Cambia protocollo: abilita nuove funzionalità passando il log delle transazioni di Delta Lake al protocollo software più recente.
  • Informazioni sul commit: contiene informazioni sul commit, sull'operazione eseguita, da dove e a che ora.

Tali azioni vengono quindi registrate nel log delle transazioni come unità atomiche ordinate note come commit.

Ad esempio, supponiamo che un utente crei una transazione per aggiungere una nuova colonna a una tabella e aggiungere altri dati. Delta Lake suddividerebbe tale transazione nelle sue parti componenti e, una volta completata la transazione, le aggiungerebbe al log delle transazioni come i seguenti commit:

  1. Aggiorna metadati: modifica lo schema per includere la nuova colonna
  2. Aggiungi file: per ogni nuovo file aggiunto

Il log delle transazioni di Delta Lake a livello di file

Quando un utente crea una tabella Delta Lake, il log delle transazioni di tale tabella viene creato automaticamente nella sottodirectory _delta_log. Man mano che apporta modifiche a tale tabella, tali modifiche vengono registrate come commit atomici ordinati nel log delle transazioni. Ogni commit viene scritto come file JSON, a partire da 000000.json. Ulteriori modifiche alla tabella generano file JSON successivi in ordine numerico crescente in modo che il commit successivo venga scritto come 000001.json, il successivo come 000002.json e così via.

Diagramma della struttura dei file di log delle transazioni di Delta Lake.

Quindi, ad esempio, potremmo aggiungere record aggiuntivi alla nostra tabella dai file di dati 1.parquet e 2.parquet. Tale transazione verrebbe automaticamente aggiunta al log delle transazioni, salvata su disco come commit 000000.json. Quindi, forse cambiamo idea e decidiamo di rimuovere tali file e aggiungere invece un nuovo file (3.parquet). Tali azioni verrebbero registrate come commit successivo nel log delle transazioni, come 000001.json, come mostrato di seguito.

Diagramma che illustra due commit che eseguono operazioni sullo stesso file.

Anche se 1.parquet e 2.parquet non fanno più parte della nostra tabella Delta Lake, la loro aggiunta e rimozione sono comunque registrate nel log delle transazioni perché tali operazioni sono state eseguite sulla nostra tabella, nonostante il fatto che alla fine si siano annullate a vicenda. Delta Lake conserva ancora commit atomici come questi per garantire che, nel caso in cui sia necessario controllare la nostra tabella o utilizzare il "time travel" per vedere come appariva la nostra tabella in un determinato momento, potremmo farlo con precisione.

Inoltre, Spark non rimuove immediatamente i file dal disco, anche se abbiamo rimosso i file di dati sottostanti dalla nostra tabella. Gli utenti possono eliminare i file che non sono più necessari utilizzando VACUUM.

Ricalcolo rapido dello stato con i file di checkpoint

Una volta che abbiamo eseguito diversi commit nel log delle transazioni, Delta Lake salva un file di checkpoint in formato Parquet nella stessa sottodirectory _delta_log. Delta Lake genera automaticamente il checkpoint in base alle necessità per mantenere buone prestazioni di lettura.

Diagramma che illustra la struttura dei file di log delle transazioni di Delta Lake, incluse le directory di partizione.

Questi file di checkpoint salvano l'intero stato della tabella in un determinato momento, in formato Parquet nativo che è facile e veloce da leggere per Spark. In altre parole, offrono al lettore Spark una sorta di "scorciatoia" per riprodurre completamente lo stato di una tabella che consente a Spark di evitare di rielaborare quelli che potrebbero essere migliaia di piccoli file JSON inefficienti.

Per accelerare i tempi, Spark può eseguire un'operazione listFrom per visualizzare tutti i file nel log delle transazioni, passare rapidamente al file di checkpoint più recente ed elaborare solo i commit JSON eseguiti dall'ultimo salvataggio del file di checkpoint.

Per dimostrare come funziona, immaginiamo di aver creato commit fino a 000007.json come mostrato nel diagramma seguente. Spark è aggiornato tramite questo commit, avendo memorizzato automaticamente nella cache la versione più recente della tabella in memoria. Nel frattempo, però, diversi altri scrittori (forse i tuoi compagni di squadra troppo entusiasti) hanno scritto nuovi dati nella tabella, aggiungendo commit fino a 0000012.json.

Per incorporare queste nuove transazioni e aggiornare lo stato della nostra tabella, Spark eseguirà quindi un'operazione listFrom version 7 per vedere le nuove modifiche alla tabella.

Diagramma che illustra come Spark legge i file di checkpoint recenti per calcolare rapidamente lo stato della tabella.

Invece di elaborare tutti i file JSON intermedi, Spark può passare al file di checkpoint più recente, poiché contiene l'intero stato della tabella al commit n. 10. Ora, Spark deve solo eseguire l'elaborazione incrementale di 0000011.json e 0000012.json per avere lo stato corrente della tabella. Spark quindi memorizza nella cache la versione 12 della tabella in memoria. Seguendo questo flusso di lavoro, Delta Lake è in grado di utilizzare Spark per mantenere lo stato di una tabella aggiornato in ogni momento in modo efficiente.

Gestione di più letture e scritture simultanee

Ora che abbiamo capito come funziona il log delle transazioni di Delta Lake ad alto livello, parliamo di concorrenza. Finora, i nostri esempi hanno riguardato principalmente scenari in cui gli utenti eseguono il commit delle transazioni in modo lineare o almeno senza conflitti. Ma cosa succede quando Delta Lake ha a che fare con più letture e scritture simultanee?

La risposta è semplice. Poiché Delta Lake è alimentato da Apache Spark, non solo è possibile per più utenti modificare una tabella contemporaneamente, ma è previsto. Per gestire queste situazioni, Delta Lake utilizza il controllo della concorrenza ottimistico.

Cos'è il controllo della concorrenza ottimistico?

Il controllo della concorrenza ottimistico è un metodo per gestire le transazioni simultanee che presuppone che le transazioni (modifiche) apportate a una tabella da utenti diversi possano essere completate senza entrare in conflitto tra loro. È incredibilmente veloce perché quando si ha a che fare con petabyte di dati, c'è un'alta probabilità che gli utenti lavorino del tutto su parti diverse dei dati, consentendo loro di completare contemporaneamente transazioni non conflittuali.

Ad esempio, immagina che io e te stiamo lavorando insieme a un puzzle. Finché stiamo lavorando entrambi su parti diverse, tu sugli angoli e io sui bordi, ad esempio, non c'è motivo per cui non possiamo lavorare entrambi sulla nostra parte del puzzle più grande contemporaneamente e finire il puzzle due volte più velocemente. È solo quando abbiamo bisogno degli stessi pezzi, nello stesso momento, che c'è un conflitto. Questo è il controllo della concorrenza ottimistico.

Naturalmente, anche con il controllo della concorrenza ottimistico, a volte gli utenti cercano di modificare le stesse parti dei dati contemporaneamente. Fortunatamente, Delta Lake ha un protocollo per questo.

Risoluzione ottimistica dei conflitti

Per offrire transazioni ACID, Delta Lake ha un protocollo per capire come ordinare i commit (noto come concetto di serializzabilità nei database) e determinare cosa fare nel caso in cui due o più commit vengano eseguiti contemporaneamente. Delta Lake gestisce questi casi implementando una regola di mutua esclusione, quindi tentando di risolvere qualsiasi conflitto in modo ottimistico. Questo protocollo consente a Delta Lake di rispettare il principio ACID di isolamento, che garantisce che lo stato risultante della tabella dopo più scritture simultanee sia lo stesso di se tali scritture fossero avvenute in serie, isolatamente l'una dall'altra.

In generale, il processo si svolge in questo modo:

  1. Registra la versione iniziale della tabella.
  2. Registra letture/scritture.
  3. Tenta un commit.
  4. Se qualcun altro vince, controlla se qualcosa che hai letto è cambiato.
  5. Ripeti.

Per vedere come si svolge tutto questo in tempo reale, diamo un'occhiata al diagramma seguente per vedere come Delta Lake gestisce i conflitti quando si presentano. Immagina che due utenti leggano dalla stessa tabella, quindi ognuno cerchi di aggiungere alcuni dati.

Illustrazione del controllo della concorrenza ottimistico che mostra due utenti con commit in conflitto.

  • Delta Lake registra la versione iniziale della tabella (versione 0) che viene letta prima di apportare qualsiasi modifica.
  • Gli utenti 1 e 2 tentano entrambi di aggiungere alcuni dati alla tabella contemporaneamente. Qui, ci siamo imbattuti in un conflitto perché solo un commit può venire dopo ed essere registrato come 000001.json.
  • Delta Lake gestisce questo conflitto con il concetto di "mutua esclusione", il che significa che solo un utente può eseguire correttamente il commit 000001.json. Il commit dell'utente 1 viene accettato, mentre quello dell'utente 2 viene rifiutato.
  • Invece di generare un errore per l'utente 2, Delta Lake preferisce gestire questo conflitto in modo ottimistico. Controlla se sono stati eseguiti nuovi commit nella tabella e aggiorna la tabella in modo silenzioso per riflettere tali modifiche, quindi riprova semplicemente il commit dell'utente 2 sulla tabella appena aggiornata (senza alcuna elaborazione dei dati), eseguendo correttamente il commit 000002.json.

Nella stragrande maggioranza dei casi, questa riconciliazione avviene in modo silenzioso, continuo e con successo. Tuttavia, nel caso in cui ci sia un problema inconciliabile che Delta Lake non può risolvere in modo ottimistico (ad esempio, se l'utente 1 ha eliminato un file che anche l'utente 2 ha eliminato), l'unica opzione è generare un errore.

Come nota finale, poiché tutte le transazioni eseguite sulle tabelle Delta Lake vengono archiviate direttamente su disco, questo processo soddisfa la proprietà ACID di durabilità, il che significa che persisterà anche in caso di guasto del sistema.

LEADER PER LA 5ª VOLTA

Gartner®: Databricks leader dei database cloud

Altri casi d'uso

Time Travel

Ogni tabella è il risultato della somma totale di tutti i commit registrati nel log delle transazioni di Delta Lake, né più né meno. Il log delle transazioni fornisce una guida passo passo, che descrive in dettaglio esattamente come passare dallo stato originale della tabella al suo stato attuale.

Pertanto, possiamo ricreare lo stato di una tabella in qualsiasi momento iniziando con una tabella originale ed elaborando solo i commit eseguiti prima di quel punto. Questa potente capacità è nota come "time travel" o controllo delle versioni dei dati e può essere un salvavita in diverse situazioni. Per ulteriori informazioni, leggi il post del blog Introduzione al time travel di Delta per data lake su larga scala oppure consulta la documentazione sul time travel di Delta Lake.

Data Lineage e debug

Come record definitivo di ogni modifica apportata a una tabella, il log delle transazioni di Delta Lake offre agli utenti una data lineage verificabile che è utile per scopi di governance, audit e conformità. Può anche essere utilizzato per risalire all'origine di una modifica involontaria o di un bug in una pipeline all'azione esatta che l'ha causato. Gli utenti possono eseguire DESCRIBE HISTORY per visualizzare i metadati relativi alle modifiche apportate.

Riepilogo del log delle transazioni di Delta Lake

In questo blog, abbiamo approfondito i dettagli di come funziona il log delle transazioni di Delta Lake, tra cui:

  • Cos'è il log delle transazioni, come è strutturato e come i commit vengono archiviati come file su disco.
  • Come il log delle transazioni funge da unica fonte di verità, consentendo a Delta Lake di implementare il principio di atomicità.
  • Come Delta Lake calcola lo stato di ogni tabella, incluso come utilizza il log delle transazioni per recuperare dall'ultimo checkpoint.
  • Utilizzo del controllo della concorrenza ottimistico per consentire più letture e scritture simultanee anche quando le tabelle cambiano.
  • Come Delta Lake utilizza la mutua esclusione per garantire che i commit vengano serializzati correttamente e come vengono ritentati in modo silenzioso in caso di conflitto.
Ti interessa l'open source Delta Lake?
Visita l'hub online di Delta Lake per saperne di più, scaricare l'ultimo codice e unirti alla community di Delta Lake.

Correlati

Articoli di questa serie:
Immersione in Delta Lake n. 1: Disimballaggio del log delle transazioni
Immersione in Delta Lake n. 2: Applicazione ed evoluzione dello schema
Immersione in Delta Lake n. 3: Elementi interni DML (Aggiorna, Elimina, Unisci)

Articoli correlati:
Cos'è un data lake?
Produzione di Machine Learning con Delta Lake

(Questo post sul blog è stato tradotto utilizzando strumenti basati sull'intelligenza artificiale) Post originale

Non perdere mai un post di Databricks

Iscriviti al nostro blog e ricevi gli ultimi post direttamente nella tua casella di posta elettronica.