sql >> Database >  >> RDS >> Database

Inleiding tot vergrendelingen

In sommige van mijn eerdere artikelen hier over prestatieafstemming heb ik meerdere soorten wachttijden besproken en hoe deze indicatief zijn voor verschillende resource-knelpunten. Ik begin een nieuwe serie over scenario's waarin een synchronisatiemechanisme, een vergrendeling genaamd, een prestatieknelpunt is, en met name niet-pagina-vergrendelingen. In deze eerste post ga ik uitleggen waarom vergrendelingen nodig zijn, wat ze eigenlijk zijn en hoe ze een knelpunt kunnen zijn.

Waarom zijn vergrendelingen nodig?

Het is een basisprincipe van de informatica dat wanneer een gegevensstructuur bestaat in een systeem met meerdere threads, de gegevensstructuur op de een of andere manier moet worden beschermd. Deze bescherming geeft de volgende voorwaarden:

  1. (Gegarandeerd) Een datastructuur kan niet worden gewijzigd door een thread terwijl een andere thread deze leest
  2. (Gegarandeerd) Een datastructuur kan niet worden gelezen door een thread terwijl een andere thread deze aan het wijzigen is
  3. (Gegarandeerd) Een datastructuur kan niet door twee of meer threads tegelijk worden gewijzigd
  4. (Optioneel) Sta twee of meer threads toe om de datastructuur tegelijkertijd te lezen
  5. (Optioneel) Laat threads op een geordende manier in de wachtrij staan ​​voor toegang tot de gegevensstructuur

Dit kan op verschillende manieren, waaronder:

  • Een mechanisme waarbij slechts één thread tegelijk toegang heeft tot de datastructuur. SQL Server implementeert dit mechanisme en noemt het een spinlock. Dit staat #1, #2 en #3 hierboven toe.
  • Een mechanisme waarmee meerdere threads tegelijkertijd de gegevensstructuur kunnen lezen (d.w.z. ze hebben gedeelde toegang), waardoor een enkele thread exclusieve toegang krijgt tot de gegevensstructuur (met uitsluiting van alle andere threads) en implementeert een eerlijke manier van in de rij staan ​​voor toegang. SQL Server implementeert dit mechanisme en noemt het een vergrendeling. Dit staat alle vijf bovenstaande voorwaarden toe.

Dus waarom gebruikt SQL Server zowel spinlocks als vergrendelingen? Sommige datastructuren worden zo vaak benaderd dat een grendel gewoon te duur is en daarom wordt in plaats daarvan een zeer lichtgewicht spinlock gebruikt. Twee voorbeelden van dergelijke datastructuren zijn de lijst met vrije buffers in de bufferpool en de lijst met vergrendelingen in de vergrendelingsmanager.

Wat is een vergrendeling?

Een vergrendeling is een synchronisatiemechanisme dat een enkele gegevensstructuur beschermt en er zijn drie brede soorten vergrendeling in SQL Server:

  1. Vergrendelt om een ​​gegevensbestandspagina te beschermen terwijl deze van schijf wordt gelezen. Deze verschijnen als PAGEIOLATCH_XX wacht, en ik heb ze in dit bericht besproken.
  2. Vergrendelt de toegang tot een gegevensbestandspagina die al in het geheugen staat (een pagina van 8 KB in de bufferpool is in feite slechts een gegevensstructuur). Deze verschijnen als PAGELATCH_XX wacht, en ik heb ze in dit bericht besproken.
  3. Vergrendelt ter bescherming van niet-paginagegevensstructuren. Deze verschijnen als LATCH_SH en LATCH_EX wacht.

In deze serie gaan we ons concentreren op de derde soort vergrendelingen.

Een vergrendeling is zelf een kleine gegevensstructuur en je kunt het zien als drie componenten:

  • Een resourcebeschrijving (van wat het beschermt)
  • Een statusveld dat aangeeft in welke modi de vergrendeling momenteel wordt vastgehouden, hoeveel threads de vergrendeling in die modus vasthouden en of er threads wachten (plus andere dingen waar we ons geen zorgen over hoeven te maken)
  • Een first-in-first-out wachtrij van threads die wachten op toegang tot de datastructuur, en op welke toegangsmodi ze wachten (de wachtrij genoemd)

Voor niet-pagina-latches zullen we ons beperken tot alleen de toegangsmodi SH (share) voor het lezen van de datastructuur en EX (exclusief) voor het wijzigen van de datastructuur. Er zijn andere, meer exotische modi, maar deze worden zelden gebruikt en zullen niet verschijnen als twistpunten, dus ik zal doen alsof ze niet bestaan ​​voor de rest van deze discussie.

Sommigen van jullie weten misschien dat er ook diepere complicaties zijn rond superlatches/sublatches en latch-partitionering voor schaalbaarheid, maar we hoeven niet tot die diepte te gaan voor de doeleinden van deze serie.

Een grendel verwerven

Wanneer een thread een vergrendeling wil verkrijgen, kijkt deze naar de status van de vergrendeling.

