Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Transcrición da charla de 2020 de Bruce Momjian "Desbloqueando o xestor de bloqueos de Postgres".

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

(Nota: todas as consultas SQL das diapositivas pódense obter nesta ligazón: http://momjian.us/main/writings/pgsql/locking.sql)

Ola! É xenial estar aquí de novo en Rusia. Sinto non poder vir o ano pasado, pero este ano Ivan e eu temos grandes plans. Espero estar aquí moito máis a miúdo. Encántame vir a Rusia. Visitarei Tyumen, Tver. Alégrome moito de poder visitar estas cidades.

Chámome Bruce Momjian. Traballo en EnterpriseDB e levo máis de 23 anos traballando con Postgres. Vivo en Filadelfia, Estados Unidos. Viaxo uns 90 días ao ano. E asisto a unhas 40 conferencias. Meu Sitio web, que contén as diapositivas que agora vos mostrarei. Por iso, despois da conferencia podedes descargalos da miña páxina web persoal. Tamén contén unhas 30 presentacións. Tamén hai vídeos e un gran número de entradas no blog, máis de 500. Trátase dun recurso bastante informativo. E se estás interesado neste material, invito a que o uses.

Eu fun profesor, profesor antes de comezar a traballar con Postgres. E alégrome moito de poder contarvos agora o que vos vou dicir. Esta é unha das miñas presentacións máis interesantes. E esta presentación contén 110 diapositivas. Comezaremos a falar de cousas sinxelas, e ao final o informe será cada vez máis complexo, e será bastante complexo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Esta é unha conversa bastante desagradable. O bloqueo non é o tema máis popular. Queremos que isto desapareza nalgún lugar. É como ir ao dentista.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

  1. O bloqueo é un problema para moitas persoas que traballan en bases de datos e teñen varios procesos en execución ao mesmo tempo. Necesitan bloqueo. É dicir, hoxe vouche dar coñecementos básicos sobre o bloqueo.
  2. ID de transacción. Esta é unha parte bastante aburrida da presentación, pero hai que entendelas.
  3. A continuación falaremos dos tipos de bloqueo. Esta é unha parte bastante mecánica.
  4. E a continuación daremos algúns exemplos de bloqueo. E será bastante difícil de entender.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Falemos de bloqueo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

A nosa terminoloxía é bastante complexa. Cantos de vós sabedes de onde vén esta pasaxe? Dúas persoas. Isto é dun xogo chamado Colossal Cave Adventure. Era un xogo de ordenador baseado en texto nos anos 80, creo. Alí había que entrar nunha cova, nun labirinto, e o texto cambiaba, pero o contido era aproximadamente o mesmo cada vez. Así lembro este xogo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E aquí vemos o nome dos peches que nos chegaron de Oracle. Usámolas.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Aquí vemos termos que me confunden. Por exemplo, COMPARTIR ACTUALIZACIÓN ECXLUSIVE. Seguinte COMPARTIR RAW ECXLUSIVE. Para ser honesto, estes nomes non están moi claros. Tentaremos consideralos con máis detalle. Algúns conteñen a palabra "compartir", que significa separar. Algúns conteñen a palabra "exclusivo". Algúns conteñen estas dúas palabras. Gustaríame comezar co funcionamento destes bloqueos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E a palabra "acceso" tamén é moi importante. E as palabras "fila" son unha cadea. É dicir, distribución de acceso, distribución de filas.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Outro tema que hai que entender en Postgres, que lamentablemente non poderei tratar na miña charla, é MVCC. Teño unha presentación separada sobre este tema no meu sitio web. E se pensas que esta presentación é difícil, MVCC é probablemente o meu máis difícil. E se estás interesado, podes velo na páxina web. Podes ver o vídeo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Outra cousa que debemos entender son os ID de transacción. Moitas transaccións non poden funcionar sen identificadores únicos. E aquí temos unha explicación do que é unha transacción. Postgres ten dous sistemas de numeración de transaccións. Sei que esta non é unha solución moi bonita.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Tamén hai que ter en conta que as diapositivas serán bastante difíciles de entender, polo que o que está resaltado en vermello é ao que debes prestar atención.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

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

Vexamos. O número de transacción está resaltado en vermello. A función SELECT pg_back móstrase aquí. Devolve a miña transacción e o ID da transacción.

Unha cousa máis, se che gusta esta presentación e queres executala na túa base de datos, podes ir a esta ligazón en rosa e descargar o SQL para esta presentación. E pode simplemente executalo no seu PSQL e toda a presentación estará na súa pantalla inmediatamente. Non conterá flores, pero polo menos podemos velo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Neste caso vemos o ID da transacción. Este é o número que lle asignamos. E hai outro tipo de ID de transacción en Postgres, que se chama ID de transacción virtual

E debemos entender isto. Isto é moi importante, se non, non poderemos entender o bloqueo en Postgres.

Un ID de transacción virtual é un ID de transacción que non contén valores persistentes. Por exemplo, se executo un comando SELECT, o máis probable é que non cambie a base de datos, non bloquearei nada. Entón, cando executamos un simple SELECT, non lle damos a esa transacción un ID persistente. Alí só lle damos un DNI virtual.

E isto mellora o rendemento de Postgres, mellora as capacidades de limpeza, polo que o ID de transacción virtual consta de dous números. O primeiro número antes da barra inclinada é o ID do backend. E á dereita vemos só un contador.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Polo tanto, se realizo unha solicitude, di que o ID do backend é 2.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se realizo unha serie de tales transaccións, vemos que o contador aumenta cada vez que realizo unha consulta. Por exemplo, cando executo a consulta 2/10, 2/11, 2/12, etc.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Teña en conta que aquí hai dúas columnas. Á esquerda vemos o ID da transacción virtual: 2/12. E á dereita temos un ID de transacción permanente. E este campo está baleiro. E esta transacción non modifica a base de datos. Polo tanto, non lle dou un ID de transacción permanente.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

En canto executo o comando de análise ((ANALYZE)), a mesma consulta dáme un ID de transacción permanente. Mirade como cambiou isto para nós. Antes non tiña esta identificación, pero agora téñoa.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Entón, aquí hai outra solicitude, outra transacción. O número de transacción virtual é 2/13. E se pido un ID de transacción persistente, cando execute a consulta, conseguireina.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Entón, unha vez máis. Temos un ID de transacción virtual e un ID de transacción persistente. Só entende este punto para comprender o comportamento de Postgres.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Pasamos á terceira sección. Aquí simplemente percorreremos os diferentes tipos de peches en Postgres. Non é moi interesante. O último apartado será moito máis interesante. Pero hai que ter en conta as cousas básicas, porque se non, non entenderemos que pasará despois.

Pasaremos por esta sección, veremos cada tipo de bloqueo. E mostrareiche exemplos de como se instalan, como funcionan, mostrareiche algunhas consultas que podes usar para ver como funciona o bloqueo en Postgres.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Para crear unha consulta e ver o que está a suceder en Postgres, necesitamos emitir a consulta na vista do sistema. Neste caso, pg_lock está resaltado en vermello. Pg_lock é unha táboa do sistema que nos indica cales bloqueos están en uso actualmente en Postgres.

Non obstante, é moi difícil para min mostrarche pg_lock por si só porque é bastante complexo. Entón creei unha vista que mostra pg_locks. E tamén me fai un traballo que me permite entender mellor. É dicir, exclúe os meus bloqueos, a miña propia sesión, etc. É só SQL estándar e permíteche mostrar mellor o que está a suceder.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Outro problema é que esta vista é moi ampla, polo que teño que crear unha segunda: lockview2.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian E móstrame máis columnas da táboa. E outra que me mostra o resto das columnas. Isto é bastante complexo, polo que tentei presentalo o máis sinxelo posible.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Así que creamos unha táboa chamada Lockdemo. E creamos unha liña alí. Esta é a nosa táboa de mostra. E imos crear seccións só para mostrarche exemplos de bloqueos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Entón, unha fila, unha columna. O primeiro tipo de bloqueo chámase ACCESO COMPARTIR. Este é o bloqueo menos restritivo. Isto significa que practicamente non entra en conflito con outros bloqueos.

E se queremos definir explícitamente un bloqueo, executamos o comando "bloquear táboa". E obviamente bloquearase, é dicir, no modo ACCESO COMPARTIR iniciamos a táboa de bloqueo. E se executo PSQL en segundo plano, comezo a segunda sesión desde a miña primeira sesión deste xeito. É dicir, que farei aquí? Vou a outra sesión e dígolle "mostrame a vista de bloqueo para esta solicitude". E aquí teño AccessShareLock nesta táboa. Isto é exactamente o que pedín. E di que o bloque foi asignado. Moi sinxelo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Ademais, se miramos a segunda columna, entón non hai nada alí. Están baleiros.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se executo o comando "SELECT", entón esta é a forma implícita (explícita) de solicitar AccessShareLock. Entón, solto a miña táboa e executo a consulta e a consulta devolve varias filas. E nunha das liñas vemos AccessShareLock. Así, SELECT chama a AccessShareLock sobre a mesa. E non entra en conflito con practicamente nada porque é un bloqueo de baixo nivel.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se executo un SELECT e teño tres táboas diferentes? Anteriormente só estaba a executar unha táboa, agora estou executando tres: pg_class, pg_namespace e pg_attribute.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E agora, cando miro a consulta, vexo 9 AccessShareLocks en tres táboas. Por que? Tres táboas están resaltadas en azul: pg_attribute, pg_class, pg_namespace. Pero tamén podes ver que todos os índices que se definen a través destas táboas tamén teñen AccessShareLock.

E este é un bloqueo que practicamente non entra en conflito cos demais. E o único que fai é simplemente evitar que reiniciemos a táboa mentres a seleccionamos. Ten sentido. É dicir, se seleccionamos unha táboa, esta desaparece nese momento, entón isto está mal, entón AccessShare é un bloqueo de baixo nivel que nos di "non solte esta táboa mentres estou a traballar". Esencialmente, iso é todo o que fai.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

COMPARTIR FILA: este bloqueo é un pouco diferente.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Poñamos un exemplo. método SELECT ROW SHARE para bloquear cada fila individualmente. Deste xeito ninguén pode borralos nin cambialos mentres os vemos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce MomjianEntón, que fai SHARE LOCK? Vemos que o ID da transacción é 681 para SELECT. E isto é interesante. Que pasou aquí? A primeira vez que vemos o número é no campo "Bloquear". Tomamos o ID da transacción e di que o está bloqueando en modo exclusivo. Todo o que fai é que di que teño unha fila que está tecnicamente bloqueada nalgún lugar da táboa. Pero non di onde exactamente. Veremos isto con máis detalle un pouco máis tarde.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Aquí dicimos que a pechadura é usada por nós.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Entón, un bloqueo exclusivo di explícitamente que é exclusivo. E tamén se eliminas unha fila nesta táboa, isto é o que sucederá, como podes ver.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

SHARE EXCLUSIVE é un bloqueo máis longo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Este é o comando do analizador (ANALYZE) que se utilizará.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

BLOQUEO COMPARTIR: podes bloquear explícitamente no modo de compartir.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Tamén pode crear un índice único. E alí podes ver SHARE LOCK, que forma parte deles. E pecha a mesa e ponlle un LOCK DE COMPARTIR.

Por defecto, COMPARTIR BLOQUEO nunha táboa significa que outras persoas poden ler a táboa, pero ninguén pode modificala. E isto é exactamente o que ocorre cando creas un índice único.

Se creo un índice concurrente único, entón terei un tipo de bloqueo diferente porque, como lembras, usar índices simultáneamente reduce o requisito de bloqueo. E se uso un bloqueo normal, un índice normal, entón impedirei escribir no índice da táboa mentres se crea. Se uso un índice simultáneamente, entón teño que usar un tipo de bloqueo diferente.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

COMPARTIR FILA EXCLUSIVA: de novo pódese configurar de forma explícita (explícita).

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Ou podemos crear unha regra, é dicir, tomar un caso específico no que se utilizará.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

O bloqueo EXCLUSIVO significa que ninguén máis pode cambiar a mesa.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Aquí vemos diferentes tipos de peches.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

ACCESS EXCLUSIVE, por exemplo, é un comando de bloqueo. Por exemplo, se o fas CLUSTER table, entón isto significará que ninguén poderá escribir alí. E bloquea non só a táboa en si, senón tamén os índices.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Esta é a segunda páxina do bloqueo ACCESS EXCLUSIVE, onde vemos exactamente o que bloquea na táboa. Bloquea filas individuais da táboa, o que é bastante interesante.

Esa é toda a información básica que quería dar. Falamos de bloqueos, de ID de transacción, de ID de transacción virtuais, de ID de transacción permanente.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E agora imos pasar por algúns exemplos de bloqueo. Esta é a parte máis interesante. Veremos casos moi interesantes. E o meu obxectivo nesta presentación é darlle unha mellor comprensión do que realmente está facendo Postgres cando intenta bloquear certas cousas. Creo que é moi bo para bloquear partes.

Vexamos algúns exemplos específicos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Comezaremos con táboas e unha fila nunha táboa. Cando insiro algo, aparecen na táboa ExclusiveLock, ID de transacción e ExclusiveLock.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Que pasa se insiro dúas filas máis? E agora a nosa táboa ten tres filas. E inseriu unha fila e obtiven isto como saída. E se inserio dúas filas máis, que hai de raro? Hai algo raro aquí porque engadín tres filas a esta táboa, pero aínda teño dúas filas na táboa de bloqueo. E este é esencialmente o comportamento fundamental de Postgres.

Moita xente pensa que se bloqueas 100 filas nunha base de datos, terás que crear 100 entradas de bloqueo. Se bloqueo 1 filas á vez, necesitarei 000 consultas deste tipo. E se necesito un millón ou mil millóns para bloquear. Pero se facemos isto, non funcionará moi ben. Se utilizaches un sistema que crea entradas de bloqueo para cada fila individual, podes ver que isto é complicado. Porque cómpre definir inmediatamente unha táboa de bloqueo que poida desbordarse, pero Postgres non o fai.

E o que é realmente importante desta diapositiva é que demostra claramente que hai outro sistema que se executa dentro de MVCC que bloquea filas individuais. Entón, cando bloquea miles de millóns de filas, Postgres non crea mil millóns de comandos de bloqueo separados. E isto ten un efecto moi bo sobre a produtividade.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Que tal unha actualización? Estou actualizando a fila agora, e podes ver que realizou dúas operacións diferentes á vez. Bloqueou a táboa ao mesmo tempo, pero tamén bloqueou o índice. E necesitaba bloquear o índice porque hai restricións únicas nesta táboa. E queremos asegurarnos de que ninguén o cambie, polo que o bloqueamos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Que pasa se quero actualizar dúas filas? E vemos que se comporta do mesmo xeito. Facemos o dobre de actualizacións, pero exactamente o mesmo número de liñas de bloqueo.

Se estás a preguntar como fai isto Postgres, terás que escoitar as miñas charlas sobre MVCC para saber como Postgres marca internamente estas liñas que cambia. E Postgres ten unha forma de facelo, pero non o fai no nivel de bloqueo da táboa, faino nun nivel máis baixo e máis eficiente.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se quero eliminar algo? Se borro, por exemplo, unha fila e aínda teño as miñas dúas entradas de bloqueo, e aínda que queira eliminalas todas, aínda están aí.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E, por exemplo, quero inserir 1 liñas, e despois eliminar ou engadir 000 liñas, entón esas liñas individuais que engado ou cambio, non están rexistradas aquí. Están escritos nun nivel inferior dentro da propia serie. E durante a intervención do MVCC falei diso en detalle. Pero é moi importante cando estás a analizar bloqueos para asegurarte de que estás bloqueando a nivel de táboa e de que non estás vendo como se rexistran as filas individuais aquí.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E o bloqueo explícito?

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Se fago clic en actualizar, teño dúas filas bloqueadas. E se os selecciono todos e fago clic en "actualizar en todas partes", aínda teño dous rexistros de bloqueo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Non creamos rexistros separados para cada fila individual. Porque entón a produtividade cae, pode haber demasiado. E podemos atoparnos nunha situación desagradable.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E o mesmo, se compartimos, podemos facelo as 30 veces.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Restauramos a nosa táboa, borramos todo e despois inserimos unha fila de novo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Outro comportamento que ves en Postgres que é moi coñecido e desexado é que podes facer unha actualización ou unha selección. E podes facelo ao mesmo tempo. E seleccionar non bloquea actualización e o mesmo na dirección oposta. Dicímoslle ao lector que non bloquee ao escritor, e o escritor non bloqueou ao lector.

Vouche mostrar un exemplo diso. Vou facer unha elección agora. Despois faremos o INSERTAR. E entón podes ver - 694. Podes ver o ID da transacción que realizou esta inserción. E así funciona.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se miro o meu ID de backend agora, agora é 695.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E podo ver 695 aparecendo na miña táboa.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se actualizo aquí así, entón teño un caso diferente. Neste caso, 695 é un bloqueo exclusivo e a actualización ten o mesmo comportamento, pero non hai conflito entre eles, o que é bastante inusual.

E podes ver que na parte superior está ShareLock, e na parte inferior é ExclusiveLock. E ambas as transaccións funcionaron.

E cómpre escoitar a miña charla no MVCC para entender como ocorre isto. Pero esta é unha ilustración de que podes facelo ao mesmo tempo, é dicir, facer unha SELECCIÓN e unha ACTUALIZACIÓN ao mesmo tempo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Resetemos e fagamos unha operación máis.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Se tentas executar dúas actualizacións á vez na mesma fila, bloquearase. E lembre, dixen que o lector non bloquea o escritor, e o escritor non bloquea o lector, pero un escritor bloquea outro escritor. É dicir, non podemos que dúas persoas actualicen a mesma fila ao mesmo tempo. Hai que esperar ata que remate un deles.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E para ilustralo, mirarei a táboa de Lockdemo. E veremos unha fila. Por transacción 698.

Actualizamos isto a 2. 699 é a primeira actualización. E tivo éxito ou está nunha transacción pendente e está á espera de que confirmemos ou cancelemos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Pero mira outra cousa: 2/51 é a nosa primeira transacción, a nosa primeira sesión. 3/112 é a segunda solicitude que veu da parte superior que cambiou ese valor a 3. E se observas, a superior bloqueouse, que é 699. Pero 3/112 non concedeu o bloqueo. A columna Lock_mode indica o que está esperando. Espera 699. E se miras onde está 699, é máis alto. E que fixo a primeira sesión? Creou un bloqueo exclusivo no seu propio ID de transacción. Así o fai Postgres. Bloquea o seu propio ID de transacción. E se queres esperar a que alguén confirme ou cancele, entón tes que esperar mentres haxa unha transacción pendente. E por iso podemos ver unha liña estraña.

Vexamos de novo. Á esquerda vemos o noso ID de procesamento. Na segunda columna vemos o noso ID de transacción virtual, e na terceira vemos lock_type. Que significa isto? Esencialmente, o que di é que está bloqueando o ID da transacción. Pero teña en conta que todas as filas da parte inferior din relación. E así tes dous tipos de peches sobre a mesa. Hai un bloqueo de relación. E despois está o bloqueo de transacción, onde se bloquea por conta propia, que é exactamente o que ocorre na primeira fila ou na parte inferior, onde está o transacción, onde agardamos a que 699 remate a súa operación.

Vou ver que pasa aquí. E aquí suceden dúas cousas á vez. Estás mirando un bloqueo de ID de transacción na primeira fila que se bloquea por si mesmo. E bloquea-se para facer esperar á xente.

Se miras a 6ª liña, é a mesma entrada que a primeira. E polo tanto, a transacción 699 está bloqueada. 700 tamén é de bloqueo automático. E despois na fila inferior verás que estamos agardando a que 699 remate a súa operación.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E en lock_type, tupla ves números.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Podes ver que é 0/10. E este é o número de páxina e tamén a compensación desta fila en particular.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E ves que pasa a ser 0/11 cando actualizamos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Pero en realidade é 0/10, porque hai unha espera para esta operación. Temos a oportunidade de ver que esta é a serie que estou pendente de confirmar.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Unha vez que o confirmamos e prememos confirmar, e cando remate a actualización, isto é o que obtemos de novo. A transacción 700 é o único bloqueo, non espera a ninguén porque se comprometeu. Simplemente agarda a que se complete a transacción. Unha vez que se esgota o 699, xa non agardamos por nada. E agora a transacción 700 di que todo está ben, que ten todos os bloqueos que necesita en todas as táboas permitidas.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E para complicar aínda máis todo isto, creamos outra vista, que esta vez nos proporcionará unha xerarquía. Non espero que entenda esta petición. Pero isto daranos unha visión máis clara do que está a suceder.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Esta é unha vista recursiva que tamén ten outra sección. E entón reúne todo de novo. Usemos isto.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se facemos tres actualizacións simultáneas e dicimos que a fila agora son tres. E cambiaremos de 3 a 4.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E aquí vemos 4. E a ID de transacción 702.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E despois cambiarei de 4 a 5. E de 5 a 6 e de 6 a 7. E poñerei en fila a varias persoas que estarán esperando a que finalice esta transacción.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E todo queda claro. Cal é a primeira fila? Este é 702. Este é o ID de transacción que estableceu orixinalmente este valor. Que está escrito na miña columna Concedido? Teño marcas f. Estas son as miñas actualizacións que (5, 6, 7) non se poden aprobar porque estamos esperando a que finalice a ID de transacción 702. Alí temos o bloqueo de ID de transacción. E isto dá lugar a 5 bloqueos de identificación transaccional.

E se miras no 704, no 705, aínda non hai nada escrito alí, porque aínda non saben o que está a pasar. Simplemente escriben que non teñen nin idea do que está a pasar. E só irán durmir porque están esperando a que alguén remate e se esperte cando teña a oportunidade de cambiar de fila.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Isto é o que parece. Está claro que todos están á espera da 12a liña.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Isto é o que vimos aquí. Aquí está 0/12.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Polo tanto, unha vez que se aprobe a primeira transacción, podes ver aquí como funciona a xerarquía. E agora todo queda claro. Quedan todos limpos. E en realidade seguen esperando.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Velaquí o que está a pasar. 702 compromisos. E agora 703 obtén este bloqueo de fila e, a continuación, 704 comeza a esperar a que 703 se comprometa. E o 705 tamén está esperando por isto. E cando todo isto está rematado, limpanse. E quero sinalar que todo o mundo está facendo cola. E isto é moi semellante a unha situación nun atasco cando todos esperan o primeiro coche. O primeiro coche para e todos fan cola nunha longa fila. Despois móvese, entón o seguinte coche pode avanzar e conseguir o seu bloqueo, etc.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se isto non che pareceu o suficientemente complicado, agora falaremos sobre os puntos mortos. Non sei cal de vós os atopou. Este é un problema bastante común nos sistemas de bases de datos. Pero os bloqueos son cando unha sesión está esperando a que outra sesión faga algo. E neste momento outra sesión está á espera da primeira sesión para facer algo.

E, por exemplo, se Iván di: "Dáme algo", e eu digo: "Non, só cho darei se me das outra cousa". E di: "Non, non cho darei se non mo das". E acabamos nunha situación de impasse. Estou seguro de que Iván non o fará, pero entendes o que significa que temos dúas persoas que queren conseguir algo e non están dispostas a regalarllo ata que a outra persoa lles dea o que queren. E non hai solución.

E esencialmente, a súa base de datos debe detectar isto. E entón cómpre eliminar ou pechar unha das sesións, porque se non, permanecerán alí para sempre. E vémolo nas bases de datos, vémolo nos sistemas operativos. E en todos os lugares onde temos procesos paralelos, isto pode ocorrer.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E agora instalaremos dous bloqueos. Poñeremos 50 e 80. Na primeira fila, actualizarei de 50 a 50. Terei o número de transacción 710.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E entón cambiarei de 80 a 81 e de 50 a 51.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E así se verá. Así, 710 ten unha fila bloqueada e 711 está á espera de confirmación. Vimos isto cando actualizamos. 710 é o propietario da nosa serie. E 711 agarda a que 710 complete a transacción.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E mesmo di en que fila se producen os bloqueos. E aquí é onde comeza a ser raro.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Agora estamos actualizando 80 a 80.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E aquí é onde comezan os bloqueos. 710 está esperando unha resposta do 711, e 711 está á espera de 710. E isto non acabará ben. E non hai saída disto. E esperarán unha resposta uns dos outros.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E só comezará a atrasar todo. E iso non queremos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E Postgres ten formas de notar cando isto ocorre. E cando isto ocorre, recibe este erro. E disto queda claro que tal ou cal proceso está á espera dun BLOQUEO COMPARTIR doutro proceso, é dicir, que está bloqueado polo proceso 711. E ese proceso estaba á espera de que se dese un BLOQUEO COMPARTIR a tal ou cal ID de transacción e foi bloqueado por tal ou cal proceso. Polo tanto, aquí hai unha situación de bloqueo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Hai bloqueos de tres vías? É posible? Si.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Introducimos estes números nunha táboa. Cambiamos de 40 a 40, facemos bloqueo.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Cambiamos 60 por 61, 80 por 81.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E despois cambiamos 80 e despois boom!

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E agora o 714 está esperando polo 715. O 716 está esperando polo 715. E nada se pode facer ao respecto.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Aquí xa non hai dúas persoas, aquí xa hai tres. Quero algo de ti, este quere algo dunha terceira persoa e a terceira persoa quere algo de min. E acabamos nunha espera de tres vías porque todos estamos esperando a que a outra persoa complete o que ten que facer.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E Postgres sabe en que fila ocorre isto. E así darache a seguinte mensaxe, que mostra que tes un problema no que tres entradas se bloquean entre si. E aquí non hai restricións. Este pode ser o caso en que 20 entradas se bloqueen entre si.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

O seguinte problema é serializable.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Se bloqueo especial serializable.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E volvemos ao 719. A súa saída é bastante normal.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E pode facer clic para facer a transacción desde serializable.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E dás conta de que agora tes un tipo diferente de bloqueo SA - que significa serializable.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E por iso temos un novo tipo de bloqueo chamado SARieadLock, que é un bloqueo de serie e permite introducir series.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E tamén pode inserir índices únicos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Nesta táboa temos índices únicos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Entón, se poño aquí o número 2, entón teño un 2. Pero na parte superior, poño outro 2. E podes ver que o 721 ten un bloqueo exclusivo. Pero agora 722 está á espera de que 721 complete a súa operación porque non pode inserir 2 ata que se saiba o que pasará co 721.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se facemos subtransacción.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Aquí temos 723.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E se gardamos o punto e despois o actualizamos, obtemos un novo ID de transacción. Este é outro patrón de comportamento que debes ter en conta. Se devolvemos isto, o ID da transacción desaparecerá. 724 marcha. Pero agora temos 725.

Entón, que estou intentando facer aquí? Estou tentando mostrarche exemplos de bloqueos pouco habituais que podes atopar: xa sexan bloqueos serializables ou SAVEPOINT, estes son diferentes tipos de bloqueos que aparecerán na táboa de bloqueos.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Esta é a creación de bloqueos explícitos (explícitos), que teñen pg_advisory_lock.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E ves que o tipo de bloqueo aparece como asesor. E aquí di "asesor" en vermello. E podes bloquear simultáneamente así con pg_advisory_unlock.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E para rematar, gustaríame mostrarvos unha cousa máis alucinante. Vou crear outra vista. Pero vou unirme á táboa pg_locks coa táboa pg_stat_activity. E por que quero facer isto? Porque isto permitirame mirar e ver todas as sesións actuais e ver exactamente que tipo de bloqueos están esperando. E isto é bastante interesante cando xuntamos a táboa de bloqueo e a táboa de consultas.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E aquí creamos pg_stat_view.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E actualizamos a fila por unha. E aquí vemos 724. E despois actualizamos a nosa fila a tres. E agora que ves aquí? Estas son solicitudes, é dicir, verás a lista completa de solicitudes que aparecen na columna da esquerda. E despois no lado dereito podes ver os bloqueos e o que crean. E pode ser máis claro para ti para que non teñas que volver a cada sesión cada vez e ver se necesitas unirte a ela ou non. Fano por nós.

Outra característica que é moi útil é pg_blocking_pids. Probablemente nunca escoitou falar dela. Que está facendo ela? Permítenos dicir que para esta sesión 11740 que ID de proceso específico está esperando. E podes ver que 11740 está esperando por 724. E 724 está na parte superior. E 11306 é o teu ID de proceso. Esencialmente, esta función pasa pola súa táboa de bloqueo. E sei que é un pouco complicado, pero logras entendelo. Esencialmente, esta función pasa por esta táboa de bloqueos e tenta atopar onde se lle dá a este ID de proceso os bloqueos que está esperando. E tamén tenta descubrir que ID de proceso ten o proceso que está esperando polo bloqueo. Entón pode executar esta función pg_blocking_pids.

E isto pode ser moi útil. Só engadimos isto na versión 9.6, polo que esta función ten só 5 anos, pero é moi, moi útil. E o mesmo ocorre coa segunda solicitude. Mostra exactamente o que necesitamos ver.

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Isto é do que quería falarche. E como esperaba, gastamos todo o tempo porque había moitas diapositivas. E as diapositivas están dispoñibles para descargar. Gustaríame darche as grazas por estar aquí. Seguro que gozarás do resto da conferencia, moitas grazas!

Preguntas:

Por exemplo, se estou tentando actualizar filas e a segunda sesión está tentando eliminar toda a táboa. Polo que entendo, debería haber algo así como un bloqueo de intención. Existe tal cousa en Postgres?

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

Volvamos ao principio. Podes lembrar que cando fas calquera cousa, por exemplo cando fas un SELECT, emitimos un AccessShareLock. E iso evita que a mesa se caia. Entón, se, por exemplo, quere actualizar unha fila dunha táboa ou eliminar unha fila, entón alguén non pode eliminar a táboa completa ao mesmo tempo porque está mantendo este AccessShareLock sobre toda a táboa e sobre a fila. E unha vez que remates, poden borralo. Pero mentres cambias algo directamente alí, eles non poderán facelo.

Imos facelo de novo. Pasemos ao exemplo de eliminación. E ves como hai un bloqueo exclusivo na fila por riba de toda a táboa.

Isto parecerá un bloqueo exclusivo, non?

Si, así o parece. Entendo do que estás a falar. Estás dicindo que se fago un SELECT, entón teño un ShareExclusive e despois o fago en Row Exclusive, convértese iso nun problema? Pero, sorprendentemente, isto non supón ningún problema. Isto parece aumentar o grao de bloqueo, pero esencialmente teño un bloqueo que impide a eliminación. E agora, cando fago este bloqueo máis potente, aínda impide a eliminación. Entón non é que suba. É dicir, tamén impediu que ocorrese cando estaba a un nivel inferior, polo que cando subo o seu nivel aínda impide que se elimine a táboa.

Entendo do que estás a falar. Non hai ningún caso de escalada de bloqueo aquí, onde estás tentando renunciar a un bloqueo para introducir outro máis forte. Aquí só aumenta esta prevención en todos os ámbitos, polo que non causa ningún conflito. Pero é unha boa pregunta. Moitas grazas por preguntar isto!

Que debemos facer para evitar unha situación de bloqueo cando temos moitas sesións, un gran número de usuarios?

Postgres detecta automaticamente situacións de bloqueo. E eliminará automaticamente unha das sesións. A única forma de evitar o bloqueo morto é bloquear persoas na mesma orde. Entón, cando miras a túa aplicación, moitas veces o motivo dos bloqueos... Imaxinemos que quero bloquear dúas cousas diferentes. Unha aplicación bloquea a táboa 1, outra aplicación bloquea a 2, e despois a táboa 1. E a forma máis sinxela de evitar bloqueos é mirar a súa aplicación e asegurarse de que o bloqueo se produce na mesma orde en todas as aplicacións. E isto normalmente elimina o 80% dos problemas, porque todo tipo de persoas escriben estas aplicacións. E se os bloqueas na mesma orde, non atoparás unha situación de bloqueo.

Moitas grazas pola túa actuación! Falaches de vacuum full e, se entendo ben, vacuum full distorsiona a orde dos rexistros en almacenamento separado, polo que manteñen os rexistros actuais sen cambios. Por que o baleiro completo ten acceso exclusivo ao bloqueo e por que entra en conflito coas operacións de escritura?

Esa é unha boa pregunta. A razón é que o baleiro cheo leva a mesa. E esencialmente estamos creando unha nova versión da táboa. E a mesa será nova. Resulta que esta será unha versión completamente nova da táboa. E o problema é que cando facemos isto, non queremos que a xente o lea porque necesitamos que vexan a nova táboa. E así, isto conéctase á pregunta anterior. Se puidésemos ler ao mesmo tempo, non poderiamos movelo e dirixir á xente a unha mesa nova. Teríamos que esperar a que todos terminen de ler esta táboa, polo que é esencialmente unha situación de bloqueo exclusivo.
Só dicimos que bloqueamos desde o principio porque sabemos que ao final necesitaremos un bloqueo exclusivo para mover todos á nova copia. Polo tanto, podemos resolver isto. E facémolo deste xeito con indexación simultánea. Pero isto é moito máis difícil de facer. E isto está moi relacionado coa túa pregunta anterior sobre o bloqueo exclusivo.

¿É posible engadir o tempo de espera de bloqueo a Postgres? En Oracle, podo, por exemplo, escribir "seleccionar para actualizar" e esperar 50 segundos antes de actualizar. Foi bo para a aplicación. Pero en Postgres, ou teño que facelo de inmediato e non esperar nada, ou agardar ata algún tempo.

Si, podes escoller un tempo de espera nas túas pechaduras, nas túas pechaduras. Tamén pode emitir un comando de ningún xeito, que... se non pode obter o bloqueo inmediatamente. Polo tanto, un tempo de espera de bloqueo ou outra cousa que che permita facelo. Isto non se fai a nivel sintáctico. Isto faise como unha variable no servidor. Ás veces, isto non se pode usar.

Podes abrir a diapositiva 75?

Si

Desbloqueando o Xestor de bloqueo de Postgres. Bruce Momjian

E a miña pregunta é a seguinte. Por que ambos os procesos de actualización esperan 703?

E esta é unha gran pregunta. Non entendo, por certo, por que Postgres fai isto. Pero cando se creou 703, estaba esperando 702. E cando aparecen 704 e 705, parece que non saben o que están esperando porque aínda non hai nada. E Postgres faino deste xeito: cando non podes conseguir un bloqueo, escribe "Para que serve procesarte?", porque xa estás esperando por alguén. Entón, deixarémolo no aire, non o actualizará en absoluto. Pero que pasou aquí? Tan pronto como 702 completou o proceso e 703 recibiu o seu bloqueo, o sistema volveu. E dixo que agora temos dúas persoas que están esperando. E entón imos actualizalos xuntos. E imos indicar que ambos están esperando.

Non sei por que Postgres fai isto. Pero hai un problema chamado f... Paréceme que este non é un termo en ruso. Aquí é cando todo o mundo está esperando por un castelo, aínda que haxa 20 autoridades que están esperando polo castelo. E de súpeto espertan todos á vez. E todo o mundo comeza a tentar reaccionar. Pero o sistema fai que todo o mundo estea esperando polo 703. Porque todos están esperando, e enseguida poñerémolos todos en fila. E se aparece algunha outra solicitude nova que se xerou despois deste, por exemplo, 707, entón haberá de novo baleiro.

E paréceme que se fai así para poder dicir que neste momento o 702 está á espera do 703, e todos os que veñan despois non terán ningunha entrada neste campo. Pero en canto sae o primeiro camareiro, todos aqueles que estaban agardando nese momento antes da actualización reciben a mesma ficha. E por iso creo que se fai para que poidamos tramitar en orde para que estean debidamente ordenados.

Sempre considerei isto como un fenómeno bastante estraño. Porque aquí, por exemplo, non os enumeramos en absoluto. Pero paréceme que cada vez que damos un novo bloqueo, miramos a todos aqueles que están en proceso de espera. Despois aliñamos todos. E entón calquera novo que entre só entra na cola cando a seguinte persoa rematou de procesarse. Moi boa pregunta. Moitas grazas pola túa pregunta!

Paréceme que é moito máis lóxico cando 705 espera 704.

Pero o problema aquí é o seguinte. Tecnicamente, podes espertar un ou outro. E así espertaremos un ou outro. Pero que pasa no sistema? Podes ver como 703 na parte superior bloqueou o seu propio ID de transacción. Así funciona Postgres. E 703 está bloqueado polo seu propio ID de transacción, polo que se alguén quere esperar, entón esperará por 703. E, en esencia, 703 completa. E só despois da súa finalización esperta un dos procesos. E non sabemos cal será exactamente este proceso. Despois procesamos todo aos poucos. Pero non está claro cal é o proceso que se esperta primeiro, porque podería tratarse de calquera destes procesos. Esencialmente, tiñamos un programador que dicía que agora podemos activar calquera destes procesos. Escollemos un ao chou. Polo tanto, hai que ter en conta os dous porque podemos espertar a calquera deles.

E o problema é que temos CP-infinity. E polo tanto, é moi probable que poidamos espertar o posterior. E se, por exemplo, espertamos ao posterior, agardaremos ao que acaba de recibir o bloque, polo que non determinamos exactamente quen espertará primeiro. Simplemente creamos tal situación e o sistema espertaraos nunha orde aleatoria.

Ten artigos sobre peches de Egor Rogov. Mira, tamén son interesantes e útiles. O tema, por suposto, é terriblemente complexo. Moitas grazas, Bruce!

Fonte: www.habr.com

Engadir un comentario