Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Prepis govora Brucea Momjiana iz leta 2020 "Odklepanje upravitelja zaklepanja Postgres".

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

(Opomba: Vse poizvedbe SQL iz diapozitivov lahko dobite na tej povezavi: http://momjian.us/main/writings/pgsql/locking.sql)

Zdravo! Super je spet biti tukaj v Rusiji. Lani mi je žal, da nisem mogel priti, letos pa imava z Ivanom velike načrte. Upam, da bom tukaj veliko pogosteje. Rad prihajam v Rusijo. Obiskal bom Tjumen, Tver. Zelo sem vesel, da bom lahko obiskal ta mesta.

Moje ime je Bruce Momjian. Delam v podjetju EnterpriseDB in s Postgresom delam že več kot 23 let. Živim v Philadelphiji, ZDA. Potujem približno 90 dni na leto. Udeležujem se okoli 40 konferenc. moj Spletna stran, ki vsebuje diapozitive, ki vam jih bom zdaj pokazal. Zato si jih lahko po konferenci prenesete z moje osebne spletne strani. Vsebuje tudi okoli 30 predstavitev. Obstajajo tudi videoposnetki in veliko število vnosov v blog, več kot 500. To je dokaj informativen vir. In če vas to gradivo zanima, vas vabim, da ga uporabite.

Preden sem začel delati s Postgresom, sem bil učitelj, profesor. In zelo sem vesel, da vam bom zdaj lahko povedal, kar vam bom povedal. To je ena mojih najbolj zanimivih predstavitev. In ta predstavitev vsebuje 110 diapozitivov. Začeli bomo govoriti s preprostimi stvarmi, na koncu pa bo poročilo postajalo vse bolj zapleteno in postalo bo precej kompleksno.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

To je precej neprijeten pogovor. Blokiranje ni najbolj priljubljena tema. Želimo, da to nekam izgine. Kot bi šel k zobozdravniku.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

  1. Zaklepanje je težava za veliko ljudi, ki delajo v bazah podatkov in imajo več procesov, ki tečejo hkrati. Potrebujejo blokado. Se pravi, danes vam bom dal osnovno znanje o blokiranju.
  2. ID-ji transakcij. To je precej dolgočasen del predstavitve, vendar jih je treba razumeti.
  3. Nato bomo govorili o vrstah blokad. To je dokaj mehanski del.
  4. Spodaj bomo podali nekaj primerov blokiranja. In to bo precej težko razumeti.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Pogovorimo se o blokadi.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Naša terminologija je precej zapletena. Koliko vas ve, od kod prihaja ta odlomek? Dva človeka. To je iz igre, imenovane Colossal Cave Adventure. Mislim, da je bila to besedilna računalniška igra v 80. letih. Tam si moral iti v jamo, v labirint, in besedilo se je spreminjalo, vsebina pa je bila vsakič približno enaka. Tako se spominjam te igre.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In tukaj vidimo ime ključavnic, ki so nam prišle iz Oracla. Uporabljamo jih.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Tukaj vidimo izraze, ki me zmedejo. Na primer, SHARE UPDATE ECXLUSIVE. Naprej DELI RAW ECXLUSIVE. Iskreno povedano, ta imena niso zelo jasna. Poskusili jih bomo podrobneje razmisliti. Nekateri vsebujejo besedo »share«, kar pomeni ločiti. Nekateri vsebujejo besedo "ekskluzivno". Nekateri vsebujejo obe besedi. Rad bi začel s tem, kako te ključavnice delujejo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In beseda "dostop" je prav tako zelo pomembna. In besede "vrstica" so niz. To je distribucija dostopa, distribucija vrstic.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Drugo vprašanje, ki ga je treba razumeti v Postgresu in ga žal ne bom mogel obravnavati v svojem govoru, je MVCC. Na svoji spletni strani imam ločeno predstavitev na to temo. In če mislite, da je ta predstavitev težka, je MVCC verjetno moja najtežja. In če vas zanima, si ga lahko ogledate na spletni strani. Posnetek si lahko ogledate.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Druga stvar, ki jo moramo razumeti, so ID-ji transakcij. Mnoge transakcije ne morejo delovati brez edinstvenih identifikatorjev. In tukaj imamo razlago, kaj je transakcija. Postgres ima dva sistema številčenja transakcij. Vem, da to ni zelo lepa rešitev.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Upoštevajte tudi, da bo diapozitive precej težko razumeti, zato morate biti pozorni na tisto, kar je označeno z rdečo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

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

Pa poglejmo. Številka transakcije je označena z rdečo barvo. Tukaj je prikazana funkcija SELECT pg_back. Vrne mojo transakcijo in ID transakcije.

Še ena stvar, če vam je ta predstavitev všeč in jo želite zagnati v svoji bazi podatkov, lahko obiščete to povezavo v rožnati barvi in ​​prenesete SQL za to predstavitev. Lahko ga preprosto zaženete v svojem PSQL in celotna predstavitev bo takoj na vašem zaslonu. Ne bo vseboval rožic, a ga bomo vsaj videli.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

V tem primeru vidimo ID transakcije. To je številka, ki smo ji jo dodelili. V Postgresu obstaja še ena vrsta ID-ja transakcije, ki se imenuje ID virtualne transakcije

In to moramo razumeti. To je zelo pomembno, sicer ne bomo mogli razumeti zaklepanja v Postgresu.

Navidezni ID transakcije je ID transakcije, ki ne vsebuje trajnih vrednosti. Na primer, če zaženem ukaz SELECT, potem najverjetneje ne bom spremenil baze podatkov, ničesar ne bom zaklenil. Torej, ko zaženemo preprost SELECT, tej transakciji ne damo trajnega ID-ja. Tam ji damo samo virtualni ID.

In to izboljša zmogljivost Postgresa, izboljša zmožnosti čiščenja, zato je ID navidezne transakcije sestavljen iz dveh številk. Prva številka pred poševnico je ID zaledja. In na desni vidimo samo števec.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Zato, če zaženem zahtevo, piše, da je zaledni ID 2.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In če izvedem niz takšnih transakcij, potem vidimo, da se števec poveča vsakič, ko izvedem poizvedbo. Na primer, ko zaženem poizvedbo 2/10, 2/11, 2/12 itd.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Upoštevajte, da sta tukaj dva stolpca. Na levi strani vidimo virtualni ID transakcije – 2/12. In na desni imamo stalni ID transakcije. In to polje je prazno. In ta transakcija ne spremeni baze podatkov. Zato mu ne dam trajnega ID-ja transakcije.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Takoj ko zaženem ukaz za analizo ((ANALYZE)), mi ista poizvedba da stalni ID transakcije. Poglejte, kako se je to spremenilo za nas. Te osebne izkaznice prej nisem imel, zdaj pa jo imam.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Torej, tukaj je še ena zahteva, še ena transakcija. Virtualna transakcijska številka je 2/13. In če zahtevam trajni ID transakcije, ga bom dobil, ko zaženem poizvedbo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Torej, še enkrat. Imamo virtualni ID transakcije in obstojni ID transakcije. Samo razumejte to točko, da boste razumeli vedenje Postgresa.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Prehajamo na tretji del. Tukaj se bomo preprosto sprehodili skozi različne vrste ključavnic v Postgresu. Ni zelo zanimivo. Zadnji del bo veliko bolj zanimiv. Upoštevati pa moramo osnovne stvari, saj drugače ne bomo razumeli, kaj se bo zgodilo.

Šli bomo skozi ta razdelek, pogledali bomo vsako vrsto ključavnice. In pokazal vam bom primere, kako so nameščeni, kako delujejo, pokazal vam bom nekaj poizvedb, s katerimi lahko vidite, kako deluje zaklepanje v Postgresu.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Če želite ustvariti poizvedbo in videti, kaj se dogaja v Postgresu, moramo izdati poizvedbo v sistemskem pogledu. V tem primeru je pg_lock označen z rdečo. Pg_lock je sistemska tabela, ki nam pove, katere ključavnice so trenutno v uporabi v Postgresu.

Vendar vam zelo težko pokažem pg_lock samega, ker je precej zapleten. Zato sem ustvaril pogled, ki prikazuje pg_locks. In tudi zame opravlja nekaj dela, ki mi omogoča boljše razumevanje. To pomeni, da izključuje moja zaklepanja, mojo lastno sejo itd. Je samo standardni SQL in vam omogoča, da vam bolje pokaže, kaj se dogaja.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Druga težava je, da je ta pogled zelo širok, zato moram ustvariti drugega - lockview2.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian In prikaže mi več stolpcev iz tabele. In še ena, ki mi pokaže preostale stolpce. To je precej zapleteno, zato sem ga poskušal predstaviti čim bolj preprosto.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Tako smo ustvarili tabelo z imenom Lockdemo. In tam smo ustvarili eno vrstico. To je naša vzorčna tabela. Ustvarili bomo razdelke samo zato, da vam pokažemo primere ključavnic.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Torej, ena vrstica, en stolpec. Prva vrsta ključavnice se imenuje ACCESS SHARE. To je najmanj restriktivno blokiranje. To pomeni, da praktično ni v nasprotju z drugimi ključavnicami.

In če želimo eksplicitno definirati ključavnico, zaženemo ukaz "lock table". In očitno bo blokiral, tj. v načinu ACCESS SHARE zaženemo tabelo za zaklepanje. In če zaženem PSQL v ozadju, potem začnem drugo sejo s prve seje na ta način. Se pravi, kaj bom počel tukaj? Grem na drugo sejo in rečem "pokaži mi pogled zaklepanja za to zahtevo." In tukaj imam AccessShareLock v tej tabeli. Točno to sem zahteval. In pravi, da je bil blok dodeljen. Zelo preprosto.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Nadalje, če pogledamo drugi stolpec, potem tam ni ničesar. So prazne.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In če zaženem ukaz "SELECT", potem je to implicitni (eksplicitni) način za zahtevo AccessShareLock. Zato sprostim svojo tabelo in zaženem poizvedbo, poizvedba pa vrne več vrstic. In v eni od vrstic vidimo AccessShareLock. Tako SELECT pokliče AccessShareLock na tabeli. In ni v nasprotju s tako rekoč ničemer, ker je zaklepanje na nizki ravni.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Kaj pa, če zaženem SELECT in imam tri različne tabele? Prej sem izvajal samo eno tabelo, zdaj izvajam tri: pg_class, pg_namespace in pg_attribute.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In zdaj, ko pogledam poizvedbo, vidim 9 AccessShareLocks v treh tabelah. Zakaj? Tri tabele so označene z modro: pg_attribute, pg_class, pg_namespace. Vidite pa lahko tudi, da imajo vsi indeksi, ki so definirani v teh tabelah, tudi AccessShareLock.

In to je ključavnica, ki praktično ni v nasprotju z drugimi. In vse, kar naredi, je, da nam preprosto prepreči ponastavitev tabele, medtem ko jo izbiramo. Je smiselno. Se pravi, če izberemo mizo, ta v tistem trenutku izgine, potem je to narobe, torej AccessShare je nizkostopenjska ključavnica, ki nam pove "ne izpusti te mize, medtem ko delam". V bistvu je to vse, kar počne.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

ROW SHARE - Ta ključavnica je malo drugačna.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Vzemimo primer. SELECT ROW SHARE metoda zaklepanja vsake vrstice posebej. Tako jih nihče ne more izbrisati ali spremeniti, medtem ko jih gledamo.

Odklepanje upravitelja ključavnic Postgres. Bruce MomjianKaj torej naredi SHARE LOCK? Vidimo, da je ID transakcije 681 za SELECT. In to je zanimivo. Kaj se je zgodilo tukaj? Prvič vidimo številko v polju »Zakleni«. Vzamemo ID transakcije in piše, da ga blokira v ekskluzivnem načinu. Vse kar naredi je, da piše, da imam vrstico, ki je tehnično zaklenjena nekje v tabeli. A ne pove, kje točno. To si bomo podrobneje ogledali malo kasneje.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Tukaj pravimo, da ključavnico uporabljamo mi.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Torej ekskluzivna ključavnica izrecno pove, da je ekskluzivna. In tudi če izbrišete vrstico v tej tabeli, se bo to zgodilo, kot lahko vidite.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

SHARE EXCLUSIVE je daljša ključavnica.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

To je ukaz analizatorja (ANALIZIRAJ), ki bo uporabljen.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

SHARE LOCK – v načinu skupne rabe lahko izrecno zaklenete.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Ustvarite lahko tudi edinstven indeks. In tam lahko vidite SHARE LOCK, ki je del njih. In zaklene mizo in nanjo postavi KLJUČAVNICO SHARE LOCK.

Privzeto SHARE LOCK za tabelo pomeni, da lahko drugi ljudje berejo tabelo, vendar je nihče ne more spreminjati. In točno to se zgodi, ko ustvarite edinstven indeks.

Če ustvarim edinstven sočasni indeks, bom imel drugačno vrsto zaklepanja, ker, kot se spomnite, uporaba sočasnih indeksov zmanjša zahtevo po zaklepanju. In če uporabim običajno ključavnico, običajni indeks, potem bom tako preprečil pisanje v indeks tabele, medtem ko se ta ustvarja. Če uporabljam sočasni indeks, potem moram uporabiti drugo vrsto zaklepanja.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

SHARE ROW EXCLUSIVE – zopet se lahko nastavi eksplicitno (izrecno).

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Lahko pa ustvarimo pravilo, tj. vzamemo določen primer, v katerem bo uporabljeno.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

EKSKLUZIVNO zaklepanje pomeni, da nihče drug ne more spremeniti mize.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Tukaj vidimo različne vrste ključavnic.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

ACCESS EXCLUSIVE je na primer ukaz za blokiranje. Na primer, če to storite CLUSTER table, potem bo to pomenilo, da tam nihče ne bo mogel pisati. In ne zaklene samo tabele same, ampak tudi indekse.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

To je druga stran blokade ACCESS EXCLUSIVE, kjer v tabeli vidimo, kaj točno blokira. Zaklene posamezne vrstice tabele, kar je zelo zanimivo.

To so vse osnovne informacije, ki sem jih želel podati. Govorili smo o ključavnicah, o ID-jih transakcij, o ID-jih virtualnih transakcij, o trajnih ID-jih transakcij.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In zdaj bomo šli skozi nekaj primerov blokiranja. To je najbolj zanimiv del. Ogledali si bomo zelo zanimive primere. In moj cilj v tej predstavitvi je, da vam bolje razumete, kaj Postgres dejansko počne, ko poskuša blokirati določene stvari. Mislim, da je zelo dober pri blokiranju delov.

Poglejmo nekaj konkretnih primerov.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Začeli bomo s tabelami in eno vrstico v tabeli. Ko nekaj vstavim, imam na tabeli prikazan ExclusiveLock, ID transakcije in ExclusiveLock.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Kaj se zgodi, če vstavim še dve vrstici? In zdaj ima naša tabela tri vrstice. In vstavil sem eno vrstico in dobil to kot izhod. In če vstavim še dve vrstici, kaj je tu čudnega? Tu je nekaj čudnega, ker sem v to tabelo dodal tri vrstice, vendar imam še vedno dve vrstici v zaklenjeni tabeli. In to je v bistvu temeljno vedenje Postgresa.

Mnogi ljudje mislijo, da če v bazi podatkov zaklenete 100 vrstic, boste morali ustvariti 100 vnosov za zaklepanje. Če blokiram 1 vrstic hkrati, bom potreboval 000 takšnih poizvedb. In če rabim milijon ali milijardo za blokado. Toda če to storimo, ne bo dobro delovalo. Če ste uporabili sistem, ki ustvarja blokirne vnose za vsako posamezno vrstico, lahko vidite, da je to zapleteno. Ker morate takoj definirati tabelo zaklepanja, ki se lahko preliva, vendar Postgres tega ne počne.

In kar je resnično pomembno pri tem diapozitivu, je, da jasno prikazuje, da obstaja drug sistem, ki teče znotraj MVCC in zaklepa posamezne vrstice. Torej, ko zaklenete milijarde vrstic, Postgres ne ustvari milijarde ločenih ukazov za zaklepanje. In to zelo dobro vpliva na produktivnost.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Kaj pa posodobitev? Zdaj posodabljam vrstico in lahko vidite, da je izvedla dve različni operaciji hkrati. Hkrati je zaklenil tabelo, vendar je zaklenil tudi indeks. In moral je zakleniti indeks, ker so na tej tabeli edinstvene omejitve. In želimo zagotoviti, da tega nihče ne spremeni, zato ga blokiramo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Kaj se zgodi, če želim posodobiti dve vrstici? In vidimo, da se obnaša enako. Naredimo dvakrat več posodobitev, vendar popolnoma enako število zaklepnih vrstic.

Če se sprašujete, kako to počne Postgres, boste morali poslušati moje pogovore o MVCC, da boste izvedeli, kako Postgres interno označuje te vrstice, ki jih spreminja. In Postgres ima način, na katerega to počne, vendar tega ne počne na ravni zaklepanja tabele, ampak na nižji in učinkovitejši ravni.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Kaj pa, če želim nekaj izbrisati? Če na primer izbrišem eno vrstico in imam še vedno svoja dva blokirajoča vnosa, in tudi če jih želim vse izbrisati, sta še vedno tam.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In na primer, želim vstaviti 1 vrstic in nato izbrisati ali dodati 000 vrstic, nato pa te posamezne vrstice, ki jih dodam ali spremenim, niso zabeležene tukaj. Napisane so na nižji ravni znotraj same serije. In med govorom MVCC sem o tem podrobno govoril. Ko analizirate zaklepanja, pa je zelo pomembno, da se prepričate, da zaklepate na ravni tabele in da ne vidite, kako so tukaj zabeležene posamezne vrstice.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Kaj pa eksplicitna blokada?

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Če kliknem osveži, imam dve vrstici zaklenjeni. In če jih izberem vse in kliknem »posodobi povsod«, imam še vedno dva blokirajoča zapisa.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Za vsako posamezno vrstico ne ustvarjamo ločenih zapisov. Ker potem pade produktivnost, je lahko tega preveč. In lahko se znajdemo v neprijetni situaciji.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In ista stvar, če delimo, lahko to storimo vseh 30-krat.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Obnovimo našo tabelo, izbrišemo vse, nato znova vstavimo eno vrstico.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Drugo vedenje, ki ga vidite v Postgresu in je zelo dobro znano in želeno vedenje, je, da lahko izvedete posodobitev ali izbiro. In to lahko storite hkrati. In izberite ne blokira posodobitve in isto stvar v nasprotni smeri. Bralcu povemo, naj ne blokira pisca, in pisec ni blokiral bralca.

Pokazal vam bom primer tega. Zdaj se bom odločil. Nato bomo naredili INSERT. In potem lahko vidite - 694. Vidite lahko ID transakcije, ki je izvedla to vstavljanje. In tako to deluje.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In če zdaj pogledam svoj zaledni ID, je zdaj 695.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In vidim, da se v moji tabeli pojavlja 695.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In če tukaj posodobim takole, dobim drugačen primer. V tem primeru je 695 ekskluzivna ključavnica in posodobitev se obnaša enako, vendar med njima ni konflikta, kar je precej nenavadno.

Vidite lahko, da je na vrhu ShareLock, na dnu pa ExclusiveLock. In obe transakciji sta uspeli.

In poslušati morate moj govor na MVCC, da razumete, kako se to zgodi. Ampak to je ilustracija, da lahko to storite hkrati, tj. izvedete SELECT in UPDATE hkrati.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Ponastavimo in naredimo še eno operacijo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Če poskusite zagnati dve posodobitvi hkrati v isti vrstici, bo blokirana. In ne pozabite, rekel sem, da bralec ne blokira pisca in pisec ne blokira bralca, ampak en pisec blokira drugega pisca. To pomeni, da dve osebi ne moreta posodobiti iste vrstice hkrati. Morate počakati, da eden od njih konča.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In da bi to ponazoril, si bom ogledal tabelo Lockdemo. In pogledali bomo eno vrstico. Na transakcijo 698.

To smo posodobili na 2. 699 je prva posodobitev. In je bila uspešna ali pa je v čakajoči transakciji in čaka na našo potrditev ali preklic.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Toda poglejte nekaj drugega – 2/51 je naša prva transakcija, naša prva seja. 3/112 je druga zahteva, ki je prišla z vrha in je spremenila to vrednost na 3. In če opazite, se je zgornja zaklenila, kar je 699. Toda 3/112 ni odobrila zaklepanja. Stolpec Lock_mode pove, kaj čaka. Pričakuje 699. In če pogledate, kje je 699, je višje. In kaj je naredila prva seja? Ustvarila je ekskluzivno ključavnico za svoj ID transakcije. Tako to počne Postgres. Blokira svoj ID transakcije. In če želite počakati, da nekdo potrdi ali prekliče, potem morate počakati, dokler obstaja transakcija v teku. In zato lahko vidimo čudno črto.

Poglejmo še enkrat. Na levi strani vidimo naš ID obdelave. V drugem stolpcu vidimo ID virtualne transakcije, v tretjem pa lock_type. Kaj to pomeni? V bistvu piše, da blokira ID transakcije. Vendar opazite, da vse vrstice na dnu pravijo razmerje. In tako imate na mizi dve vrsti ključavnic. Obstaja relacijska ključavnica. In potem je tu še blokada transakcijskega ID-ja, kjer blokirate sami, kar se točno zgodi v prvi vrstici ali čisto na dnu, kjer je transakcijski ID, kjer čakamo, da 699 zaključi svojo operacijo.

Bom videl, kaj se bo zgodilo tukaj. In tukaj se zgodita dve stvari hkrati. Gledate zaklepanje ID-ja transakcije v prvi vrstici, ki se zaklene sama. In blokira se, da ljudje čakajo.

Če pogledate 6. vrstico, je enak vnos kot prvi. In zato je transakcija 699 blokirana. 700 je tudi samozaklepanje. In potem boste v spodnji vrstici videli, da čakamo, da 699 zaključi svoje delovanje.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In v lock_type, tuple vidite številke.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Lahko vidite, da je 0/10. In to je številka strani in tudi odmik te posebne vrstice.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In vidite, da postane 0/11, ko posodobimo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

A v resnici je 0/10, ker se na to operacijo čaka. Imamo priložnost videti, da je to serija, ki jo čakam na potrditev.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Ko smo to potrdili in pritisnili na commit, in ko je posodobitev končana, to spet dobimo. Transakcija 700 je edina ključavnica, ne čaka na nikogar drugega, ker je bila odobrena. Preprosto počaka, da se transakcija zaključi. Ko zmanjka 699, ne čakamo več na nič. In zdaj transakcija 700 pravi, da je vse v redu, da ima vse potrebne ključavnice na vseh dovoljenih tabelah.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In da bo vsa stvar še bolj zapletena, ustvarimo še en pogled, ki nam bo tokrat ponudil hierarhijo. Ne pričakujem, da boste razumeli to zahtevo. Toda to nam bo dalo jasnejši pogled na to, kaj se dogaja.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

To je rekurziven pogled, ki ima še en razdelek. In potem vse spet združi. Uporabimo to.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Kaj pa, če naredimo tri sočasne posodobitve in rečemo, da je vrstica zdaj tri. In spremenili bomo 3 v 4.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In tukaj vidimo 4. In ID transakcije 702.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In potem bom spremenil 4 v 5. In 5 v 6 in 6 v 7. In postavil bom več ljudi, ki bodo čakali, da se ta transakcija konča.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In vse postane jasno. Kaj je prva vrsta? To je 702. To je ID transakcije, ki je prvotno nastavil to vrednost. Kaj piše v mojem stolpcu Odobreno? Znamke imam f. To so moje posodobitve, ki jih (5, 6, 7) ni mogoče odobriti, ker čakamo, da se ID transakcije 702 konča. Tam imamo blokiranje ID transakcije. Posledica tega je 5 transakcijskih ID-jev.

In če pogledate 704, 705, tam še ni nič napisano, ker še ne vedo, kaj se dogaja. Preprosto pišejo, da nimajo pojma, kaj se dogaja. In bodo samo šli spat, ker čakajo, da nekdo konča in jih zbudi, ko bo priložnost za zamenjavo vrstic.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Takole izgleda. Jasno je, da vsi čakajo na 12. vrstico.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

To smo videli tukaj. Tukaj je 0/12.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Ko je torej prva transakcija odobrena, si lahko tukaj ogledate, kako deluje hierarhija. In zdaj je vse jasno. Vsi postanejo čisti. In pravzaprav še vedno čakajo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Evo, kaj se dogaja. 702 se zaveže. In zdaj 703 dobi to zaklepanje vrstice, nato pa 704 začne čakati, da se 703 izvrši. In 705 čaka tudi na to. In ko je vse to dokončano, se očistijo. In rad bi poudaril, da se vsi postavljajo v vrsto. In to je zelo podobno situaciji v prometnem zastoju, ko vsi čakajo na prvi avto. Prvi avto se ustavi in ​​vsi se postavijo v dolgo vrsto. Nato se premakne, nato se lahko naslednji avto odpelje naprej in dobi svoj blok itd.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In če se vam to ni zdelo dovolj zapleteno, se bomo zdaj z vami pogovarjali o zastojih. Ne vem, kdo od vas se je srečal z njimi. To je dokaj pogosta težava v sistemih baz podatkov. Toda zastoji so, ko ena seja čaka na drugo sejo, da nekaj naredi. In v tem trenutku druga seja čaka na prvo sejo, da nekaj naredi.

In če na primer Ivan reče: "Daj mi nekaj," jaz pa rečem: "Ne, dal ti bom samo, če mi daš kaj drugega." In pravi: "Ne, ne bom ti ga dal, če mi ga ne daš." In na koncu smo v slepi ulici. Prepričan sem, da Ivan tega ne bo storil, vendar razumete pomen, da imamo dva človeka, ki želita nekaj dobiti in tega nista pripravljena dati, dokler jima drugi ne da, kar hočeta. In rešitve ni.

In v bistvu mora vaša zbirka podatkov to zaznati. In potem morate eno od sej izbrisati ali zapreti, ker sicer bodo tam ostale za vedno. In to vidimo v bazah podatkov, vidimo to v operacijskih sistemih. In povsod, kjer imamo vzporedne procese, se to lahko zgodi.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In zdaj bomo namestili dva zastoja. Postavili bomo 50 in 80. V prvo vrstico bom posodobil s 50 na 50. Dobil bom številko transakcije 710.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In potem bom 80 spremenil v 81 in 50 v 51.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In takole bo videti. In tako ima 710 blokirano vrstico, 711 pa čaka na potrditev. To smo videli, ko smo posodobili. 710 je lastnik naše serije. In 711 čaka, da 710 zaključi transakcijo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In celo piše, v kateri vrstici se pojavijo zastoji. In tukaj začne postajati čudno.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Zdaj posodabljamo 80 na 80.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In tu se začnejo zastoji. 710 čaka na odgovor 711, 711 pa na 710. In to se ne bo dobro končalo. In iz tega ni izhoda. In drug od drugega bodo pričakovali odziv.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In začelo bo vse odlagati. In tega si ne želimo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In Postgres ima načine, kako opaziti, kdaj se to zgodi. In ko se to zgodi, dobite to napako. In iz tega je razvidno, da tak in tak proces čaka na SHARE LOCK od drugega procesa, tj. ki ga blokira proces 711. In ta proces je čakal, da se dodeli SHARE LOCK za tak in tak ID transakcije, in ga je blokiral tak in ta proces. Zato je tukaj zastoj.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Ali obstajajo tristranski zastoji? Ali je možno? ja

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Te številke vnesemo v tabelo. Spremenimo 40 na 40, naredimo blokado.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

60 spremenimo v 61, 80 v 81.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In potem zamenjamo 80 in potem bum!

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In 714 zdaj čaka na 715. 716. čaka na 715. In nič se ne da narediti glede tega.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Tu nista več dva človeka, tukaj so že trije. Jaz hočem nekaj od tebe, ta hoče nekaj od tretje osebe, tretja pa hoče nekaj od mene. In na koncu čakamo na tri strani, ker vsi čakamo, da druga oseba dokonča, kar mora narediti.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In Postgres ve, v kateri vrstici se to zgodi. In tako vam bo dalo naslednje sporočilo, ki kaže, da imate težavo, kjer se trije vhodi blokirajo. In tukaj ni nobenih omejitev. To se lahko zgodi, ko 20 vnosov blokira drug drugega.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Naslednja težava je možnost serializacije.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Če je posebna serializable lock.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In vrnemo se na 719. Njegov rezultat je povsem normalen.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In lahko kliknete, da naredite transakcijo iz serije.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In ugotovite, da imate zdaj drugačno vrsto SA ključavnice - to pomeni možnost serializacije.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In tako imamo novo vrsto ključavnice, imenovano SARieadLock, ki je serijska ključavnica in omogoča vnos serijskih številk.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Prav tako lahko vstavite edinstvene indekse.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

V tej tabeli imamo edinstvene indekse.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Torej, če tukaj vstavim številko 2, imam 2. Toda čisto na vrh sem vstavil še eno 2. In lahko vidite, da ima 721 ekskluzivno ključavnico. Zdaj pa 722 čaka, da 721 dokonča svojo operacijo, ker ne more vstaviti 2, dokler ne ve, kaj se bo zgodilo s 721.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In če naredimo podtransakcijo.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Tukaj imamo 723.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In če točko shranimo in jo nato posodobimo, potem dobimo nov ID transakcije. To je še en vzorec obnašanja, ki se ga morate zavedati. Če to vrnemo, ID transakcije izgine. 724 odhaja. Toda zdaj jih imamo 725.

Torej, kaj poskušam narediti tukaj? Poskušam vam pokazati primere nenavadnih ključavnic, ki jih lahko najdete: ne glede na to, ali gre za ključavnice, ki jih je mogoče serializirati, ali SAVEPOINT, so to različne vrste ključavnic, ki se bodo pojavile v tabeli ključavnic.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

To je ustvarjanje eksplicitnih (eksplicitnih) ključavnic, ki imajo pg_advisory_lock.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In vidite, da je vrsta blokiranja navedena kot svetovalna. In tukaj piše "svetovalno" z rdečo barvo. Hkrati lahko tako blokirate s pg_advisory_unlock.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In na koncu bi vam rad pokazal še eno neverjetno stvar. Ustvaril bom drug pogled. Vendar bom tabelo pg_locks združil s tabelo pg_stat_activity. In zakaj želim to narediti? Ker mi bo to omogočilo, da si ogledam vse trenutne seje in natančno vidim, kakšne vrste zaklepanja čakajo. In to je zelo zanimivo, ko sestavimo tabelo zaklepanja in tabelo poizvedb.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In tukaj ustvarimo pg_stat_view.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In posodobimo vrstico za eno. In tukaj vidimo 724. In nato našo vrstico posodobimo na tri. In kaj zdaj vidite tukaj? To so zahteve, kar pomeni, da vidite celoten seznam zahtev, ki so navedene v levem stolpcu. In potem na desni strani lahko vidite blokade in kaj ustvarjajo. In lahko vam bo bolj jasno, tako da se vam ni treba vsakič znova vračati na vsako sejo in videti, ali se ji morate pridružiti ali ne. To naredijo za nas.

Druga funkcija, ki je zelo uporabna, je pg_blocking_pids. Verjetno še niste slišali zanjo. Kaj ona počne? Omogoča nam, da za to sejo 11740 povemo, katere specifične ID-je procesa čaka. In lahko vidite, da 11740 čaka na 724. In 724 je na samem vrhu. In 11306 je ID vašega procesa. V bistvu gre ta funkcija skozi vašo ključavnico. In vem, da je malo zapleteno, vendar ti uspe razumeti. V bistvu gre ta funkcija skozi to tabelo zaklepanja in poskuša najti, kje je ta ID procesa glede na zaklepanja, na katera čaka. Prav tako poskuša ugotoviti, kateri ID procesa ima proces, ki čaka na zaklepanje. Torej lahko zaženete to funkcijo pg_blocking_pids.

In to je lahko zelo koristno. To smo dodali šele v različici 9.6, tako da je ta funkcija stara le 5 let, vendar je zelo, zelo uporabna. In enako velja za drugo zahtevo. Prikazuje točno to, kar moramo videti.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

To je tisto, o čemer sem hotel govoriti s tabo. In kot sem pričakoval, smo porabili ves čas, ker je bilo toliko diapozitivov. In diapozitivi so na voljo za prenos. Rad bi se vam zahvalil, da ste tukaj. Prepričan sem, da boste uživali v nadaljevanju konference, najlepša hvala!

Vprašanja:

Na primer, če poskušam posodobiti vrstice, druga seja pa poskuša izbrisati celotno tabelo. Kolikor razumem, bi moralo obstajati nekaj podobnega zaklepanju namena. Ali obstaja kaj takega v Postgresu?

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

Pa se vrnimo na sam začetek. Morda se spomnite, da ko naredite karkoli, na primer ko naredite SELECT, izdamo AccessShareLock. In to preprečuje, da bi miza padla. Torej, če želite na primer posodobiti vrstico v tabeli ali izbrisati vrstico, potem nekdo ne more izbrisati celotne tabele hkrati, ker držite ta AccessShareLock nad celotno tabelo in nad vrstico. In ko končate, ga lahko izbrišejo. Toda medtem ko tam neposredno nekaj spremenite, oni tega ne bodo mogli narediti.

Naredimo to še enkrat. Pojdimo na primer brisanja. In vidite, kako je ekskluzivna ključavnica v vrstici nad celotno tabelo.

To bo videti kot ekskluzivna ključavnica, kajne?

Da, izgleda tako. Razumem o čem govoriš. Pravite, da če naredim SELECT, potem imam ShareExclusive in nato naredim Row Exclusive, ali to postane problem? A presenetljivo to ne predstavlja težave. To je videti kot povečanje stopnje zaklepanja, vendar v bistvu imam zaklepanje, ki preprečuje brisanje. In zdaj, ko naredim to ključavnico močnejšo, še vedno preprečuje brisanje. Torej ni tako, da grem gor. To pomeni, da je preprečil, da bi se to zgodilo tudi, ko je bil na nižji ravni, tako da, ko zvišam njegovo raven, še vedno preprečuje brisanje tabele.

Razumem o čem govoriš. Tukaj ni primera eskalacije zaklepanja, kjer se poskušate odpovedati enemu zaklepanju, da bi uvedli močnejšega. Tukaj le poveča to preprečevanje na vseh področjih, tako da ne povzroči nobenega konflikta. Ampak to je dobro vprašanje. Najlepša hvala za to vprašanje!

Kaj moramo storiti, da se izognemo zastoju, ko imamo veliko sej, veliko število uporabnikov?

Postgres samodejno opazi situacije zastoja. In samodejno bo izbrisal eno od sej. Edini način, da se izognete mrtvemu blokiranju, je blokiranje ljudi v enakem vrstnem redu. Torej, ko pogledate svojo aplikacijo, je pogosto razlog za zastoje ... Predstavljajmo si, da želim blokirati dve različni stvari. Ena aplikacija zaklene tabelo 1, druga aplikacija zaklene tabelo 2 in nato tabelo 1. Najlažji način, da se izognete zastojem, je, da pogledate svojo aplikacijo in se prepričate, da se zaklepanje izvaja v enakem vrstnem redu v vseh aplikacijah. In to običajno odpravi 80% težav, ker te aplikacije pišejo vsi ljudje. In če jih blokirate v enakem vrstnem redu, ne boste naleteli na zastoj.

Najlepša hvala za vaš nastop! Govorili ste o polnem vakuumu in, če prav razumem, poln vakuum popači vrstni red zapisov v ločenem shranjevanju, zato trenutni zapisi ostanejo nespremenjeni. Zakaj vakuumsko polno zahteva izključni dostop do zaklepanja in zakaj je v nasprotju z operacijami pisanja?

To je dobro vprašanje. Razlog je v tem, da je miza polna vakuuma. In v bistvu ustvarjamo novo različico tabele. In miza bo nova. Izkazalo se je, da bo to popolnoma nova različica tabele. In težava je, da ko to naredimo, ne želimo, da ljudje to preberejo, ker potrebujemo, da vidijo novo tabelo. In tako je to povezano s prejšnjim vprašanjem. Če bi lahko brali hkrati, je ne bi mogli premakniti in ljudi usmeriti k novi mizi. Morali bi počakati, da vsi končajo z branjem te tabele, zato gre v bistvu za situacijo, ki izključuje ključavnico.
Pravimo le, da zaklenemo od začetka, ker vemo, da bomo čisto na koncu potrebovali ekskluzivno zaklepanje, da bomo vse premaknili na novo kopijo. Torej lahko to potencialno rešimo. In to naredimo na ta način s hkratnim indeksiranjem. Toda to je veliko težje narediti. In to je zelo povezano z vašim prejšnjim vprašanjem o ekskluzivni ključavnici.

Ali je mogoče v Postgres dodati časovno omejitev zaklepanja? V Oracle lahko na primer napišem "select to update" in počakam 50 sekund pred posodobitvijo. Za aplikacijo je bilo dobro. Toda v Postgresu moram to storiti takoj in sploh ne čakati ali pa počakati nekaj časa.

Da, lahko izberete časovno omejitev za svoje ključavnice, za svoje ključavnice. Izdate lahko tudi ukaz za prepoved, ki bo ... če ne morete takoj pridobiti ključavnice. Zato bodisi časovna omejitev zaklepanja ali kaj drugega, kar vam bo to omogočilo. To se ne naredi na sintaktični ravni. To se naredi kot spremenljivka na strežniku. Včasih tega ni mogoče uporabiti.

Ali lahko odprete diapozitiv 75?

Da.

Odklepanje upravitelja ključavnic Postgres. Bruce Momjian

In moje vprašanje je naslednje. Zakaj oba postopka posodobitve pričakujeta 703?

In to je odlično vprašanje. Mimogrede, ne razumem, zakaj Postgres to počne. Toda ko je bil ustvarjen 703, je pričakoval 702. In ko se pojavita 704 in 705, se zdi, kot da ne vesta, kaj pričakujeta, ker tam še ni ničesar. In Postgres to naredi tako: ko ne moreš dobiti ključavnice, napiše "What's point in processing you?", ker nekoga že čakaš. Zato ga bomo pustili obviseti v zraku in ga sploh ne bo posodobil. Toda kaj se je zgodilo tukaj? Takoj ko je 702 zaključil postopek in je 703 prejel zaklepanje, se je sistem vrnil nazaj. In rekla je, da imamo zdaj dve osebi, ki čakata. In potem jih skupaj posodobimo. In naj povemo, da oba pričakujeta.

Ne vem, zakaj Postgres to počne. Toda obstaja problem, ki se imenuje f…. Zdi se mi, da to ni izraz v ruščini. To je takrat, ko vsi čakajo na en grad, tudi če je 20 oblasti, ki čakajo na grad. In nenadoma se vsi zbudijo hkrati. In vsi začnejo poskušati reagirati. Ampak sistem naredi tako, da vsi čakajo na 703. Ker vsi čakajo in jih bomo takoj vse postavili v vrsto. In če se pojavi še kakšna nova zahteva, ki je bila ustvarjena po tej, na primer 707, potem bo spet praznina.

In zdi se mi, da je to narejeno zato, da lahko rečemo, da na tej stopnji 702 čaka na 703 in vsi tisti, ki pridejo za tem, ne bodo imeli nobenega vpisa v to polje. Toda takoj, ko prvi natakar odide, vsi tisti, ki so čakali v tistem trenutku pred posodobitvijo, prejmejo isti žeton. In zato mislim, da je to narejeno zato, da lahko obdelamo po vrstnem redu, tako da so pravilno urejeni.

Na to sem vedno gledal kot na precej čuden pojav. Ker jih tukaj na primer sploh ne navajamo. Se mi pa zdi, da vsakič, ko damo novo ključavnico, pogledamo vse tiste, ki so na čakanju. Nato jih vse poravnamo. In potem vsak nov, ki pride, pride v čakalno vrsto šele, ko je obdelava naslednje osebe končana. Zelo dobro vprašanje. Najlepša hvala za vaše vprašanje!

Zdi se mi, da je veliko bolj logično, ko 705 pričakuje 704.

Toda tukaj je problem naslednji. Tehnično gledano lahko zbudiš enega ali drugega. In tako bomo enega ali drugega prebudili. Toda kaj se zgodi v sistemu? Vidite lahko, kako je 703 na samem vrhu blokiral svoj ID transakcije. Tako deluje Postgres. In 703 je blokiran z lastnim ID-jem transakcije, tako da če nekdo želi počakati, bo počakal na 703. In v bistvu se 703 zaključi. In šele po njegovem zaključku se prebudi eden od procesov. In ne vemo, kakšen točno bo ta proces. Nato vse postopoma obdelamo. Vendar ni jasno, kateri proces se prebudi prvi, ker bi lahko bil kateri koli od teh procesov. V bistvu smo imeli razporejevalnik, ki je rekel, da lahko zdaj prebudimo katerega koli od teh procesov. Samo naključno izberemo enega. Oba sta torej treba upoštevati, ker lahko enega od njiju prebudimo.

In problem je, da imamo CP-neskončnost. In zato je precej verjetno, da lahko kasneje prebudimo. In če na primer prebudimo kasnejšega, bomo počakali na tistega, ki je pravkar prejel blok, tako da ne določimo, kdo točno bo prebujen prvi. Enostavno ustvarimo takšno situacijo in sistem jih bo prebudil po naključnem vrstnem redu.

Obstaja članki o ključavnicah Egorja Rogova. Poglejte, tudi zanimivi in ​​uporabni so. Tematika je seveda strašno kompleksna. Najlepša hvala, Bruce!

Vir: www.habr.com

Dodaj komentar