Sbloccare il Postgres Lock Manager. Bruce Momjian

Decrittazione della presentazione del 2020 di Bruce Momjian "Sbloccare il Postgres Lock Manager".

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

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

Mi chiamo Bruce Momjian. Lavoro in EnterpriseDB e utilizzo Postgres da oltre 23 anni. Vivo a Filadelfia, negli Stati Uniti. Viaggio circa 90 giorni all'anno e partecipo a circa 40 conferenze. Il mio sito web, che contiene le diapositive che vi mostrerò ora. Quindi, dopo la conferenza, potete scaricarle dal mio sito personale. Ci sono anche circa 30 presentazioni disponibili. Inoltre, ci sono video e un gran numero di post sul blog, oltre 500. È una risorsa piuttosto sostanziosa. E se vi interessa questo materiale, vi invito a utilizzarlo.

In passato ero professore, prima di iniziare a lavorare con Postgres. Sono molto felice di potervi raccontare ciò che ho in programma di condividere. È una delle mie presentazioni più interessanti. Questa presentazione contiene 110 diapositive. Inizieremo parlando di concetti semplici, ma man mano che andremo avanti, il discorso diventerà sempre più complesso.

Sbloccare il Postgres Lock Manager. Bruce Momjian

È una conversazione piuttosto sgradevole. Il locking non è un argomento molto popolare. Vorremmo che sparisse. È come andare dal dentista.

Sbloccare il Postgres Lock Manager. Bruce Momjian

  1. Il locking è un problema per molte persone che lavorano con i database e che hanno più processi in esecuzione contemporaneamente. Hanno bisogno del locking. Quindi oggi vi fornirò le basi su questo argomento.
  2. Identificatori delle transazioni. Questa è una parte piuttosto noiosa della presentazione, ma è fondamentale comprenderla.
  3. Passiamo ora ai tipi di locking. Questa è una parte abbastanza meccanica.
  4. Successivamente, presenteremo alcuni esempi di locking. E sarà piuttosto complesso da comprendere.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Parliamo di locking.

Sbloccare il Postgres Lock Manager. Bruce Momjian

La nostra terminologia è piuttosto complessa. Quanti di voi sanno da dove viene questo estratto? Due persone. Proviene da un gioco chiamato "Colossal Cave Adventure". Era un videogioco testuale degli anni '80, se non sbaglio. Bisognava entrare in una caverna, in un labirinto, e il testo cambiava, ma il contenuto era più o meno lo stesso ogni volta. Così ricordo questo gioco.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Qui vediamo i nomi dei blocchi che ci sono stati forniti da Oracle. Li utilizziamo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Qui ci sono termini che mi confondono. Ad esempio, SHARE UPDATE EXCLUSIVE. Poi SHARE RAW EXCLUSIVE. Onestamente, questi nomi non sono molto chiari. Cercheremo di esaminarli in dettaglio. Alcuni contengono la parola "share", che significa – separarsi. Alcuni contengono la parola "exclusive" — esclusivo. Alcuni contengono entrambe queste parole. Vorrei cominciare con il modo in cui funzionano questi blocchi.

Sbloccare il Postgres Lock Manager. Bruce Momjian

È anche molto importante la parola "access" — accesso. E la parola "row" — riga. Cioè, distribuzione dell'accesso, distribuzione delle righe.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Un'altra questione da comprendere in Postgres, e purtroppo non potrò parlarne nella mia presentazione, è il MVCC. Ho una presentazione separata su questo argomento sul mio sito web. E se pensate che questa presentazione sia complessa, il MVCC è probabilmente la mia più complessa. Se vi interessa, potete vederla sul sito. Potete guardare il video.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Un altro aspetto che dobbiamo capire sono gli identificatori delle transazioni. Molte transazioni non possono funzionare senza identificatori unici. Qui è fornita una spiegazione su cosa sia una transazione. In Postgres ci sono due sistemi di numerazione delle transazioni. Lo so, non è una soluzione molto elegante.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Tenete presente che le diapositive saranno piuttosto complesse da comprendere, quindi è importante prestare attenzione a ciò che è evidenziato in rosso.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Vediamo. Il numero della transazione è evidenziato in rosso. Qui è mostrata la funzione SELECT pg_back. Essa restituisce la mia transazione e l'ID di questa transazione.

Un altro aspetto: se ti piace questa presentazione e desideri avviarla nel tuo database, puoi seguire questo link evidenziato in rosa e scaricare il SQL per questa presentazione. Puoi semplicemente eseguirlo nel tuo PSQL e l'intera presentazione apparirà sul tuo schermo immediatamente. Non conterrà colori, ma almeno potremo vederla.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Dobbiamo comprenderlo. È molto importante, altrimenti non saremo in grado di capire il blocco in Postgres.

