Sblocco del gestore blocchi Postgres. Bruce Momjian

Trascrizione del discorso di Bruce Momjian del 2020 "Unlocking the Postgres Lock Manager".

Sblocco del gestore blocchi Postgres. Bruce Momjian

(Nota: tutte le query SQL delle diapositive possono essere ottenute da questo collegamento: http://momjian.us/main/writings/pgsql/locking.sql)

Ciao! È bello essere di nuovo qui in Russia. Mi dispiace non essere potuto venire l'anno scorso, ma quest'anno io e Ivan abbiamo grandi progetti. Spero di essere qui molto più spesso. Adoro venire in Russia. Visiterò Tyumen, Tver. Sono molto felice di poter visitare queste città.

Il mio nome è Bruce Momjian. Lavoro presso EnterpriseDB e collaboro con Postgres da oltre 23 anni. Vivo a Filadelfia, negli Stati Uniti. Viaggio circa 90 giorni all'anno. E partecipo a circa 40 conferenze. Mio il mio sito, che contiene le slide che ora vi mostrerò. Pertanto, dopo la conferenza potrete scaricarli dal mio sito personale. Contiene anche circa 30 presentazioni. Ci sono anche video e un gran numero di post di blog, più di 500. Questa è una risorsa abbastanza informativa. E se sei interessato a questo materiale, ti invito a usarlo.

Ero un insegnante, un professore prima di iniziare a lavorare con Postgres. E sono molto felice di poterti dire ora quello che sto per dirti. Questa è una delle mie presentazioni più interessanti. E questa presentazione contiene 110 diapositive. Inizieremo a parlare con cose semplici e alla fine la relazione diventerà sempre più complessa, e diventerà piuttosto complessa.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Questa è una conversazione piuttosto spiacevole. Il blocco non è l’argomento più popolare. Vogliamo che tutto questo scompaia da qualche parte. È come andare dal dentista.

Sblocco del gestore blocchi Postgres. Bruce Momjian

  1. Il blocco è un problema per molte persone che lavorano nei database e hanno più processi in esecuzione contemporaneamente. Hanno bisogno di essere bloccati. Cioè, oggi ti darò le conoscenze di base sul blocco.
  2. ID delle transazioni. Questa è una parte piuttosto noiosa della presentazione, ma è necessario capirli.
  3. Successivamente parleremo dei tipi di blocco. Questa è una parte abbastanza meccanica.
  4. E di seguito forniremo alcuni esempi di blocco. E sarà abbastanza difficile da capire.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Parliamo del blocco.

Sblocco del gestore blocchi Postgres. Bruce Momjian

La nostra terminologia è piuttosto complessa. Quanti di voi sanno da dove viene questo passaggio? Due persone. Questo proviene da un gioco chiamato Colossal Cave Adventure. Credo che fosse un gioco per computer basato su testo negli anni '80. Lì dovevi entrare in una grotta, in un labirinto, e il testo cambiava, ma il contenuto era più o meno lo stesso ogni volta. È così che ricordo questa partita.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E qui vediamo il nome delle serrature che ci sono arrivate da Oracle. Li usiamo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Qui vediamo termini che mi confondono. Ad esempio, CONDIVIDI AGGIORNAMENTO ECXLUSIVE. Successivo CONDIVIDI RAW ECXLUSIVE. Ad essere onesti, questi nomi non sono molto chiari. Cercheremo di considerarli in modo più dettagliato. Alcuni contengono la parola “condividere”, che significa separare. Alcuni contengono la parola “esclusivo”. Alcuni contengono entrambe queste parole. Vorrei iniziare spiegando come funzionano queste serrature.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E anche la parola “accesso” è molto importante. E le parole "riga" sono una stringa. Cioè, distribuzione degli accessi, distribuzione delle righe.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Un altro problema che deve essere compreso in Postgres, che purtroppo non potrò trattare nel mio discorso, è MVCC. Ho una presentazione separata su questo argomento sul mio sito web. E se pensi che questa presentazione sia difficile, MVCC è probabilmente la più difficile. E se sei interessato, puoi guardarlo sul sito. Puoi guardare il video.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Un'altra cosa che dobbiamo capire sono gli ID delle transazioni. Molte transazioni non possono funzionare senza identificatori univoci. E qui abbiamo una spiegazione di cosa sia una transazione. Postgres ha due sistemi di numerazione delle transazioni. So che non è una soluzione molto carina.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Tieni inoltre presente che le diapositive saranno piuttosto difficili da comprendere, quindi ciò che è evidenziato in rosso è ciò a cui devi prestare attenzione.

Sblocco del gestore blocchi Postgres. Bruce Momjian

http://momjian.us/main/writings/pgsql/locking.sql

Vediamo. Il numero della transazione è evidenziato in rosso. La funzione SELECT pg_back è mostrata qui. Restituisce la mia transazione e l'ID della transazione.

Ancora una cosa: se ti piace questa presentazione e desideri eseguirla sul tuo database, puoi andare a questo collegamento in rosa e scaricare l'SQL per questa presentazione. E puoi semplicemente eseguirlo nel tuo PSQL e l'intera presentazione sarà immediatamente sul tuo schermo. Non conterrà fiori, ma almeno potremo vederlo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

In questo caso vediamo l'ID della transazione. Questo è il numero che le abbiamo assegnato. E c'è un altro tipo di ID di transazione in Postgres, chiamato ID di transazione virtuale

E questo dobbiamo capirlo. Questo è molto importante, altrimenti non saremo in grado di comprendere il blocco in Postgres.

Un ID di transazione virtuale è un ID di transazione che non contiene valori persistenti. Ad esempio, se eseguo un comando SELECT, molto probabilmente non modificherò il database e non bloccherò nulla. Pertanto, quando eseguiamo una semplice SELECT, non diamo a quella transazione un ID persistente. Lì le diamo solo un documento d'identità virtuale.

E questo migliora le prestazioni di Postgres, migliora le capacità di pulizia, quindi l'ID della transazione virtuale è composto da due numeri. Il primo numero prima della barra è l'ID del backend. E sulla destra vediamo solo un bancone.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Pertanto, se eseguo una richiesta, viene visualizzato che l'ID del backend è 2.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se eseguo una serie di transazioni di questo tipo, vediamo che il contatore aumenta ogni volta che eseguo una query. Ad esempio, quando eseguo la query 2/10, 2/11, 2/12, ecc.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Tieni presente che ci sono due colonne qui. A sinistra vediamo l’ID della transazione virtuale – 2/12. E sulla destra abbiamo un ID transazione permanente. E questo campo è vuoto. E questa transazione non modifica il database. Quindi non gli do un ID di transazione permanente.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Non appena eseguo il comando di analisi ((ANALYZE)), la stessa query mi fornisce un ID transazione permanente. Guarda come è cambiato per noi. Prima non avevo questo documento d'identità, ma ora ce l'ho.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Quindi ecco un'altra richiesta, un'altra transazione. Il numero di transazione virtuale è 2/13. E se chiedo un ID transazione persistente, quando eseguo la query lo otterrò.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Quindi, ancora una volta. Abbiamo un ID di transazione virtuale e un ID di transazione persistente. Basta comprendere questo punto per comprendere il comportamento di Postgres.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Passiamo alla terza sezione. Qui esamineremo semplicemente i diversi tipi di lucchetti in Postgres. Non è molto interessante. L'ultima sezione sarà molto più interessante. Ma dobbiamo considerare le cose fondamentali, perché altrimenti non capiremo cosa succederà dopo.

Esamineremo questa sezione, esamineremo ogni tipo di blocco. E ti mostrerò esempi di come sono installati, come funzionano, ti mostrerò alcune query che puoi utilizzare per vedere come funziona il blocco in Postgres.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Per creare una query e vedere cosa sta succedendo in Postgres, dobbiamo inviare la query nella vista di sistema. In questo caso, pg_lock è evidenziato in rosso. Pg_lock è una tabella di sistema che ci dice quali blocchi sono attualmente in uso in Postgres.

Tuttavia, è molto difficile per me mostrarti pg_lock da solo perché è piuttosto complesso. Quindi ho creato una vista che mostra pg_locks. E fa anche un lavoro per me che mi permette di capire meglio. Cioè, esclude i miei blocchi, la mia sessione, ecc. È solo SQL standard e ti consente di mostrarti meglio cosa sta succedendo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Un altro problema è che questa visualizzazione è molto ampia, quindi devo crearne una seconda: lockview2.

Sblocco del gestore blocchi Postgres. Bruce Momjian E mi mostra più colonne dalla tabella. E un altro che mi mostra il resto delle colonne. Questo è piuttosto complesso, quindi ho cercato di presentarlo nel modo più semplice possibile.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Quindi abbiamo creato una tabella chiamata Lockdemo. E abbiamo creato una riga lì. Questa è la nostra tabella di esempio. E creeremo sezioni solo per mostrarti esempi di serrature.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Quindi, una riga, una colonna. Il primo tipo di blocco si chiama ACCESS SHARE. Questo è il blocco meno restrittivo. Ciò significa che praticamente non è in conflitto con altre serrature.

E se vogliamo definire esplicitamente un lock, eseguiamo il comando “lock table”. E ovviamente si bloccherà, ovvero in modalità ACCESS SHARE lanciamo la tabella di blocco. E se eseguo PSQL in background, inizio la seconda sessione dalla prima in questo modo. Cioè, cosa farò qui? Vado in un'altra sessione e gli dico "mostrami il lockview per questa richiesta". E qui ho AccessShareLock in questa tabella. Questo è esattamente quello che ho richiesto. E dice che il blocco è stato assegnato. Molto semplice.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Inoltre, se guardiamo la seconda colonna, non c'è nulla. Sono vuoti.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se eseguo il comando "SELECT", questo è il modo implicito (esplicito) per richiedere AccessShareLock. Quindi rilascio la mia tabella ed eseguo la query e la query restituisce più righe. E in una delle righe vediamo AccessShareLock. Pertanto, SELECT chiama AccessShareLock sulla tabella. E non è in conflitto praticamente con nulla perché è un blocco di basso livello.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Cosa succede se eseguo una SELECT e ho tre tabelle diverse? In precedenza eseguivo solo una tabella, ora ne eseguo tre: pg_class, pg_namespace e pg_attribute.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E ora quando guardo la query, vedo 9 AccessShareLocks in tre tabelle. Perché? Tre tabelle sono evidenziate in blu: pg_attribute, pg_class, pg_namespace. Ma puoi anche vedere che tutti gli indici definiti tramite queste tabelle hanno anche AccessShareLock.

E questo è un lucchetto che praticamente non entra in conflitto con gli altri. E tutto ciò che fa è semplicemente impedirci di reimpostare la tabella mentre la selezioniamo. Ha senso. Cioè, se selezioniamo una tabella, questa in quel momento scompare, allora è sbagliato, quindi AccessShare è un blocco di basso livello che ci dice "non rilasciare questa tabella mentre sto lavorando". In sostanza, è tutto ciò che fa.

Sblocco del gestore blocchi Postgres. Bruce Momjian

CONDIVISIONE FILA: questo blocco è leggermente diverso.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Facciamo un esempio. SELEZIONA CONDIVIDI RIGA metodo per bloccare ciascuna riga individualmente. In questo modo nessuno potrà cancellarli o modificarli mentre li stiamo guardando.

Sblocco del gestore blocchi Postgres. Bruce MomjianQuindi cosa fa SHARE LOCK? Vediamo che l'ID della transazione è 681 per SELECT. E questo è interessante. Cos'è successo qua? La prima volta che vediamo il numero è nel campo “Blocca”. Prendiamo l'ID della transazione e dice che lo sta bloccando in modalità esclusiva. Tutto ciò che fa è dire che ho una riga che è tecnicamente bloccata da qualche parte nella tabella. Ma non dice dove esattamente. Lo vedremo più in dettaglio un po' più tardi.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Qui diciamo che la serratura viene utilizzata da noi.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Quindi, un blocco esclusivo dice esplicitamente che è esclusivo. E anche se elimini una riga in questa tabella, questo è ciò che accadrà, come puoi vedere.

Sblocco del gestore blocchi Postgres. Bruce Momjian

SHARE EXCLUSIVE è un blocco più lungo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Questo è il comando dell'analizzatore (ANALIZZA) che verrà utilizzato.

Sblocco del gestore blocchi Postgres. Bruce Momjian

BLOCCO CONDIVIDI: puoi bloccare esplicitamente la modalità di condivisione.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Puoi anche creare un indice univoco. E lì puoi vedere SHARE LOCK, che ne fa parte. E blocca il tavolo e vi inserisce uno SHARE LOCK.

Per impostazione predefinita, SHARE LOCK su una tabella significa che altre persone possono leggere la tabella, ma nessuno può modificarla. E questo è esattamente ciò che accade quando crei un indice univoco.

Se creo un indice simultaneo univoco, avrò un tipo diverso di blocco perché, come ricorderete, l'utilizzo di indici simultanei riduce i requisiti di blocco. E se utilizzo un blocco normale, un indice normale, eviterò così di scrivere sull'indice della tabella mentre viene creata. Se utilizzo un indice simultaneo, devo utilizzare un diverso tipo di blocco.

Sblocco del gestore blocchi Postgres. Bruce Momjian

CONDIVIDI RIGA ESCLUSIVA – ancora una volta può essere impostato esplicitamente (esplicitamente).

Sblocco del gestore blocchi Postgres. Bruce Momjian

Oppure possiamo creare una regola, cioè prendere un caso specifico in cui verrà utilizzata.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Il blocco ESCLUSIVO significa che nessun altro può cambiare il tavolo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Qui vediamo diversi tipi di serrature.

Sblocco del gestore blocchi Postgres. Bruce Momjian

ACCESS EXCLUSIVE, ad esempio, è un comando di blocco. Ad esempio, se lo fai CLUSTER table, allora questo significherà che nessuno potrà scrivere lì. E blocca non solo la tabella stessa, ma anche gli indici.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Questa è la seconda pagina del blocco ACCESS EXCLUSIVE, dove vediamo esattamente cosa blocca nella tabella. Blocca le singole righe della tabella, il che è piuttosto interessante.

Queste sono tutte le informazioni di base che volevo fornire. Abbiamo parlato di blocchi, di ID di transazione, abbiamo parlato di ID di transazione virtuali, di ID di transazione permanenti.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E ora esamineremo alcuni esempi di blocco. Questa è la parte più interessante. Vedremo casi molto interessanti. E il mio obiettivo in questa presentazione è darti una migliore comprensione di ciò che Postgres sta effettivamente facendo quando tenta di bloccare determinate cose. Penso che sia molto bravo a bloccare le parti.

Diamo un'occhiata ad alcuni esempi specifici.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Inizieremo con le tabelle e una riga in una tabella. Quando inserisco qualcosa ho ExclusiveLock, ID transazione ed ExclusiveLock visualizzati sul tavolo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Cosa succede se inserisco altre due righe? E ora la nostra tabella ha tre righe. E ho inserito una riga e ho ottenuto questo come output. E se inserisco altre due righe, cosa c'è di strano? C'è una stranezza perché ho aggiunto tre righe a questa tabella, ma ho ancora due righe nella tabella dei blocchi. E questo è essenzialmente il comportamento fondamentale di Postgres.

Molte persone pensano che se in un database blocchi 100 righe, dovrai creare 100 voci di blocco. Se blocco 1 righe contemporaneamente, avrò bisogno di 000 query di questo tipo. E se ho bisogno di un milione o un miliardo per bloccare. Ma se lo facciamo, non funzionerà molto bene. Se hai utilizzato un sistema che crea voci di blocco per ogni singola riga, puoi vedere che è complicato. Perché è necessario definire immediatamente una tabella di lock che possa traboccare, ma Postgres non lo fa.

E ciò che è veramente importante in questa diapositiva è che dimostra chiaramente che esiste un altro sistema in esecuzione all'interno di MVCC che blocca le singole righe. Pertanto, quando blocchi miliardi di righe, Postgres non crea un miliardo di comandi di blocco separati. E questo ha un ottimo effetto sulla produttività.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Che ne dici di un aggiornamento? Sto aggiornando la riga ora e puoi vedere che ha eseguito due diverse operazioni contemporaneamente. Allo stesso tempo ha bloccato la tabella, ma ha anche bloccato l'indice. E doveva bloccare l'indice perché su questa tabella sono presenti vincoli univoci. E vogliamo assicurarci che nessuno lo cambi, quindi lo blocchiamo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Cosa succede se voglio aggiornare due righe? E vediamo che si comporta allo stesso modo. Effettuiamo il doppio degli aggiornamenti, ma esattamente lo stesso numero di linee di blocco.

Se ti stai chiedendo come fa Postgres, dovrai ascoltare i miei discorsi su MVCC per scoprire come Postgres contrassegna internamente queste righe che modifica. E Postgres ha un modo per farlo, ma non lo fa a livello di blocco della tabella, lo fa a un livello più basso e più efficiente.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Cosa succede se voglio eliminare qualcosa? Se elimino, ad esempio, una riga e ho ancora i miei due input bloccanti, e anche se volessi eliminarli tutti, sono ancora lì.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E, ad esempio, voglio inserire 1 righe e poi eliminare o aggiungere 000 righe, quindi le singole righe che aggiungo o modifico non vengono registrate qui. Sono scritti a un livello inferiore all'interno della serie stessa. E durante l'intervento del MVCC ho parlato approfonditamente di questo. Ma è molto importante quando analizzi i blocchi per assicurarti di bloccarli a livello di tabella e di non vedere come vengono registrate qui le singole righe.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E il blocco esplicito?

Sblocco del gestore blocchi Postgres. Bruce Momjian

Se faccio clic su Aggiorna, ho due righe bloccate. E se li seleziono tutti e faccio clic su "Aggiorna ovunque", ho ancora due record bloccanti.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Non creiamo record separati per ogni singola riga. Poiché poi la produttività diminuisce, potrebbe essercene troppa. E potremmo trovarci in una situazione spiacevole.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E la stessa cosa, se condividiamo, possiamo farlo tutto 30 volte.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ripristiniamo la nostra tabella, cancelliamo tutto, quindi inseriamo nuovamente una riga.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Un altro comportamento molto noto e desiderato che vedi in Postgres è che puoi eseguire un aggiornamento o una selezione. E puoi farlo allo stesso tempo. E la selezione non blocca l'aggiornamento e la stessa cosa nella direzione opposta. Diciamo al lettore di non bloccare lo scrittore e lo scrittore non ha bloccato il lettore.

Ti mostrerò un esempio di questo. Farò una scelta adesso. Faremo quindi l'INSERT. E poi puoi vedere - 694. Puoi vedere l'ID della transazione che ha eseguito questo inserimento. Ed è così che funziona.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se guardo ora il mio ID backend, ora è 695.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E posso vedere 695 apparire nella mia tabella.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se aggiorno qui in questo modo, ottengo un caso diverso. In questo caso, 695 è un blocco esclusivo e l'aggiornamento ha lo stesso comportamento, ma non c'è conflitto tra loro, il che è abbastanza insolito.

E puoi vedere che in alto c'è ShareLock e in basso c'è ExclusiveLock. Ed entrambe le transazioni hanno funzionato.

E devi ascoltare il mio discorso al MVCC per capire come ciò accade. Ma questo è un esempio del fatto che puoi farlo contemporaneamente, ovvero eseguire una SELEZIONE e un AGGIORNAMENTO contemporaneamente.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ripristiniamo e facciamo un'altra operazione.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Se provi a eseguire due aggiornamenti contemporaneamente sulla stessa riga, verrà bloccato. E ricorda, ho detto che il lettore non blocca lo scrittore, e lo scrittore non blocca il lettore, ma uno scrittore blocca un altro scrittore. Cioè, non possiamo avere due persone che aggiornano la stessa riga contemporaneamente. Devi aspettare finché uno di loro non finisce.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E per illustrarlo, guarderò la tabella Lockdemo. E guarderemo una riga. Per transazione 698.

Lo abbiamo aggiornato a 2. 699 è il primo aggiornamento. E ha avuto successo o è in una transazione in sospeso e sta aspettando la nostra conferma o annullamento.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ma guarda qualcos'altro: 2/51 è la nostra prima transazione, la nostra prima sessione. 3/112 è la seconda richiesta arrivata dall'alto che ha cambiato quel valore in 3. E se notate, quella in alto si è bloccata, ovvero 699. Ma 3/112 non ha concesso il blocco. La colonna Lock_mode dice cosa sta aspettando. Si aspetta 699. E se guardi dove si trova 699, è più alto. E cosa ha fatto la prima sessione? Ha creato un blocco esclusivo sul proprio ID transazione. Ecco come fa Postgres. Blocca il proprio ID di transazione. E se vuoi aspettare che qualcuno confermi o annulli, allora devi aspettare mentre c'è una transazione in sospeso. Ed è per questo che possiamo vedere una strana linea.

Guardiamo di nuovo. A sinistra vediamo il nostro ID di elaborazione. Nella seconda colonna vediamo il nostro ID di transazione virtuale e nella terza vediamo lock_type. Cosa significa questo? Essenzialmente ciò che dice è che sta bloccando l'ID della transazione. Ma nota che tutte le righe in basso dicono relazione. E quindi hai due tipi di lucchetti sul tavolo. C'è un blocco della relazione. E poi c'è il blocco TransactionID, dove blocchi da solo, che è esattamente ciò che accade nella prima riga o in fondo, dove si trova TransactionID, dove aspettiamo che 699 finisca la sua operazione.

Vedrò cosa succede qui. E qui accadono due cose contemporaneamente. Stai osservando un blocco dell'ID transazione nella prima riga che si blocca da solo. E si blocca per far aspettare.

Se guardi la sesta riga, è la stessa voce della prima. E quindi la transazione 6 è bloccata. 699 è anche autobloccante. E poi nella riga in basso vedrai che stiamo aspettando che 700 finisca la sua operazione.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E in lock_type, tuple vedi i numeri.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Puoi vedere che è 0/10. E questo è il numero di pagina e anche l'offset di questa particolare riga.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E vedi che diventa 0/11 quando aggiorniamo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ma in realtà è 0/10, perché c'è un'attesa per questa operazione. Abbiamo l'opportunità di vedere che questa è la serie che sto aspettando di confermare.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Dopo averlo confermato e premuto commit, e al termine dell'aggiornamento, questo è ciò che otteniamo di nuovo. La transazione 700 è l'unico blocco, non aspetta nessun altro perché è stata impegnata. Aspetta semplicemente che la transazione venga completata. Una volta esauriti i 699 non aspettiamo più nulla. E ora la transazione 700 dice che va tutto bene, che ha tutti i lock di cui ha bisogno su tutti i tavoli consentiti.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E per rendere il tutto ancora più complicato, creiamo un'altra vista, che questa volta ci fornirà una gerarchia. Non mi aspetto che tu capisca questa richiesta. Ma questo ci darà una visione più chiara di quello che sta succedendo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Questa è una vista ricorsiva che ha anche un'altra sezione. E poi rimette tutto insieme. Usiamo questo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se eseguissimo tre aggiornamenti simultanei e dicessimo che la riga ora è tre? E cambieremo da 3 a 4.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E qui vediamo 4. E ID transazione 702.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E poi cambierò 4 in 5. E 5 in 6, e 6 in 7. E metterò in fila un numero di persone che aspetteranno che questa transazione finisca.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E tutto diventa chiaro. Qual è la prima riga? Questo è 702. Questo è l'ID della transazione che originariamente ha impostato questo valore. Cosa c'è scritto nella mia colonna Concessi? Ho dei segni f. Questi sono i miei aggiornamenti che (5, 6, 7) non possono essere approvati perché stiamo aspettando il termine della transazione ID 702. Lì abbiamo il blocco dell'ID transazione. E questo si traduce in 5 blocchi ID transazionali.

E se guardi 704, 705, lì non è stato ancora scritto nulla, perché non sanno ancora cosa sta succedendo. Scrivono semplicemente che non hanno idea di cosa stia succedendo. E andranno a dormire perché aspettano che qualcuno finisca e si sveglieranno quando ci sarà l'opportunità di cambiare fila.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Questo è quello che sembra. È chiaro che stanno tutti aspettando la dodicesima riga.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Questo è ciò che abbiamo visto qui. Ecco 0/12.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Quindi, una volta approvata la prima transazione, puoi vedere qui come funziona la gerarchia. E ora tutto diventa chiaro. Diventano tutti puliti. E in realtà stanno ancora aspettando.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ecco cosa sta succedendo. 702 impegni. E ora 703 ottiene questo blocco di riga, e poi 704 inizia ad aspettare che 703 si impegni. E il 705 aspetta anche questo. E quando tutto questo sarà completato, si ripuliranno. E ci tengo a sottolineare che sono tutti in fila. E questo è molto simile a una situazione in un ingorgo, quando tutti aspettano la prima macchina. La prima macchina si ferma e tutti si mettono in fila. Quindi si muove, quindi la macchina successiva può avanzare e ottenere il suo blocco, ecc.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se questo non ti è sembrato abbastanza complicato, allora ti parleremo ora dei deadlock. Non so chi di voi li ha incontrati. Questo è un problema abbastanza comune nei sistemi di database. Ma i deadlock si verificano quando una sessione attende che un'altra sessione faccia qualcosa. E in questo momento un'altra sessione sta aspettando che la prima sessione faccia qualcosa.

E, per esempio, se Ivan dice: “Dammi qualcosa”, e io dico: “No, te lo darò solo se mi dai qualcos’altro”. E lui: "No, non te lo darò se tu non me lo dai". E ci ritroviamo in una situazione di stallo. Sono sicuro che Ivan non lo farà, ma capisci il significato che abbiamo due persone che vogliono ottenere qualcosa e non sono pronte a darlo via finché l'altra persona non dà loro ciò che vogliono. E non c'è soluzione.

E in sostanza, il tuo database deve rilevarlo. E poi bisogna eliminare o chiudere una delle sessioni, perché altrimenti rimarranno lì per sempre. E lo vediamo nei database, lo vediamo nei sistemi operativi. E in tutti i luoghi in cui abbiamo processi paralleli, questo può accadere.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E ora installeremo due deadlock. Metteremo 50 e 80. Nella prima riga aggiornerò da 50 a 50. Otterrò il numero di transazione 710.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E poi cambierò 80 in 81 e 50 in 51.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E questo è ciò che apparirà. E così il 710 ha una fila bloccata, e il 711 è in attesa di conferma. L'abbiamo visto durante l'aggiornamento. 710 è il proprietario della nostra serie. E 711 attende che 710 completi la transazione.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E dice anche su quale riga si verificano i deadlock. Ed è qui che inizia a diventare strano.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ora stiamo aggiornando da 80 a 80.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ed è qui che iniziano le situazioni di stallo. 710 aspetta una risposta da 711 e 711 aspetta 710. E questo non finirà bene. E non c'è via d'uscita da questo. E si aspetteranno una risposta l'uno dall'altro.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E inizierà a ritardare tutto. E non lo vogliamo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E Postgres ha dei modi per notare quando ciò accade. E quando ciò accade, ricevi questo errore. E da ciò è chiaro che questo o quel processo attende uno SHARE LOCK da un altro processo, cioè bloccato dal processo 711. E quel processo era in attesa che venisse assegnato un SHARE LOCK su questo o quell'ID di transazione ed è stato bloccato da questo o quell'altro processo. Pertanto, qui c'è una situazione di stallo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Ci sono situazioni di stallo a tre vie? È possibile? SÌ.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Inseriamo questi numeri in una tabella. Cambiamo da 40 a 40, facciamo il blocco.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Cambiamo da 60 a 61, da 80 a 81.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E poi ne cambiamo 80 e poi boom!

Sblocco del gestore blocchi Postgres. Bruce Momjian

E il 714 ora sta aspettando il 715. Il 716 sta aspettando il 715. E non si può fare nulla al riguardo.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Qui non ci sono più due persone, ce ne sono già tre. Io voglio qualcosa da te, questo vuole qualcosa da una terza persona e la terza persona vuole qualcosa da me. E ci ritroviamo in un'attesa a tre perché stiamo tutti aspettando che l'altra persona completi ciò che deve fare.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E Postgres sa su quale riga ciò accade. E così ti darà il seguente messaggio, che mostra che hai un problema in cui tre input si bloccano a vicenda. E non ci sono restrizioni qui. Questo può accadere quando 20 voci si bloccano a vicenda.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Il prossimo problema è serializzabile.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Se speciale blocco serializzabile.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E torniamo al 719. La sua uscita è abbastanza normale.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E puoi fare clic per rendere la transazione da serializzabile.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E ti rendi conto che ora hai un diverso tipo di blocco SA: significa serializzabile.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Sblocco del gestore blocchi Postgres. Bruce Momjian

E quindi abbiamo un nuovo tipo di blocco chiamato SARieadLock, che è un blocco seriale e ti consente di inserire i numeri seriali.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E puoi anche inserire indici univoci.

Sblocco del gestore blocchi Postgres. Bruce Momjian

In questa tabella abbiamo indici univoci.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Quindi se inserisco il numero 2 qui, ho un 2. Ma proprio in alto, ne inserisco un altro 2. E puoi vedere che 721 ha un lucchetto esclusivo. Ma ora 722 sta aspettando che 721 completi la sua operazione perché non può inserire 2 finché non sa cosa accadrà a 721.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se eseguiamo una subtransazione.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Qui ne abbiamo 723.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E se salviamo il punto e poi lo aggiorniamo, otteniamo un nuovo ID transazione. Questo è un altro modello di comportamento di cui devi essere consapevole. Se lo restituiamo, l'ID della transazione scomparirà. Il 724 sta partendo. Ma ora ne abbiamo 725.

Allora cosa sto cercando di fare qui? Sto cercando di mostrarti esempi di blocchi insoliti che potresti trovare: che si tratti di blocchi serializzabili o SAVEPOINT, questi sono diversi tipi di blocchi che appariranno nella tabella dei blocchi.

Sblocco del gestore blocchi Postgres. Bruce Momjian

Questa è la creazione di blocchi espliciti (espliciti), che hanno pg_advisory_lock.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E vedi che il tipo di blocco è elencato come consultivo. E qui c'è scritto "avviso" in rosso. E puoi bloccare contemporaneamente in questo modo con pg_advisory_unlock.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E in conclusione, vorrei mostrarvi un’altra cosa strabiliante. Creerò un'altra visualizzazione. Ma unirò la tabella pg_locks alla tabella pg_stat_activity. E perché voglio farlo? Perché questo mi permetterà di guardare e vedere tutte le sessioni attuali e vedere esattamente che tipo di blocchi stanno aspettando. E questo è piuttosto interessante quando mettiamo insieme la tabella dei lock e la tabella delle query.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E qui creiamo pg_stat_view.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E aggiorniamo la riga di uno. E qui vediamo 724. E poi aggiorniamo la nostra riga a tre. E cosa vedi qui adesso? Queste sono richieste, ovvero vedi l'intero elenco di richieste elencate nella colonna di sinistra. E poi sul lato destro puoi vedere i blocchi e cosa creano. E può essere più chiaro per te in modo da non dover tornare ogni volta a ogni sessione e vedere se è necessario parteciparvi o meno. Lo fanno per noi.

Un'altra caratteristica molto utile è pg_blocking_pids. Probabilmente non ne hai mai sentito parlare. Cosa sta facendo? Ci consente di indicare per questa sessione 11740 quali ID di processo specifici sta aspettando. E puoi vedere che 11740 sta aspettando 724. E 724 è in cima. E 11306 è il tuo ID processo. Essenzialmente, questa funzione passa attraverso la tabella di blocco. E so che è un po' complicato, ma riesci a capirlo. Essenzialmente questa funzione esamina questa tabella di blocco e tenta di trovare dove a questo ID di processo vengono assegnati i blocchi su cui è in attesa. E cerca anche di capire quale ID di processo ha il processo in attesa del blocco. Quindi puoi eseguire questa funzione pg_blocking_pids.

E questo può essere molto utile. L'abbiamo aggiunto solo nella versione 9.6, quindi questa funzionalità ha solo 5 anni, ma è molto, molto utile. E lo stesso vale per la seconda richiesta. Mostra esattamente ciò che dobbiamo vedere.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E' di questo che volevo parlarti. E come mi aspettavo, abbiamo esaurito tutto il nostro tempo perché c'erano così tante diapositive. E le diapositive sono disponibili per il download. Vorrei ringraziarvi per essere qui. Sono sicuro che ti piacerà il resto della conferenza, grazie mille!

Domande:

Ad esempio, se sto provando ad aggiornare le righe e la seconda sessione sta tentando di eliminare l'intera tabella. Per quanto ho capito, dovrebbe esserci qualcosa come un blocco degli intenti. Esiste una cosa del genere in Postgres?

Sblocco del gestore blocchi Postgres. Bruce Momjian

Torniamo all'inizio. Potresti ricordare che quando fai qualcosa, ad esempio quando esegui una SELECT, emettiamo un AccessShareLock. E questo impedisce che il tavolo venga lasciato cadere. Pertanto, se ad esempio desideri aggiornare una riga in una tabella o eliminare una riga, qualcuno non potrà eliminare l'intera tabella contemporaneamente perché stai mantenendo questo AccessShareLock sull'intera tabella e sulla riga. E una volta finito, possono eliminarlo. Ma mentre cambi direttamente qualcosa lì, non saranno in grado di farlo.

Facciamolo ancora. Passiamo all'esempio di eliminazione. E vedi come c'è un blocco esclusivo sulla riga sopra l'intera tabella.

Sembrerà un blocco esclusivo, giusto?

Sì, sembra di sì. Capisco di cosa stai parlando. Stai dicendo che se eseguo una SELECT, ho una ShareExclusive e poi la rendo Row Exclusive, diventa un problema? Ma sorprendentemente questo non rappresenta un problema. Sembra aumentare il grado di blocco, ma essenzialmente ho un blocco che impedisce la cancellazione. E ora, quando rendo questo blocco più potente, ne impedisce comunque la cancellazione. Quindi non è che sto salendo. Cioè, ha impedito che ciò accadesse anche quando era a un livello inferiore, quindi quando alzo il suo livello impedisce comunque l'eliminazione della tabella.

Capisco di cosa stai parlando. Non esiste un caso di escalation del blocco qui, in cui si tenta di rinunciare a un blocco per introdurne uno più forte. In questo caso non fa altro che aumentare questa prevenzione a tutti i livelli, quindi non causa alcun conflitto. Ma è una buona domanda. Grazie mille per avermelo chiesto!

Cosa dobbiamo fare per evitare una situazione di stallo quando abbiamo molte sessioni, un gran numero di utenti?

Postgres rileva automaticamente le situazioni di stallo. E eliminerà automaticamente una delle sessioni. L'unico modo per evitare il dead blocking è bloccare le persone nello stesso ordine. Quindi, quando guardi la tua domanda, spesso il motivo degli stalli... Immaginiamo che io voglia bloccare due cose diverse. Un'applicazione blocca la tabella 1, un'altra applicazione blocca la tabella 2 e quindi la tabella 1. Il modo più semplice per evitare blocchi critici è esaminare l'applicazione e cercare di assicurarsi che il blocco avvenga nello stesso ordine in tutte le applicazioni. E questo di solito elimina l'80% dei problemi, perché tutti i tipi di persone scrivono queste applicazioni. E se li blocchi nello stesso ordine, non ti imbatterai in una situazione di stallo.

Grazie mille per la tua prestazione! Hai parlato di vuoto pieno e, se ho capito bene, il vuoto pieno distorce l'ordine dei record in archivi separati, quindi mantengono invariati i record attuali. Perché il vuoto completo accetta l'accesso esclusivo al blocco e perché è in conflitto con le operazioni di scrittura?

Questa è una bella domanda. Il motivo è che il vuoto pieno prende il tavolo. E stiamo essenzialmente creando una nuova versione della tabella. E il tavolo sarà nuovo. Si scopre che questa sarà una versione completamente nuova del tavolo. E il problema è che quando lo facciamo, non vogliamo che le persone lo leggano perché abbiamo bisogno che vedano la nuova tabella. E quindi questo si collega alla domanda precedente. Se potessimo leggere contemporaneamente, non saremmo in grado di spostarlo e indirizzare le persone a un nuovo tavolo. Dovremmo aspettare che tutti finiscano di leggere questa tabella, quindi è essenzialmente una situazione esclusiva del blocco.
Diciamo semplicemente che blocchiamo dall'inizio perché sappiamo che alla fine avremo bisogno di un blocco esclusivo per spostare tutti nella nuova copia. Quindi possiamo potenzialmente risolverlo. E lo facciamo in questo modo con l'indicizzazione simultanea. Ma questo è molto più difficile da fare. E questo è molto correlato alla tua domanda precedente sull'esclusività del blocco.

È possibile aggiungere il timeout di blocco a Postgres? In Oracle posso, ad esempio, scrivere "seleziona per aggiornare" e attendere 50 secondi prima dell'aggiornamento. È stato positivo per l'applicazione. Ma in Postgres, devo farlo subito e non aspettare affatto, oppure aspettare fino a un po' di tempo.

Sì, puoi scegliere un timeout sulle tue serrature, sulle tue serrature. Puoi anche impartire un comando "no way", che... se non riesci a ottenere immediatamente il blocco. Pertanto, o un timeout di blocco o qualcos'altro che ti consentirà di farlo. Questo non viene fatto a livello sintattico. Questo viene fatto come una variabile sul server. A volte questo non può essere utilizzato.

Puoi aprire la diapositiva 75?

Sì.

Sblocco del gestore blocchi Postgres. Bruce Momjian

E la mia domanda è la seguente. Perché entrambi i processi di aggiornamento prevedono 703?

E questa è un'ottima domanda. A proposito, non capisco perché Postgres lo fa. Ma quando è stato creato 703, si aspettava 702. E quando appaiono 704 e 705, sembra che non sappiano cosa si aspettano perché non c'è ancora niente. E Postgres fa così: quando non riesci a ottenere un lock, scrive “Che senso ha processarti?”, perché stai già aspettando qualcuno. Quindi lo lasceremo sospeso in aria, non lo aggiornerà affatto. Ma cosa è successo qui? Non appena 702 ha completato il processo e 703 ha ricevuto il blocco, il sistema è tornato indietro. E ha detto che ora abbiamo due persone che stanno aspettando. E allora aggiorniamoli insieme. E indichiamo che entrambi sono in attesa.

Non so perché Postgres lo fa. Ma c'è un problema chiamato f…. Mi sembra che questo non sia un termine in russo. Questo è il momento in cui tutti aspettano un castello, anche se ci sono 20 autorità che aspettano il castello. E all'improvviso si svegliano tutti allo stesso tempo. E tutti iniziano a provare a reagire. Ma il sistema fa in modo che tutti aspettino il 703. Perché tutti aspettano, e noi li metteremo subito in fila. E se appare qualsiasi altra nuova richiesta generata dopo questa, ad esempio 707, allora ci sarà di nuovo il vuoto.

E mi sembra che questo sia fatto in modo che possiamo dire che in questa fase 702 aspetta 703, e tutti quelli che verranno dopo non avranno alcuna voce in questo campo. Ma non appena il primo cameriere se ne va, tutti coloro che in quel momento aspettavano prima dell'aggiornamento ricevono lo stesso gettone. E quindi penso che questo sia fatto in modo che possiamo elaborarli in modo che siano adeguatamente ordinati.

L’ho sempre considerato un fenomeno piuttosto strano. Perché qui, ad esempio, non li elenchiamo affatto. Ma mi sembra che ogni volta che diamo una nuova serratura, guardiamo tutti coloro che sono in attesa. Poi li mettiamo tutti in fila. E poi qualsiasi nuovo arrivato entra in coda solo quando la persona successiva ha finito di essere elaborato. Ottima domanda. Grazie mille per la domanda!

Mi sembra che sia molto più logico quando 705 si aspetta 704.

Ma il problema qui è il seguente. Tecnicamente puoi svegliare l'uno o l'altro. E così ci sveglieremo l'uno o l'altro. Ma cosa succede nel sistema? Puoi vedere come 703 in alto ha bloccato il proprio ID di transazione. Ecco come funziona Postgres. E 703 è bloccato dal proprio ID di transazione, quindi se qualcuno vuole aspettare, aspetterà 703. E, in sostanza, 703 viene completato. E solo dopo il suo completamento si risveglia uno dei processi. E non sappiamo quale sarà esattamente questo processo. Quindi elaboriamo tutto gradualmente. Ma non è chiaro quale processo venga risvegliato per primo, perché potrebbe trattarsi di uno qualsiasi di questi processi. Essenzialmente, avevamo uno scheduler che diceva che ora possiamo riattivare uno qualsiasi di questi processi. Ne scegliamo uno a caso. Quindi entrambi devono essere notati perché possiamo risvegliare l'uno o l'altro.

E il problema è che abbiamo CP-infinity. E quindi è molto probabile che potremo svegliarci più tardi. E se, ad esempio, risveglieremo quello successivo, aspetteremo colui che ha appena ricevuto il blocco, quindi non determiniamo esattamente chi verrà risvegliato per primo. Creiamo semplicemente una situazione del genere e il sistema li risveglierà in ordine casuale.

C'è articoli sulle serrature di Egor Rogov. Guarda, sono anche interessanti e utili. L’argomento, ovviamente, è terribilmente complesso. Grazie mille, Bruce!

Fonte: habr.com

Aggiungi un commento