sql >> Databasteknik >  >> RDS >> Database

Introduktion till spärrar

I några av mina tidigare artiklar här om prestandajustering har jag diskuterat flera typer av väntetider och hur de indikerar olika resursflaskhalsar. Jag startar en ny serie om scenarier där en synkroniseringsmekanism som kallas en spärr är en prestandaflaskhals, och specifikt icke-sidespärrar. I det här första inlägget ska jag förklara varför spärrar krävs, vad de faktiskt är och hur de kan vara en flaskhals.

Varför behövs spärrar?

Det är en grundläggande grundsats inom datavetenskap att närhelst en datastruktur finns i ett flertrådigt system måste datastrukturen skyddas på något sätt. Detta skydd ger följande förbehåll:

  1. (Garanterat) En datastruktur kan inte ändras av en tråd medan en annan tråd läser den
  2. (Garanterat) En datastruktur kan inte läsas av en tråd medan en annan tråd ändrar den
  3. (Garanterat) En datastruktur kan inte ändras av två eller flera trådar samtidigt
  4. (Valfritt) Tillåt två eller flera trådar att läsa datastrukturen samtidigt
  5. (Valfritt) Tillåt trådar att köa på ett ordnat sätt för åtkomst till datastrukturen

Detta kan göras på flera sätt, inklusive:

  • En mekanism som bara tillåter en enskild tråd åt gången att ha tillgång till datastrukturen. SQL Server implementerar denna mekanism och kallar den ett spinlock. Detta tillåter #1, #2 och #3 ovan.
  • En mekanism som tillåter flera trådar att läsa datastrukturen samtidigt (dvs. de har delad åtkomst), tillåter en enda tråd att få exklusiv åtkomst till datastrukturen (förutom alla andra trådar) och implementerar ett rättvist sätt att köa för tillträde. SQL Server implementerar denna mekanism och kallar den en spärr. Detta tillåter alla fem förbehållen ovan.

Så varför använder SQL Server både spinlocks och latches? Vissa datastrukturer nås så ofta att en spärr helt enkelt är för dyr och därför används ett mycket lätt spinlock istället. Två exempel på sådana datastrukturer är listan över lediga buffertar i buffertpoolen och listan över lås i låshanteraren.

Vad är en spärr?

En spärr är en synkroniseringsmekanism som skyddar en enda datastruktur och det finns tre breda typer av spärrar i SQL Server:

  1. Spärrar som skyddar en datafilsida medan den läses från disken. Dessa dyker upp när PAGEIOLATCH_XX väntar, och jag diskuterade dem i det här inlägget.
  2. Spärrar som skyddar åtkomst till en datafilsida som redan finns i minnet (en 8KB-sida i buffertpoolen är egentligen bara en datastruktur). Dessa dyker upp när PAGELATCH_XX väntar, och jag diskuterade dem i det här inlägget.
  3. Spärrar som skyddar icke-sidadatastrukturer. Dessa visas när LATCH_SH och LATCH_EX väntar.

I den här serien kommer vi att koncentrera oss på den tredje typen av spärrar.

En spärr är i sig en liten datastruktur och du kan tänka dig att den har tre komponenter:

  • En resursbeskrivning (av vad den skyddar)
  • Ett statusfält som anger vilka lägen spärren för närvarande hålls i, hur många trådar som håller spärren i det läget och om det finns några trådar som väntar (plus andra saker som vi inte behöver bry oss om)
  • En först-in-först-ut-kö av trådar som väntar på åtkomst till datastrukturen, och vilka åtkomstlägen de väntar på (kallad väntande kö)

För icke-sidspärrar begränsar vi oss till att endast överväga åtkomstlägena SH (share) för att läsa datastrukturen och EX (exklusivt) för att ändra datastrukturen. Det finns andra mer exotiska lägen, men de används sällan och kommer inte att visas som stridspunkter, så jag låtsas som att de inte existerar under resten av den här diskussionen.

En del av er kanske vet att det också finns djupare komplikationer kring superspärrar/sublatches och spärrpartitionering för skalbarhet, men vi behöver inte gå till det djupet för den här seriens syften.

Få en spärr

När en tråd vill skaffa en spärr, tittar den på spärrens status.