L'ID virtuale della transazione è un ID della transazione che non contiene valori fissi. Ad esempio, se eseguo un comando SELECT, probabilmente non cambierò il database e non bloccherò nulla. Pertanto, quando eseguiamo un semplice SELECT, non diamo a questa transazione un ID fisso. Le diamo solo un ID virtuale.

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, se eseguo una richiesta, dice che l'ID del backend è 2.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Se eseguo una serie di tali transazioni, vediamo che il contatore aumenta ogni volta che eseguo una richiesta. Ad esempio, quando eseguo la richiesta 2/10, 2/11, 2/12 e così via.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Tenete presente che ci sono due colonne. A sinistra vediamo l'ID virtuale della transazione – 2/12. A destra abbiamo l'ID permanente della transazione. E questo campo è vuoto. E questa transazione non modifica il database. Pertanto, non le assegno un ID permanente della transazione.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Non appena eseguo il comando di analisi (ANALYZE), la stessa richiesta mi fornisce un ID permanente della transazione. Vedete come è cambiato. Prima non avevo questo ID, ora è apparso.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, qui c'è un'altra richiesta, un'altra transazione. Il numero virtuale della transazione è 2/13. E se chiedo l'ID permanente della transazione, quando eseguo la richiesta, lo ottengo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, per chiarire. Abbiamo un ID virtuale della transazione e un ID permanente della transazione. È importante comprendere questo concetto per capire il comportamento di Postgres.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Passiamo alla terza sezione. Qui esamineremo i diversi tipi di blocchi in Postgres. Non è molto interessante. L'ultima sezione sarà sicuramente più coinvolgente. Ma dobbiamo trattare le basi, altrimenti non comprenderemo ciò che verrà dopo.

Affronteremo questa sezione, guarderemo ogni tipo di blocco. Vi mostrerò esempi di come vengono impostati, come funzionano, e vi presenterò alcune query che potete usare per osservare come funziona il blocco in Postgres.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Per creare una query e vedere cosa succede in Postgres, dobbiamo eseguire una query nella vista di sistema. In questo caso, evidenziamo in rosso pg_lock. Pg_lock è una tabella di sistema che ci indica quali blocchi sono attualmente attivi in Postgres.

Tuttavia, è molto difficile per me mostrarti pg_lock da solo, perché è piuttosto complesso. Perciò, ho creato una vista che mostra pg_locks. Inoltre, esegue per me alcune operazioni che mi permettono di capire meglio. Cioè, esclude i miei blocchi, la mia sessione ecc. È semplicemente SQL standard e permette di mostrarti meglio cosa sta succedendo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Un altro problema è che questa vista è molto ampia, quindi devo creare una seconda – lockview2.

Sbloccare il Postgres Lock Manager. Bruce Momjian E mostra ulteriori colonne dalla tabella. E un'altra, che mi mostra le rimanenti colonne. È abbastanza complicato, quindi ho cercato di presentarlo il più semplicemente possibile.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, abbiamo creato una tabella chiamata Lockdemo. E abbiamo inserito una riga. Questa è la nostra tabella di esempio. Creeremo sezioni per mostrarti semplicemente esempi di blocchi.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, una riga, una colonna. Il primo tipo di blocco si chiama ACCESS SHARE. Questo è il blocco meno restrittivo. Significa che praticamente non entra in conflitto con gli altri blocchi.

Se vogliamo definire esplicitamente il blocco, eseguiamo il comando "lock table". E questo bloccherà esplicitamente, cioè in modalità ACCESS SHARE, eseguiamo lock table. E se avvio PSQL in background, avvio così una seconda sessione dalla mia prima sessione. Cosa faccio qui? Passo a un'altra sessione e le dico "mostrami lockview per questa query". Qui ho AccessShareLock in questa tabella. È proprio quello che avevo richiesto. E dice che il blocco è stato assegnato. Molto semplice.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Inoltre, se guardiamo nella seconda colonna, non c'è nulla. Sono vuote.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se eseguo il comando "SELECT", questo è un modo implicito (esplicito) per richiedere AccessShareLock. Quindi rilascio la mia tabella e avvio la query, e la query restituisce diverse righe. In una delle righe vediamo AccessShareLock. Così SELECT chiama AccessShareLock nella tabella. E non entra praticamente in conflitto con nulla, perché è un blocco di basso livello.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

E ora, mentre guardo la richiesta, vedo 9 AccessShareLocks in tre tabelle. Perché? Le tre tabelle sono evidenziate in blu: pg_attribute, pg_class, pg_namespace. Ma puoi anche vedere che tutti gli indici definiti attraverso queste tabelle hanno anch'essi un AccessShareLock.

E questa è una lock che praticamente non confligge con altre. E tutto ciò che fa è semplicemente impedirci di resettare la tabella mentre la stiamo selezionando. Ha senso. Cioè, se stiamo selezionando una tabella, scompare in quel momento, il che non è corretto. AccessShare è un lock di basso livello che ci dice 'non eliminare questa tabella mentre sto lavorando'.. Fondamentalmente, è tutto ciò che fa.

Sbloccare il Postgres Lock Manager. Bruce Momjian