Als de thread de vergrendeling in de EX-modus wil verwerven, kan dit alleen als er geen threads zijn die de vergrendeling in een willekeurige modus vasthouden. Als dat het geval is, verwerft de thread de vergrendeling in de EX-modus en stelt de status in om dat aan te geven. Als er al een of meer threads zijn die de vergrendeling vasthouden, stelt de thread de status in om aan te geven dat er een wachtende thread is, komt zichzelf onderaan de wachtrij te staan ​​en wordt vervolgens onderbroken (op de kelnerlijst van de planner waarop deze zich bevindt ) wachtend op LATCH_EX.

Als de thread de grendel in SH-modus wil verwerven, kan dit alleen als geen enkele thread de grendel vasthoudt of als de enige threads die de grendel vasthouden in SH-modus zijn *en* er zijn geen threads die wachten om de grendel te verwerven. Als dat het geval is, verwerft de thread de grendel in de SH-modus, stelt de status in om dat aan te geven en verhoogt het aantal threads die de grendel vasthouden. Als de vergrendeling in de EX-modus wordt gehouden of als er een of meer wachtende threads zijn, stelt de thread de status in om aan te geven dat er een wachtende thread is, komt zichzelf onderaan in de wachtrij te staan ​​en wordt vervolgens onderbroken in afwachting van LATCH_SH.

De controle op wachtende threads wordt gedaan om eerlijkheid te garanderen voor een thread die wacht op de vergrendeling in de EX-modus. Het hoeft alleen te wachten op threads die de vergrendeling in de SH-modus vasthouden en die de vergrendeling hebben verkregen voordat deze begon te wachten. Zonder die controle kan een computerwetenschappelijke term genaamd 'honger' optreden, wanneer een constante stroom threads die de vergrendeling in SH-modus verwerven, verhindert dat de EX-modus-thread ooit de vergrendeling kan verkrijgen.

Een vergrendeling losmaken

Als de thread de vergrendeling in de EX-modus vasthoudt, wordt de status uitgeschakeld die aangeeft dat de vergrendeling in de EX-modus wordt vastgehouden en wordt vervolgens gecontroleerd of er nog wachtende threads zijn.

Als de draad de grendel in de SH-modus houdt, wordt het aantal SH-modus-threads verlaagd. Als de telling nu niet nul is, wordt de draad losgemaakt met de grendel. Als de telling *nu* nul is, wordt de status uitgeschakeld die aangeeft dat de vergrendeling in de SH-modus wordt gehouden en wordt vervolgens gecontroleerd of er wachtende threads zijn.

Als er geen draden wachten, wordt de draad losgemaakt met de vergrendeling.

Als de kop van de wachtrij wacht op de EX-modus, doet de vrijgavethread het volgende:

  • Stelt de status in om te laten zien dat de vergrendeling in de EX-modus wordt vastgehouden
  • Verwijdert de wachtende thread van de kop van de wachtrij en stelt deze in als de eigenaar van de vergrendeling
  • Signaleert de wachtende thread dat deze de eigenaar is en nu kan worden uitgevoerd (door conceptueel de wachtende thread te verplaatsen van de oberlijst op de planner naar de uitvoerbare wachtrij op de planner)
  • En het is klaar met de grendel

Als de kop van de wachtrij in de SH-modus wacht (wat alleen het geval kan zijn als de vrijgevende thread in de EX-modus was), doet de vrijgevende thread het volgende:

  • Stelt de status in om te laten zien dat de vergrendeling in de SH-modus wordt vastgehouden
  • Voor alle threads in de wachtrij die wachten op SH-modus
    • Verwijdert de wachtende thread uit de kop van de wachtrij
    • Verhoogt het aantal threads die de vergrendeling vasthouden
    • Signaleert de wachtende thread dat het een eigenaar is en nu kan worden uitgevoerd
  • En het is klaar met de grendel

Hoe kunnen vergrendelingen een twistpunt zijn?

In tegenstelling tot sloten, worden vergrendelingen over het algemeen alleen vastgehouden voor de duur van de lees- of wijzigingsbewerking, dus ze zijn vrij licht van gewicht, maar vanwege de SH vs. EX-incompatibiliteit kunnen ze net zo'n groot twistpunt zijn als sloten. Dit kan gebeuren wanneer veel threads allemaal een vergrendeling proberen te verkrijgen in de EX-modus (slechts één tegelijk kan dat) of wanneer veel threads proberen een vergrendeling te verkrijgen in de SH-modus en een andere thread de vergrendeling in de EX-modus vasthoudt.

Samenvatting

Hoe meer threads in het systeem strijden om een ​​'hot' latch, hoe hoger de stelling en hoe negatiever het effect op de workload-doorvoer zal zijn. U hebt waarschijnlijk wel eens gehoord van bekende problemen met vergrendelingsconflicten, bijvoorbeeld rond tempdb-toewijzingsbitmaps, maar er kan ook conflict optreden voor niet-pagina-vergrendelingen.

Nu heb ik je genoeg achtergrondinformatie gegeven om vergrendelingen te begrijpen en hoe ze werken. In de volgende artikelen zal ik enkele echte problemen met niet-pagina-vergrendeling onderzoeken en uitleggen hoe je ze kunt voorkomen of omzeilen.


  1. Inleiding tot langzaam veranderende afmetingen (SCD)

  2. Hoe u alle schendingen van beperkingen in een SQL Server-database kunt vinden

  3. Moet een MAMP ::1 retourneren als IP op localhost?

  4. Geavanceerde failover met behulp van post/pre-script hooks