Om tråden vill förvärva spärren i EX-läge, kan den bara göra det om det inte finns några trådar som håller spärren i något läge. Om så är fallet, hämtar tråden spärren i EX-läge och ställer in status för att indikera det. Om det finns en eller flera trådar som redan håller spärren, ställer tråden in statusen för att indikera att det finns en väntande tråd, hamnar själv längst ner i väntekön och stängs sedan av (på servitörslistan för schemaläggaren den är på ) väntar på LATCH_EX.

Om tråden vill skaffa spärren i SH-läge, kan den bara göra det om ingen tråd håller spärren eller de enda trådarna som håller spärren är i SH-läge *och* det inte finns några trådar som väntar på att få tag på spärren. Om så är fallet, förvärvar tråden spärren i SH-läge, ställer in statusen för att indikera det, och ökar antalet trådar som håller spärren. Om spärren hålls i EX-läge eller om det finns en eller flera väntande trådar, ställer tråden in statusen för att indikera att det finns en väntande tråd, hamnar själv längst ned i väntekön och avbryts sedan i väntan på LATCH_SH.

Kontrollen för väntande trådar görs för att säkerställa rättvisa mot en tråd som väntar på spärren i EX-läge. Det kommer bara att behöva vänta på trådar som håller spärren i SH-läge som skaffade spärren innan den började vänta. Utan den kontrollen kan en datavetenskaplig term som kallas "svält" uppstå, när en konstant ström av trådar som skaffar spärren i SH-läge hindrar EX-lägesgängan från att någonsin kunna förvärva spärren.

Släpp en spärr

Om tråden håller spärren i EX-läge, avaktiverar den statusen som visar att spärren hålls i EX-läge och kontrollerar sedan om det finns några väntande trådar.

Om tråden håller spärren i SH-läge, minskar den antalet SH-lägesgängor. Om räkningen nu inte är noll, görs frigöringsgängan med spärren. Om räkningen *är* nu noll, avaktiveras statusen som visar att spärren hålls i SH-läge och kontrollerar sedan om det finns några väntande trådar.

Om det inte finns några trådar som väntar, släpps tråden med spärren.

Om chefen för väntkön väntar på EX-läge, gör släpptråden följande:

  • Ställer in status för att visa att spärren hålls i EX-läge
  • Tar bort den väntande tråden från könshuvud och ställer in den som ägare av spärren
  • Signerar den väntande tråden att den är ägaren och att den nu kan köras (genom att konceptuellt flytta den väntande tråden från servitörslistan på dess schemaläggare till den körbara kön på schemaläggaren)
  • Och det är gjort med spärren

Om chefen för väntkön väntar i SH-läge (vilket bara kan vara fallet om släpptråden var i EX-läge), gör släpptråden följande:

  • Ställer in status för att visa att spärren hålls i SH-läge
  • För alla trådar i väntekön som väntar på SH-läge
    • Tar bort den väntande tråden från könshuvud
    • Ökar antalet trådar som håller spärren
    • Signerar den väntande tråden att den är en ägare och nu kan köras
  • Och det är gjort med spärren

Hur kan spärrar vara en konfliktpunkt?

Till skillnad från lås, hålls spärrarna i allmänhet bara under läs- eller ändringsoperationen, så de är ganska lätta, men på grund av SH vs. EX-inkompatibiliteten kan de vara en lika stor konfliktpunkt som lås. Detta kan hända när många trådar alla försöker få en lås i EX-läge (endast en åt gången kan) eller när många trådar försöker få en lås i SH-läge och en annan tråd håller låset i EX-läge.

Sammanfattning

Ju fler trådar i systemet som kämpar för en "het" spärr, desto högre blir påståendet och desto mer negativ blir effekten på arbetsbelastningens genomströmning. Du har antagligen hört talas om välkända spärrkonflikter, till exempel kring bitmappar för tempdb-tilldelning, men konflikter kan även hända för icke-sidspärrar.

Nu har jag gett dig tillräckligt med bakgrund för att förstå spärrhakar och hur de fungerar. I de kommande artiklarna kommer jag att undersöka några verkliga problem utan sidspärr och förklara hur man kan förebygga eller kringgå dem.


  1. ComboBox.ValueMember och DisplayMember

  2. Fixa hål/luckor i siffror som genereras av Postgres-sekvensen

  3. Hur man skapar snapshot-replikering

  4. Ansluta Oracle till SQL Server över en säker anslutning