ROW SHARE è un lock un po' diverso.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Facciamo un esempio. SELECT ROW SHARE è un modo di bloccare ogni singola riga.. Così nessuno può eliminarle o modificarle mentre le stiamo visualizzando.

Sbloccare il Postgres Lock Manager. Bruce MomjianQuindi, cosa fa SHARE LOCK? Vediamo che l'ID della transazione è 681 per il SELECT. E questo è interessante. Cosa è successo qui? Per la prima volta vediamo un numero nel campo 'Lock'. Prendiamo l'ID della transazione, e lui dice che la blocca in modalità esclusiva. Tutto ciò che fa è indicare che ho una riga che è tecnicamente bloccata da qualche parte nella tabella. Ma non dice dove esattamente. Più avanti lo esamineremo con maggiore dettaglio.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Qui diciamo che il blocco è utilizzato da noi.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, il blocco esclusivo dice esplicitamente che è esclusivo. E se si elimina una riga in questa tabella, proprio questo succederà, come puoi vedere.

Sbloccare il Postgres Lock Manager. Bruce Momjian

SHARE EXCLUSIVE è un blocco più lungo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

SHARE LOCK – puoi esplicitamente bloccare in modalità share.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Puoi anche creare un indice unico. E lì puoi vedere SHARE LOCK, che fa parte di esso. Blocca la tabella e imposta su di essa il blocco SHARE LOCK.

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

Se creo un indice unico concurrently, avrò un altro tipo di blocco, perché, come ricordi, l'uso di indici concurrently riduce la necessità di blocchi. E se utilizzo un blocco normale, un indice normale, impedirò in questo modo la scrittura nell'indice della tabella durante la sua creazione. Se utilizzo un indice concurrently, dovrò usare un altro tipo di blocco.

Sbloccare il Postgres Lock Manager. Bruce Momjian

SHARE ROW EXCLUSIVE – può essere impostato esplicitamente.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

Il blocco EXCLUSIVE significa che nessun altro potrà modificare la tabella.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Qui vediamo vari tipi di blocchi.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

Questa è la seconda pagina di blocco ACCESS EXCLUSIVE, dove vediamo specificamente cosa sta bloccando nella tabella. Blocca singole righe della tabella, il che è piuttosto interessante.

Queste sono tutte le informazioni di base che volevo fornire. Abbiamo parlato di blocchi, degli ID delle transazioni, abbiamo discusso degli ID virtuali delle transazioni e degli ID permanenti delle transazioni.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ora passeremo attraverso alcuni esempi di blocco. Questa è la parte più interessante. Esamineremo casi molto interessanti. Il mio obiettivo in questa presentazione è darvi una migliore comprensione di ciò che Postgres fa realmente quando cerca di bloccare determinate cose. Penso che sia molto abile nel bloccare parti specifiche.

Analizziamo alcuni esempi specifici.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Iniziamo con le tabelle e con una riga nella tabella. Quando inserisco qualcosa, mi appare ExclusiveLock, l'ID della transazione e ExclusiveLock sulla tabella.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se inserisco altre due righe? Ora abbiamo tre righe nella nostra tabella. Ho inserito una riga e ho ottenuto questo in output. E se inserisco altre due righe, cosa c'è di strano qui? C'è una stranezza, perché ho aggiunto tre righe a questa tabella, ma ho ancora due righe nella tabella di blocco. E questo è, in sostanza, il comportamento fondamentale di Postgres.

Molti pensano che se nella base di dati bloccate 100 righe, sarà necessario creare 100 inserimenti di blocco. Se blocco subito 1.000 righe, mi serviranno 1.000 richieste del genere. E se devo bloccare un milione o un miliardo. Ma se procediamo in questo modo, non funzionerà molto bene. Se avessi un sistema che genera inserti di blocco per ciascuna riga, vedresti che è complicato. Perché dovresti definire subito una tabella di blocco che può riempirsi, ma Postgres non funziona in questo modo.

In questo slide è molto importante notare che qui viene chiaramente dimostrato che esiste un altro sistema che opera all'interno di MVCC, il quale blocca righe specifiche. Quindi, quando bloccate miliardi di righe, Postgres non genera miliardo di comandi separati per il blocco. Questo ha un impatto molto positivo sulle prestazioni.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E per quanto riguarda l'aggiornamento? Ora sto aggiornando una riga e potete notare che ha eseguito immediatamente due operazioni diverse. Ha bloccato la tabella, ma ha anche bloccato l'indice. E doveva bloccare l'indice perché ci sono restrizioni uniche su questa tabella. Vogliamo assicurarci che nessuno la modifichi, quindi la bloccano.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E cosa succede se voglio aggiornare due righe? Vediamo che si comporta allo stesso modo. Eseguiamo il doppio degli aggiornamenti, ma esattamente lo stesso numero di righe bloccate.

