1.03k likes | 1.34k Views
Tecnologia di un Database Server. S. Costantini Dispensa per il Corso di Basi di dati e Sistemi Informativi Il materiale per queste slide e’ stato tratto da (material taken from): Phil Bernstein, Lecture notes for a graduate course on Transaction Processing at University of Washington,
E N D
Tecnologia di un Database Server S. Costantini Dispensa per il Corso di Basi di dati e Sistemi Informativi Il materiale per queste slide e’ stato tratto da (material taken from): Phil Bernstein, Lecture notes for a graduate course on Transaction Processing at University of Washington, URL http://research.microsoft.com/~philbe/
Premessa • Questa dispensa integra i contenuti della seconda parte del Capitolo 9 del Libro di Testo del Corso • Atzeni, Ceri, et al., Basi di Dati: concetti, linguaggi e architetture, McGraw-Hill editore. • Questa dispensa non sostituisce questo capitolo, che va comunque studiato.
Implementazione del Locking S. Costantini
Database Modello di un Sistema Transazione 1 Transazione N Bot, SQL Queries Commit, Abort Ottimizzatore Query Esecutore Query Scheduler Buffer Manager Recovery manager Database Server
Locking • Obiettivo: assicurare schedule serializzabili delle transazioni (vedere par. 9.1 e 9.2 del Libro di testo) • Implementazione: ritardare le operazioni che possono alterare la serializzabilita’ ponendo blocchi (locks) sui dati condivisi
Assunzione: operazioni atomiche • La Teoria del Controllo di Concorrenza considera le operazioni di Read e Write. • Quindi assume assume che esse siano atomiche • altrimenti, dovrebbe considerare le operazioni di piu’ basso livello che implementano Read e Write • Read(x) - restituisce il valore corrente di x nel DB • Write(x, val) sovrascrive x (l’intera pagina che lo contiene!) • Questa assunzione permette di astrarre l’esecuzione delle transazioni a sequenze di Read e Write
Locking • Ciascuna transazione pone un lock su ogni dato al quale intende accedere • il lock e’ una prenotazione • ci sono read locks e write locks • se una transazione ha un write lock su x, allora nessun’altra transazione puo’ avere alcun lock su x • Esempio • rli[x], rui[x], wli[x], wui[x] sono operazioni lock/unlock wl1[x] w1[x] rl2[x] r2[x] e’ impossibile • wl1[x] w1[x] wu1[x] rl2[x] r2[x] e’ OK
Il Locking di base non basta • Non garantisce la serializzabilita’ • rl1[x] r1[x] ru1[x] wl1[y] w1[y] wu1[y] c1 rl2[y] r2[y] wl2[x] w2[x] ru2[y] wu2[x] c2 • Eliminando i lock operations, abbiamo r1[x] r2[y] w2[x] c2 w1[y] c1 che non e’ serializzabile • Possibile soluzione: ogni transazione acquisisce tutti i lock all’inizio • Problema: si limita troppo la concorrenza
Two-Phase Locking (2PL) • Una transazione e’ two-phase locked (2PL) se: • prima di leggere x, pone un read lock on x • prima di scrivere x, pone un write lock on x • mantiene ciascun lock fino a dopo l’esecuzione dell’operazione sul dato • dopo il primo unlock, non puo’ porre nuovi lock • Una transazione acquisisce i lock durante la fase crescente e li rilascia nella fase calante • Esempio - a pagina precedente, T2 e’ 2PL, ma non T1 perche’ ru1[x] precede wl1[y]
Recoverability • Se Tk legge da Ti e Ti fa abort, Tk deve fare abort • Esempio - w1[x] r2[x] a1 vuol dire che T2 deve fare abort • Ma se Tk ha gia’ fatto commit? • Esempio - w1[x] r2[x] c2 a1 • T2 non puo’ fare abort dopo il commit • L’esecuzione deve essere recoverable:Il commit di una transazione T deve essere successivo al commit delle transazioni da cui legge. • Recoverable - w1[x] r2[x] c1 c2 • Non recoverable - w1[x] r2[x] c2 a1 • Si devono sincronizzare le operazioni
Evitare Abort a cascata(cascading aborts) • Per evitare aborti a cascata, lo scheduler deve assicurare che le transazioni leggano solo da transazioni che hanno fatto commit • Esempio • evita cascading aborts: w1[x] c1 r2[x] • permette cascading aborts: w1[x] r2[x] a1 • Un sistema che evita cascading aborts garantisce la recoverability.
Gestione dell’abort • Occorre annullare (undo) ogni write, w[x], ripristinando la before image (=il valore di x prima dell’esecuzione di w[x]) • Esempio - w1[x,1] scrive il valore “1” in x. • w1[x,1] w1[y,3] c1 w2[y,1] r2[x] a2 • abort T2 : si ripristina la before image of w2[y,1], = 3 • Questo non e’ sempre possibile. • Ad esempio, consideriamo w1[x,2] w2[x,3] a1 a2 • a1 & a2 non e’ implementabile mediante before images • si noti che w1[x,2] w2[x,3] a2 a1 sarebbe stato OK
Strictness • Un sistema stretto consente di eseguire ri[x] o wi[x] solo se tutte le transazioni precedenti che hanno scritto x hanno gia’ fatto commit o abort. • Esempi • stretto: w1[x] c1 w2[x] a2 • non stretto: w1[x] w2[x] … a1 a2 • stretto: w1[x] w1[y] c1 w2[y] r2[x] a2 • non stretto: w1[x] w1[y] … w2[y] a1 r2[x] a2 • “Stricness” implica “evitare cascading aborts.”
2PL e Recoverability • 2PL non garantisce la recoverability • La seguente esecuzione e’ non-recoverable, ma e’ 2PL wl1[x] w1[x] wu1[x] rl2[x] r2[x] c2 … c1 • dunque, 2PL non e’ stretta e consente cascading aborts • Per garantire la strictness bisogna che i write locks vengano rilasciato dopo commit o abort
Brain Concurrency Control • Se l’utente legge su display un output della transazione Ti , e vuole usarlo come input per la transazione Tk, deve aspettare che Ti faccia commit prima di lanciare Tk. • Solo cosi’ e’ garantito che Ti venga effettivamente serializzata prima di Tk.
Locking Automatizzato • 2PL puo’ essere reso trasparente per l’ applicazione • quando un data manager riceve una Read o Write da una transazione, emette un lock di read o write. • Come fa il data manager a sapere quando e’ ok rilasciare i locks (per essere two-phase)? • Di solito, il data manager mantiene i lock di ogni transazione finche’ essa fa commit o abort. In particolare: • rilascia i read locks appene riceve il commit • rilascia i write locks solo quando accetta il commit,per garantire la strictness
Implementazione del 2PL • Il data manager implementa il locking cosi’: • includendo un lock manager • generando un lock per ogni Read o Write • prevedendo la gestione dei deadlocks
Lock manager • Il lock manager gestisce le operazioni • Lock(trans-id, data-item-id, mode=r/w) • Unlock(trans-id, data-item-id) • Unlock(trans-id) • Memorizza i lock nella lock table. Data Item Lista Locks Lista d’attesa x [T1,r] [T2,r] [T3,w] y [T4,w] [T5,w] [T6, r]
Lock manager (cont.) • Il chiamante genera il data-item-id, applicando una funzione di hashing sul nome del dato • Infatti, la lock table e’ hashed sul data-item-id • Lock e Unlock devono essere atomici, quindi l’accesso alla lock table deve essere “locked” • Lock e Unlock vengono chiamati frequentemente. Devono essere molto veloci: < 100 istruzioni. • Non e’ facile, per via delle operazioni compare-e-swap per l’accesso atomico alla lock table
Lock manager (cont.) • In SQL Server 7.0 • I locks nella tabella occupano circa 32 bytes • Ogni lock contiene il Database-ID, Object-Id, e altre informazioni specifiche quali il record id (RID) o la chiave della tupla.
Deadlock • Un insieme di transazioni e’ in deadlock se ogni transazione e’ bloccata, e lo rimarra’ tutti’infinito se il sistema non interviene. • Esempio rl1[x] concesso rl2[y] concesso wl2[x] bloccata wl1[y] bloccata e deadlocked
Deadlock • Con il deadlock, 2PL evita le esecuzioni non serializzabili: • Ad es. rl1[x] r1[x] rl2[y] r2[y] … w2[x] w1[y] • oppure (caso della perdita di update) rl1[x] r1[x] rl2[x] r2[x] … w2[x] w1[x] • Per eliminare il deadlock: abort di una transazione • rilascio del lock senza abortire: si viola il 2PL
Prevenzione del Deadlock • Mai concedere un lock che puo’ portare al deadlock • Tecnica spesso usata nei sistemi operativi • Inutilizzabile nel 2PL, perche’ richiederebbe l’esecuzione seriale delle transazioni. • Esempio per prevenire il deadlock,rl1[x] rl2[y] wl2[x] wl1[y], il sistema nega rl2[y]
Prevenzione del Deadlock • Prevenire i deadlock non e’ praticabile in generale, perche’ pone eccessivi constraints alle applicazioni. • Porre tutti i lock in scrittura tutti’inizio delle transazioni • Previene il deadlock perche’ la transazione “parte” solo se ha tutti i dati a sua esclusiva disposizione • riduce troppo la concorrenza.
Rilevazione del Deadlock • Si cerca di rilevare i deadlock automaticamente, e si abortisce una delle transazioni (la vittima). • E’ l’approccio piu’ usato, perche’ • consente una piu’ intensiva utilizzazione delle risorse
Rilevazione del Deadlock • timeout-based deadlock detection - Se una transazione resta bloccata per troppo tempo, allora abortiscila. • Semplice ed efficiente da implementare • Ma determina aborti non necessari e • Alcuni deadlocks persistono troppo a lungo
Rilevazione Tramite Waits-for Graph • Rilevazione esplicita dei deadlock tramite un grafo chiamato Waits-for Graph • Nodi = {transazioni} • Archi = {Ti Tk | Ti attende che Tk rilasci un lock} • Esempio precedente: T1 T2 • Teorema: Se c’e un deadlock, allora il Waits-for Graph ha un ciclo.
Rilevazione tramite Waits-for Graph (cont.) • Per rilevare i deadlocks • quando una transazione si blocca, aggiungi un arco • periodicamente cerca i cicli nel Waits-for Graph • Non occorre verificare troppo spesso. (Un ciclo non scompare finche’ non lo si “rompe”) • quando si trova un deadlock, si seleziona una vittima dal ciclo e la si abortisce. • Si seleziona una vittima che ha fatto poco lavoro (ad es., ha acquisito il numero minimo di lock).
Ripartenza Ciclica • Le transazioni possono ripartire e abortire tutti’infinito. • T1 inizia. Poi T2 inizia. • vanno in deadlock, e T1 (la piu’ vecchia) e’ abortita. • T1 riparte, T2 continua, e vanno ancora in deadlock • T2 (la piu’ vecchia) e’ abortita ... • Scegliere come vittima la transazione piu’ giovane evita la ripartenza ciclica, perche’ la piu’ vecchia non viene mai abortita, e puo’ infine terminare. • Le due diverse euristiche si possono combinare
SQL Server 7.0 • Abortisce la transazione piu’ “economica” per il roll back. • La “piu’ economica” viene determinata in termini del numero di operazioni fatte (registrate nel file di log). • Permette il completamento delle transazioni che hunno fatto molto lavoro. • SET DEADLOCK_PRIORITY LOW (vs. NORMAL) permette ad un processo di designarsi da solo come vittima.
Locking distribuito • Supponiamo che una transazione possa accedere dati presso molti data managers • Ogni data manager tratta i lock nel modo usuale • Ogni transazione esegue commit o abort, nei confronti di tutti i data managers • Problema: deadlock distribuito
Deadlock distribuito Nodo 2 • Il deadlock interessa due nodi. Il nodo singolo non puo’ rilevarlo Nodo 1 rl2[y] wl1[y] (bloccata) rl1[x] wl2[x] (bloccata) • La rilevazione tramite timeout e’ la piu’ usata
Granularita’ dei Lock • Granularita’ - dimensione dei dati su cui fare lock • ad es., files, pagine, record, campi • Granularita’ grossolana implica: • pochi lock, basso locking overhead • lock su grosse porzioni di dati, alta probabilita’ di conflitti, quindi concorrenza effettiva bassa • Granularita’ sottile implica: • molti lock, alto locking overhead • conflitti solo quando due transazioni tentano di accedere concorrentemente proprio lo stesso dato
Multigranularity Locking (MGL) • Lock di differente granularita’ • grosse query fanno lock su grosse porzioni di dati (ad es. tabelle), transazioni brevi fanno lock su pochi dati (ad es. righe) • Il Lock manager non puo’ rilevare i conflitti! • ogni data item (ad es. tabella o riga) ha un differente id
Multigranularity Locking (MGL) • Multigranularity locking e’ un “trucco” • sfrutta la naturale struttura gerarchica dei dati • prima del lock su dati di basso livello, si fa un intention lock sulla struttura di piu’ alto livello che li contiene • ad es., prima di un read-lock su una, si fa un intention-read-lock sulla tabella che contiene la riga
MGL Grafi di Schema e istanza DB1 Database area A1 A2 F3 F1 F2 File Record R1.1 R1.2 R2.1 R2.2 R2.3 R2.1 R2.2 Lock di Schema Lock di istanza • Prima di un read lock su R2.3, si fa un intention-read lock su DB1, e poi A2, e poi F2 (i lock si rilasciano all’inverso)
r w ir iw riw r y n y n n w n n n n n ir y n y y y iw n n y y n riw n n y n n MGL Matrice di Compatibilita’ riw = read con intenzione di write, per scansione che aggiorna alcuni dei record che legge • Ad es., ir e’ in conflitto con w, perche’ ir segnala un r-lock su un dato piu’ interno, che e’ in conflitto con un w-lock sulla struttura che lo contiene.
SQL Server 7.0 • SQL Server 7.0 accetta lock su tabelle, pagine, e righe. • Usa lock di intention read (“share”) e intention write (“exclusive”) a livello di pagina di tabella.
Modello Matematico del Locking • K lock per transazione • D lockable data items • N transazioni • T tempo tra richieste di lock • N transazioni, ciascuna ottiene K/2 lock in media • KN/2 lock concessi in totale • Ciascuna richiesta ha probabilita' KN/2D di conflitto con un lock esistente. • Ciascuna transazione richiede K locks, quindi la sua probabilita' di entrare in conflitto e' K2N/2D. • La probabilita' di deadlock e' proporzionale a K4N/D2 • Prob(deadlock) / Prob(conflitto) = K2/D • Se K=10 e D = 106, allora K2/D = .0001
Hot Spot Techniques • Hot spot - un data item che e’ piu' usato di altri, per cui molte transazioni ne fanno uso. • cataloghi ed elenchi • end-di-file marker • contatori usati per assegnare numeri seriali • Gli hot spots spesso creano un collo di bottiglia che serializza le transazioni.
Hot Spot Techniques (cont.) • Sono necessarie tecniche per ridurre il tempo t di durata di un lock sugli hot data • mantenere gli hot data in memoria centrale • rimandare al commit le operationi su hot data • usare strategie “ottimistiche” • eseguire in batch le operazioni su hot data • partitionare gli hot data
Rimandare le Operazioni al Commit • Il data manager registra le operazioni di ciascuna transazione sugli hot data item. • Richiede i lock ed effettua gli updates dopo il Commit della transazione • Molti sistemi usano questa tecnica per • Data Entry nel DB • DB residenti in memoria centrale • Funziona per write, inserire, delete, ma non per read
Controllo di concorrenza “ottimistico” • Idea - eseguire le operazioni sui copie dei dati senza richiedere i lock. Al commit, testare se vi sono conflitti sui lock. • spesso usata nei sistemi client/server • il client fa tutti gli updates nella cache senza lock • al commit, tenta di ottenere i lock ed effettua gli update
Batching • Ogni transazione crea un mini-batch con gli update, e solo periodicamente applica il mini-batch agli hot data condivisi. • ciascun processo ha un data entry file privato,in aggiunta ad un data entry file globale • ciascuna transazione aggiunge gli update al proprio file • periodicamente appende il proprio file al file condiviso
Partizionamento • Suddividere cataloghi e inventari in parti • Ciascuna transazione puo’ accedere solo una partizione. • Esempio • ciascuna biglietteria ha una parte dei biglietti • se li vende tutti, deve richiedere altri biglietti dalle altre biglietterie
Tecniche di Query-Update • Le query durano molto tempo e fanno lock su molti dati — degradano la performance se competono con brevi transazioni di update • Esistono diverse soluzioni • Usare un data warehouse • Accettare vincoli di consistenza piu’ deboli • Usare multiversioni dei dati
Data Warehouse • Un data warehouse e’ una copia del DB, che e' periodicamente aggiornata • Tutte le query girano sul data warehouse • Tutte le transazioni di update girano su DB • Separazione fra transazioni e query • Quanto spesso aggiornare il data warehouse? • Stop alle transazioni per copiare il DB nel data warehouse. E’ possibile invece effettuare query • Le query non hanno sempre l’ultima versione dei dati
Multiversioni dei Dati • La granularita’ del locking deve arrivare al record • ciascuna write crea una nuova versione, invece di sovrascrivere il valore esistente. • Ciascun record ha una sequenza di versioni. • Ogni versione e’ annotata con l’id della transazione che ha scritto quella versione Tid TidPrec. Matr Nome Stipendio 123 null 1 Bill 100 175 123 1 Bill 125 134 null 2 Sue 120 199 134 2 Sue 140 227 null 27 Steve 80
Multiversioni dei Dati (cont.) • Si eseguono le transazioni usando 2PL • Si eseguono le query in snapshot mode • il sistema mantiene la lista delle transazioni che hanno fatto commit con successo (transazioni committed), detta commit lista. • ogni query all’inizio della sua esecuzione copia la commit lista • quando una query legge x, legge l’ultima versione di x scritta da una transazione che e’ nella sua commit lista. • cosi', ogni query fa riferimento allo stato del database relativo a quando ha iniziato l'esecuzione
Gestione della Commit lista • Il data manager mantiene e periodicamente aggiorna un tid T-Oldest, tale che • il tid di ogni transazione attiva e' maggiore di T-Oldest • ogni nuovo tid e' maggiore di T-Oldest • per ogni transazione committed con tid T-Oldest, le sue versioni sono committed • per ogni transazione abortita con tid T-Oldest, le versioni sono state eliminate • Le query mantengono la parte della commit lista con tid > T-Oldest