Se sei curioso di sapere come fa Postgres, devi ascoltare le mie presentazioni su MVCC per scoprire come Postgres etichetta internamente le righe che modifica. E Postgres ha un modo per farlo, ma non lo fa a livello di blocco delle tabelle, lo fa a un livello più basso e più efficiente.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se voglio eliminare qualcosa? Se elimino, ad esempio, una riga e ho ancora i miei due input per il blocco, anche se volessi eliminarli tutti, essi sono comunque presenti.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Per esempio, se voglio inserire 1.000 righe e poi eliminare o aggiungere altre 1.000 righe, le singole righe che aggiungo o modifico non vengono registrate qui. Vengono registrate a un livello più basso all'interno della riga stessa. Durante la mia presentazione su MVCC ne ho parlato in dettaglio. Ma è molto importante, quando analizzi i blocchi, assicurarti che hai un blocco a livello di tabella e che qui non vedi come viene registrata ogni singola riga.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E per quanto riguarda il blocco esplicito?

Sbloccare il Postgres Lock Manager. Bruce Momjian

Se clicco su «aggiorna», ho due righe bloccate. E se le seleziono tutte e premo «aggiorna tutto», ho comunque due registrazioni di blocco.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Non creiamo registrazioni separate per ogni singola riga. Perché altrimenti le prestazioni calano, ci potrebbero essere troppe. E potremmo trovarci in una situazione scomoda.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E lo stesso vale se facciamo in modalità condivisa, possiamo farlo per tutte e 30 le volte.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ripristiniamo la nostra tabella, cancelliamo tutto, poi reinseriamo una riga.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Un altro tipo di comportamento che vediamo in Postgres è molto noto e desiderato: è quello che possiamo effettuare un update o un select. E possiamo farlo simultaneamente. E il select non blocca l'update e viceversa. Diciamo al lettore di non bloccare chi scrive, e chi scrive non blocca il lettore.

Vi mostro un esempio di questo. Ora farò una selezione. Poi faremo un INSERT. E poi potrete vedere – 694. Potrete vedere l'ID della transazione che ha eseguito questo inserimento. E così funziona.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

E posso vedere che il 695 appare nella mia tabella.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se aggiorno qui in questo modo, ottengo un altro caso. In questo caso, 695 è un blocco esclusivo, e l'update ha lo stesso comportamento, ma non si creano conflitti tra loro, il che è piuttosto insolito.

E puoi notare che in alto c'è ShareLock, e in basso c'è ExclusiveLock. E entrambe le transazioni sono andate a buon fine.

Dovrei ascoltare la mia presentazione su MVCC per capire come funziona. Ma questa è un'illustrazione di ciò che puoi fare contemporaneamente, ovvero eseguire SELECT e UPDATE allo stesso tempo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Facciamo un reset e facciamo un'operazione di nuovo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Se provi a eseguire due update contemporaneamente sulla stessa riga, verrà bloccata. E ricorda, ho detto che chi legge non blocca chi scrive, ma chi scrive blocca chi legge. Ma un scrittore blocca un altro scrittore. Cioè, non possiamo fare in modo che due persone aggiornino la stessa riga contemporaneamente. Bisogna aspettare che uno di loro finisca.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E per illustrare questo, darò un'occhiata alla tabella Lockdemo. E guarderemo una riga. Nella transazione 698.

Lo abbiamo aggiornato a 2. 699 è il primo aggiornamento. E ha avuto successo oppure è in attesa di transazione e aspetta che confermiamo o annulliamo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ma guardate un'altra cosa – 2/51 – è la nostra prima transazione, la nostra prima sessione. 3/112 – è la seconda richiesta, che è apparsa sopra e ha cambiato questo valore in 3. E se notate, l'alto si è bloccato da solo, che è 699. Ma 3/112 non ha fornito alcun blocco. Nella colonna Lock_mode c'è scritto che è in attesa. Sta aspettando 699. E se guardate dove si trova 699, è sopra. E cosa ha fatto la prima sessione? Ha creato un blocco esclusivo sul proprio ID di transazione. È così che Postgres funziona. Blocca il proprio ID di transazione. E se volete aspettare che qualcuno confermi o annulli, dovete aspettare una transazione in attesa. Ecco perché possiamo vedere una riga strana.

Rivediamo un attimo. A sinistra vediamo il nostro ID di elaborazione. Nella seconda colonna troviamo il nostro ID virtuale della transazione, e nella terza vediamo il lock_type. Cosa significa? Fondamentalmente, indica che blocca l'ID della transazione. Ma notate che in tutte le righe in basso c'è scritto relation. E quindi avete due tipi di blocco nella tabella. Esiste il blocco relation. E c'è anche il blocco transactionid, dove bloccate autonomamente, questo è esattamente ciò che accade nella prima riga o nella parte inferiore, dove transactionid, dove ci aspettiamo che 699 completi la sua operazione.

Vedo cosa sta accadendo qui. E qui si svolgono due cose contemporaneamente. Stai osservando il blocco per l'ID della transazione nella prima riga, che si blocca da solo. E si blocca da solo per costringere le persone ad aspettare.

Se guardi la sesta riga, troverai la stessa voce della prima. E quindi la transazione 699 è bloccata. Anche 700 si blocca da solo. E poi nella riga inferiore vedrete che stiamo aspettando che 699 completi la sua operazione.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E nel lock_type, tuple vedete dei numeri.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

E vedi che diventa 0/11 quando aggiorniamo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ma in realtà è 0/10, perché stiamo aspettando che questa operazione si completi. Abbiamo la possibilità di vedere che è quella riga che sto aspettando per confermare.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Una volta che l'abbiamo confermata e premuto il commit, e quando l'aggiornamento è finito, questo è ciò che otteniamo di nuovo. La transazione 700 è l'unico blocco, non sta aspettando nessun altro perché è stata confermata. Sta solo aspettando che la transazione si completi. Una volta che 699 finisce, non stiamo più aspettando nulla. E ora la transazione 700 dice che va tutto bene, tutte le chiavi necessarie sono disponibili in tutte le tabelle autorizzate.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E per complicare ulteriormente le cose, creiamo un'altra vista, che questa volta ci fornirà una gerarchia. Non mi aspetto che tu capisca questa query. Ma ci darà una visione più chiara di ciò che sta accadendo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Questa è una vista ricorsiva, che ha anche un'altra sezione. E poi riunisce tutto di nuovo. Utilizziamo questo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se facessimo tre aggiornamenti simultanei e dicessimo che la riga ora è pari a tre. E cambiamo 3 in 4.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E ora vediamo 4. E l'ID transazionale è 702.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Poi cambierò 4 in 5. E 5 in 6, e 6 in 7. E metto in fila una serie di persone che aspettano che questa singola transazione si concluda.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E tutto diventa chiaro. Qual è la prima fila? È 702. Questo è l'ID transazionale che ha originariamente impostato questo valore. E cosa ho scritto nella colonna Granted? Ho dei segni f. Questi sono i miei aggiornamenti (5, 6, 7) che non possono essere approvati, perché stiamo aspettando che l'ID transazionale 702 si concluda. Qui abbiamo un blocco dell'ID transazionale. E quindi ci sono 5 blocchi dell'ID transazionale.

E se guardi 704, 705, lì non è ancora stato scritto nulla, perché non sanno ancora cosa sta accadendo. Scrivono solo che non hanno idea di cosa stia succedendo. E semplicemente andranno a dormire, perché stanno aspettando che qualcuno finisca e li svegli quando ci sarà la possibilità di cambiare fila.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ecco come appare. È chiaro che stanno tutti aspettando la dodicesima riga.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ecco cosa abbiamo visto qui. Ecco 0/12.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, una volta che la prima transazione è approvata, qui puoi vedere come funziona la gerarchia. Ora tutto diventa chiaro. Tutti si liberano. E sono effettivamente ancora in attesa.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ecco cosa succede. 702 viene committato. Ora 703 acquisisce il blocco della riga, e poi 704 inizia ad aspettare che 703 venga committato. Anche 705 sta aspettando questo. E quando tutto questo si completa, si puliscono da soli. Vorrei far notare che tutti si mettono in fila. È molto simile a una situazione di ingorgo, dove tutti aspettano la prima auto. La prima auto si è fermata, e tutti si mettono in una lunga fila. Poi si muove, e l'auto successiva può passare e ricevere il suo blocco, e così via.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se questo vi è sembrato poco complesso, parleremo adesso di deadlock. Non so quanti di voi ci siano già stati. È un problema abbastanza comune nei sistemi di database. Ma i deadlock sono quel caso in cui una sessione attende che un'altra sessione esegua qualcosa. Nel frattempo, l'altra sessione attende che la prima sessione esegua qualcosa.

E, per esempio, se Ivan dice: «Dammi qualcosa», e io dico: «No, te lo darò solo se mi dai qualcosa in cambio». E lui dice: «No, non ti darò niente se tu non mi dai qualcosa». Ci troviamo quindi in una situazione di stallo. Sono sicuro che Ivan non farebbe una cosa simile, ma capite il senso: due persone vogliono ottenere qualcosa e non sono disposte a cederlo finché l'altra persona non dà loro ciò che desidera. E qui non c'è soluzione.

E, in sostanza, il vostro database deve identificarlo. E poi è necessario rimuovere o chiudere una delle sessioni, perché altrimenti rimarranno lì per sempre. E questo lo vediamo nei database, lo vediamo nei sistemi operativi. E in tutti i luoghi dove abbiamo processi paralleli, può succedere.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E ora creeremo due deadlock. Installeremo 50 e 80. Nella prima riga farò un aggiornamento da 50 a 50. Otterrò il numero di transazione 710.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ecco come apparirà. Pertanto, 710 ha il blocco della riga, mentre 711 attende una conferma. Lo abbiamo visto quando abbiamo effettuato l'aggiornamento. 710 è il proprietario della nostra riga. E 711 attende che 710 completi la transazione.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E lì è anche scritto in quale specifica riga si verificano i deadlock. Ed è qui che inizia a diventare strano.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ora stiamo aggiornando 80 su 80.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Ed è qui che iniziano i deadlock. 710 aspetta una risposta da 711, mentre 711 aspetta 710. E questo non avrà una buona conclusione. E non c'è via d'uscita. Aspetteranno una risposta l'uno dall'altro.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

In Postgres ci sono modi per rilevare quando ciò accade. E quando succede, si riceve un errore come questo. E da ciò è chiaro che un certo processo sta aspettando un SHARE LOCK da un altro processo, cioè bloccato dal processo 711. E quel processo stava aspettando che venisse dato un SHARE LOCK su un certo ID di transazione ed è stato bloccato da un certo processo. Pertanto, qui c'è una situazione di deadlock.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Esistono deadlock a tre vie? È possibile? Sì.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Inseriamo questi numeri nella tabella. Cambiamo 40 su 40, creiamo un blocco.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Cambiamo 60 su 61, 80 su 81.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E poi cambiamo 80, e poi - boom!

Sbloccare il Postgres Lock Manager. Bruce Momjian

E 714 ora aspetta 715. Il 716 attende il 715. E non si può fare nulla con questo.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Qui non ci sono più due persone, ma già tre. Voglio qualcosa da te, lui desidera qualcosa dal terzo, e il terzo vuole qualcosa da me. Ci troviamo quindi in un'attesa reciproca, poiché tutti aspettiamo che qualcun altro completi ciò che deve fare.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E Postgres sa in quale riga si verifica. Di conseguenza, ti fornirà il seguente messaggio che indica che hai un problema in cui tre input si bloccano a vicenda. E non ci sono limiti. Questo può accadere quando 20 registrazioni si bloccano a vicenda.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Il problema successivo è serializzabile.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Se c'è un blocco serializzabile speciale.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E torniamo a 719. Ha un'uscita del tutto normale.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E puoi cliccare per effettuare una transazione in modalità serializzabile.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E capisci che ora hai un altro tipo di blocco SA – questo significa serializzabile.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

Sbloccare il Postgres Lock Manager. Bruce Momjian

E puoi anche inserire indici unici.

Sbloccare il Postgres Lock Manager. Bruce Momjian

In questa tabella abbiamo indici unici.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Quindi, se inserisco il numero 2 qui, ho 2. Ma nella parte superiore inserisco un altro 2. E potete vedere che il 721 ha un blocco esclusivo. Ora, però, il 722 attende che il 721 completi la sua operazione, perché non può inserire 2 finché non sa cosa accadrà al 721.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se facciamo una subtransazione.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Qui abbiamo il 723.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E se salviamo il punto e poi lo aggiorniamo, otteniamo un nuovo ID di transazione. Questo è un altro comportamento che dovete conoscere. Se lo restituiamo, l'ID di transazione va via. Il 724 va via. Ma ora abbiamo il 725.

E cosa sto cercando di fare qui? Sto cercando di mostrarvi esempi di blocchi insoliti che potete incontrare: che si tratti di blocchi serializzabili o SAVEPOINT - sono diversi tipi di blocchi che appariranno nella tabella dei blocchi.

Sbloccare il Postgres Lock Manager. Bruce Momjian

Questo è il creare blocchi espliciti, che hanno pg_advisory_lock.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E vedete che il tipo di blocco è elencato qui come advisory. E in rosso c'è scritto 'advisory'. E potete bloccare simultaneamente con pg_advisory_unlock.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E infine vorrei mostrarvi un'altra cosa sorprendente. Creerò un altro tipo. Ma collegherò la tabella pg_locks con la tabella pg_stat_activity. E perché voglio farlo? Perché questo mi permetterà di vedere tutte le sessioni attuali e quali blocchi stanno aspettando. Ed è piuttosto interessante, quando uniamo la tabella dei blocchi con la tabella delle query.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E qui creiamo pg_stat_view.

Sbloccare il Postgres Lock Manager. Bruce Momjian

E aggiorniamo una riga di uno. E qui vediamo 724. Poi aggiorniamo la nostra riga a tre. E cosa vedete qui adesso? Queste sono le query, cioè vedete l'intero elenco delle query elencate nella colonna di sinistra. E poi, sul lato destro, potete vedere i blocchi e cosa stanno creando. E questo potrebbe risultarvi più chiaro, in modo da non dover tornare ogni volta a ogni sessione per vedere se è necessario unirsi o meno. Lo fa per noi.

Un'altra funzionalità che è molto utile è pg_blocking_pids. Probabilmente non ne hai mai sentito parlare. Cosa fa? Ci consente di dire quale ID processo 11740 sta aspettando per questa sessione. E puoi vedere che 11740 sta aspettando 724. E 724 è in cima. Mentre 11306 è il tuo ID processo. Fondamentalmente, questa funzione scorre la tua tabella di blocco. E so che è un po' complicato, ma riesci a capirlo. Fondamentalmente, questa funzione percorre questa tabella di blocco e cerca il processo ID, considerando i blocchi che sta aspettando. Prova anche a calcolare quale processo ID ha il processo in attesa di blocco. Quindi puoi eseguire questa funzione. pg_blocking_pids.

E questo può essere davvero utile. L'abbiamo aggiunto solo dalla versione 9.6, quindi questa funzione ha solo 5 anni, ma è molto, molto utile. Lo stesso vale per la seconda richiesta. Mostra esattamente ciò che abbiamo bisogno di vedere.

Sbloccare il Postgres Lock Manager. Bruce Momjian

È di questo che volevo parlarvi. E come mi aspettavo, abbiamo utilizzato tutto il nostro tempo, perché c'era un numero così elevato di diapositive. Le diapositive sono disponibili per il download. Vorrei ringraziarvi per essere stati qui. Sono sicuro che vi piacerà il resto della conferenza, grazie mille!

Domande:

Ad esempio, se sto cercando di aggiornare le righe e la seconda sessione sta cercando di eliminare l'intera tabella. Da quanto ho capito, ci dovrebbe essere qualcosa come un intent lock. Esiste qualcosa di simile in Postgres?

Sbloccare il Postgres Lock Manager. Bruce Momjian

Torniamo all'inizio. Forse ricorderete che quando fate qualsiasi cosa, ad esempio quando eseguite un SELECT, rilasciamo un AccessShareLock. E questo impedisce l'eliminazione della tabella. Quindi, se ad esempio volete aggiornare una riga in una tabella o eliminare una riga, qualcun altro non può eliminare l'intera tabella contemporaneamente, perché mantenete questo AccessShareLock su tutta la tabella e sulla riga. E una volta che avete finito, possono eliminarla. Ma finché state modificando qualcosa, non possono farlo.

Facciamo un altro esempio. Passiamo a un esempio di eliminazione. E vedete come ci sia un lock esclusivo su tutta la tabella.

Sarà simile a un lock esclusivo, giusto?

Sì, sembra così. Capisco cosa intendi. Stai dicendo che, se eseguo un SELECT, avrò ShareExclusive, e poi lo trasformo in uno stato Row Exclusive, questo diventa un problema? Ma sorprendentemente non crea problemi. Sembra un aumento del livello di blocco, ma in effetti ho un lock che impedisce la cancellazione. E ora, quando faccio questo lock più forte, continua a impedire la cancellazione. Quindi non è un aumento. Cioè, impediva già prima quando era a un livello inferiore, quindi, quando aumento il suo livello, continua a impedire la cancellazione della tabella.

Capisco cosa intendi. Qui non c'è un caso di aumento del livello di blocco, dove stai cercando di rinunciare a un lock per introdurne uno più potente. Qui si tratta semplicemente di un aumento generale di questa prevenzione, quindi non causa alcun conflitto. Ma è una bella domanda. Grazie mille per averla posta!

Cosa dobbiamo fare per evitare la situazione di deadlock quando abbiamo molte sessioni e un grande numero di utenti?

Postgres rileva automaticamente situazioni di deadlock e rimuoverà automaticamente una delle sessioni. L'unico modo per evitare situazioni di deadlock è bloccare le entità nello stesso ordine. Pertanto, quando esamini la tua applicazione, spesso la causa dei deadlock è... Immaginiamo che io voglia bloccare due cose diverse. Un'applicazione blocca la tabella 1, mentre un'altra blocca la tabella 2 e poi la tabella 1. Il modo più semplice per evitare i deadlock è assicurarti che il blocco avvenga sempre nello stesso ordine in tutte le applicazioni. Questo generalmente elimina l'80% dei problemi, poiché diversi sviluppatori scrivono queste applicazioni. Se le blocchi nello stesso ordine, non ti troverai ad affrontare situazioni di deadlock.

Grazie mille per il tuo intervento! Hai parlato di vacuum full e, se non sbaglio, vacuum full altera l'ordine delle righe in uno storage separato, quindi mantiene le righe esistenti inalterate. Ma perché vacuum full richiede un blocco esclusivo e perché confligge con le operazioni di scrittura?

È una buona domanda. La ragione è che vacuum full prende la tabella. E, in sostanza, stiamo creando una nuova versione della tabella. La tabella sarà nuova. Risulta che sarà una versione completamente nuova della tabella. E il problema è che, quando facciamo questo, non vogliamo che le persone la leggano, perché dobbiamo assicurarci che vedano la nuova tabella. E quindi questo si collega alla domanda precedente. Se potessimo leggere contemporaneamente, non saremmo in grado di spostarla e indirizzare le persone alla nuova tabella. Dovremmo attendere che tutti finissero di leggere questa tabella, quindi, in sostanza, si tratta di una situazione di lock esclusivo.
Noi semplicemente affermiamo che blocchiamo fin dall'inizio, perché sappiamo che alla fine avremo bisogno di un blocco esclusivo per spostare tutti su una nuova copia. Quindi, potenzialmente, possiamo risolvere questo. E lo facciamo con un indicizzazione simultanea. Ma è molto più complicato da realizzare. E questo si ricollega molto alla tua domanda precedente sul lock esclusivo.

È possibile aggiungere un tempo di attesa per il blocco in Postgres? In Oracle posso, ad esempio, scrivere “seleziona per aggiornare” e attendere 50 secondi per l'aggiornamento. Questo andava bene per l'applicazione. Ma in Postgres, o devo farlo subito e non aspettare affatto, oppure attendere fino a un certo tempo.

Sì, puoi selezionare un timeout per i tuoi blocchi. Puoi anche emettere il comando no way, che sarà... se non riesci a ottenere immediatamente il blocco. Quindi, o lock timeout, o qualcos'altro che ti permetterà di farlo. Questo non si fa a livello sintattico. Si fa come variabile sul server. A volte non può essere usato.

Puoi aprire 75 slide?

Sì.

Sbloccare il Postgres Lock Manager. Bruce Momjian

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

E questa è una domanda interessante. Non capisco perché Postgres lo faccia. Quando 703 è stato creato, si aspettava 702. E quando 704 e 705 appaiono, sembra che non sappiano cosa stanno aspettando, perché non c'è ancora nulla. E Postgres agisce in questo modo: quando non riesci a ottenere un blocco, scrive "Qual è il senso di elaborarti?", perché stai già aspettando qualcuno. Quindi semplicemente lo lasciamo lì, non aggiorna affatto. Ma cosa è successo qui? Non appena 702 ha completato il processo e 703 ha ottenuto il suo blocco, il sistema è tornato indietro. E ha detto che ora abbiamo due persone in attesa. E poi aggiorniamole insieme. E indichiamo che entrambi aspettano.

Non so perché Postgres si comporti in questo modo. Ma c'è un problema chiamato f…. Sembra che non sia un termine russo. È quando tutti aspettano lo stesso lock, anche se ci sono 20 istanze che aspettano il lock. E all'improvviso si svegliano tutti insieme. E tutti iniziano a cercare di reagire. Ma il sistema fa in modo che tutti aspettino 703. Perché tutti stanno aspettando, e li metteremo immediatamente in coda. E se appare qualsiasi altra nuova richiesta, generata dopo questa, per esempio 707, ci sarà di nuovo un vuoto.

E penso che questo venga fatto per poter dire che in questa fase 702 sta aspettando 703, e tutti quelli che arriveranno dopo non avranno nessuna registrazione in questo campo. Ma appena il primo in attesa se ne va, tutti quelli che aspettavano in quel momento prima dell'aggiornamento ricevono lo stesso marker. E quindi, credo sia stato fatto per poter gestire in ordine, in modo che fossero correttamente ordinati.

Ho sempre visto questo come un fenomeno piuttosto strano. Perché qui, ad esempio, non li elenchiamo affatto. Ma credo che ogni volta che diamo un nuovo blocco, guardiamo a tutti coloro che sono in attesa. Allora li mettiamo tutti in coda. E poi, qualsiasi nuovo arrivo viene messo in coda solo quando la persona successiva ha terminato di essere elaborata. Ottima domanda. Grazie mille per la domanda!

Mi sembra molto più logico quando il 705 attende il 704.

Ma il problema è il seguente. Tecnicamente puoi risvegliare l'uno o l'altro. E quindi risveglieremo quello o l'altro. Ma cosa succede nel funzionamento del sistema? Vedi come 703 in cima ha bloccato il proprio ID di transazione. Questo è il modo in cui funziona Postgres. E 703 è bloccato dal suo stesso ID di transazione, quindi, se qualcuno vuole aspettare, dovrà aspettare 703. E, in sostanza, 703 si completa. Solo dopo il suo completamento, uno dei processi si risveglia. E non sappiamo quale sarà esattamente questo processo. Poi elaboriamo gradualmente tutto. Ma non è chiaro quale processo si risveglierà per primo, perché potrebbe essere uno qualsiasi di questi processi. Fondamentalmente, avevamo uno scheduler che diceva che ora possiamo risvegliare uno qualsiasi di questi processi. Scegliamo semplicemente uno a caso. Pertanto, entrambi devono essere contrassegnati, perché possiamo risvegliare uno qualsiasi di essi.

E il problema è che abbiamo la CP-infinito. E quindi è molto probabile che possiamo risvegliare quello più tardi. E se, ad esempio, risvegliamo quello più tardi, ci aspetteremo colui che ha appena ricevuto un blocco, quindi non definiamo chi sarà risvegliato per primo. Creiamo semplicemente una situazione del genere e il sistema li risveglierà in ordine casuale.

articoli sui locks di Egor Rogov. Guarda, sono anche interessanti e utili. L'argomento è, ovviamente, estremamente complesso. Grazie mille, Bruce!

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster