sql >> Database teknologi >  >> RDS >> Database

Introduktion til låse

I nogle af mine tidligere artikler her om justering af ydeevne, har jeg diskuteret flere ventetyper, og hvordan de er vejledende for forskellige ressourceflaskehalse. Jeg starter en ny serie om scenarier, hvor en synkroniseringsmekanisme kaldet en lås er en præstationsflaskehals, og specifikt ikke-sidelåse. I dette indledende indlæg vil jeg forklare, hvorfor låse er påkrævet, hvad de faktisk er, og hvordan de kan være en flaskehals.

Hvorfor er der brug for låse?

Det er et grundlæggende princip inden for datalogi, at når en datastruktur eksisterer i et multi-threaded system, skal datastrukturen beskyttes på en eller anden måde. Denne beskyttelse giver følgende forbehold:

  1. (Garanteret) En datastruktur kan ikke ændres af en tråd, mens en anden tråd læser den
  2. (Garanteret) En datastruktur kan ikke læses af en tråd, mens en anden tråd ændrer den
  3. (Garanteret) En datastruktur kan ikke ændres af to eller flere tråde på samme tid
  4. (Valgfrit) Tillad to eller flere tråde at læse datastrukturen på samme tid
  5. (Valgfrit) Tillad tråde at stå i kø på ordnet måde for at få adgang til datastrukturen

Dette kan gøres på flere måder, herunder:

  • En mekanisme, der kun tillader en enkelt tråd ad gangen at have adgang til datastrukturen. SQL Server implementerer denne mekanisme og kalder den en spinlock. Dette tillader #1, #2 og #3 ovenfor.
  • En mekanisme, der tillader flere tråde at læse datastrukturen på samme tid (dvs. de har delt adgang), tillader en enkelt tråd at få eksklusiv adgang til datastrukturen (med undtagelse af alle andre tråde) og implementerer en rimelig måde at stå i kø for adgang. SQL Server implementerer denne mekanisme og kalder den en lås. Dette tillader alle fem af ovenstående forbehold.

Så hvorfor bruger SQL Server både spinlocks og latches? Nogle datastrukturer tilgås så ofte, at en lås simpelthen er for dyr, og derfor bruges en meget let spinlock i stedet. To eksempler på sådanne datastrukturer er listen over ledige buffere i bufferpuljen og listen over låse i låsehåndteringen.

Hvad er en Latch?

En lås er en synkroniseringsmekanisme, der beskytter en enkelt datastruktur, og der er tre brede typer låse i SQL Server:

  1. Låser beskytter en datafilside, mens den læses fra disken. Disse dukker op, mens PAGEIOLATCH_XX venter, og jeg diskuterede dem i dette indlæg.
  2. Låse, der beskytter adgangen til en datafilside, der allerede er i hukommelsen (en 8KB-side i bufferpuljen er egentlig bare en datastruktur). Disse dukker op, mens PAGELATCH_XX venter, og jeg diskuterede dem i dette indlæg.
  3. Låse, der beskytter ikke-sidedatastrukturer. Disse vises, mens LATCH_SH og LATCH_EX venter.

I denne serie vil vi koncentrere os om den tredje slags låse.

En lås er i sig selv en lille datastruktur, og du kan tænke på, at den har tre komponenter:

  • En ressourcebeskrivelse (af hvad den beskytter)
  • Et statusfelt, der angiver, hvilke tilstande låsen i øjeblikket holdes i, hvor mange tråde der holder låsen i denne tilstand, og om der er nogen tråde, der venter (plus andre ting, vi ikke behøver at bekymre os om)
  • En først-ind-først-ud-kø af tråde, der venter på adgang til datastrukturen, og hvilke adgangsformer de venter på (kaldet ventekøen)

For ikke-sidelåse begrænser vi os til kun at overveje adgangstilstandene SH (share) til at læse datastrukturen og EX (eksklusiv) til at ændre datastrukturen. Der er andre mere eksotiske tilstande, men de bruges sjældent og vises ikke som stridspunkter, så jeg vil lade som om, de ikke eksisterer i resten af ​​denne diskussion.

Nogle af jer ved måske, at der også er dybere komplikationer omkring superlatches/sublatches og latch-partitionering for skalerbarhed, men vi behøver ikke at gå til den dybde med henblik på denne serie.

Anskaffelse af en lås

Når en tråd ønsker at anskaffe en lås, ser den på låsens status.

Hvis tråden ønsker at erhverve låsen i EX-tilstand, kan den kun gøre det, hvis der ikke er tråde, der holder låsen i nogen tilstand. Hvis det er tilfældet, henter tråden låsen i EX-tilstand og indstiller status for at indikere det. Hvis der er en eller flere tråde, der allerede holder låsen, indstiller tråden status for at indikere, at der er en ventende tråd, går ind i bunden af ​​ventekøen og suspenderes derefter (på tjenerlisten for den planlægger, den er på) ) venter på LATCH_EX.

Hvis gevindet ønsker at erhverve låsen i SH-tilstand, kan det kun gøre det, hvis ingen gevind holder låsen, eller de eneste gevind, der holder låsen, er i SH-tilstand *og* der er ingen gevind, der venter på at få låsen. Hvis det er tilfældet, henter tråden låsen i SH-tilstand, indstiller status til at indikere det, og øger antallet af tråde, der holder låsen. Hvis låsen holdes i EX-tilstand, eller der er en eller flere ventende tråde, sætter tråden status for at indikere, at der er en ventende tråd, går ind i bunden af ​​ventekøen og suspenderes derefter og venter på LATCH_SH.

Kontrollen for ventende gevind udføres for at sikre retfærdighed over for en gevind, der venter på låsen i EX-tilstand. Den skal kun vente på tråde, der holder låsen i SH-tilstand, som har erhvervet låsen, før den begyndte at vente. Uden dette tjek kan der forekomme et datalogisk udtryk kaldet 'sult', når en konstant strøm af tråde, der erhverver låsen i SH-tilstand, forhindrer EX-mode-tråden i nogensinde at kunne opnå låsen.

Slip en lås

Hvis tråden holder låsen i EX-tilstand, deaktiverer den status, der viser, at låsen holdes i EX-tilstand og kontrollerer derefter, om der er nogen ventende tråde.

Hvis gevindet holder låsen i SH-tilstand, formindsker det antallet af SH-mode-tråde. Hvis tællingen nu ikke er nul, udløses gevindet med låsen. Hvis antallet *er* nu nul, deaktiverer den status, der viser, at låsen holdes i SH-tilstand og kontrollerer derefter, om der er nogen ventende tråde.

Hvis der ikke er nogen gevind, der venter, udløses gevindet med låsen.

Hvis lederen af ​​ventekøen venter på EX-tilstand, gør frigivelsestråden følgende:

  • Indstiller status for at vise, at låsen holdes i EX-tilstand
  • Fjerner den ventende tråd fra hovedet i køen og indstiller den som ejer af låsen
  • Signererer den ventende tråd om, at den er ejeren og nu kan køres (ved konceptuelt at flytte den ventende tråd fra tjenerlisten på dens skemalægger til køen i skemalæggeren)
  • Og det er gjort med låsen

Hvis lederen af ​​ventekøen venter i SH-tilstand (hvilket kun kan være tilfældet, hvis udløsningstråden var i EX-tilstand), gør udløsningstråden følgende:

  • Indstiller status for at vise, at låsen holdes i SH-tilstand
  • For alle tråde i ventekøen, der venter på SH-tilstand
    • Fjerner den ventende tråd fra hovedet i køen
    • Øger antallet af tråde, der holder låsen
    • Signererer den ventende tråd, at den er en ejer og nu kan køres
  • Og det er gjort med låsen

Hvordan kan låse være et stridspunkt?

I modsætning til låse holdes låse generelt kun i hele læse- eller ændringsoperationen, så de er ret lette, men på grund af SH vs. EX-inkompatibiliteten kan de være lige så store et stridspunkt som låse. Dette kan ske, når mange tråde alle forsøger at opnå en lås i EX-tilstand (det kan kun én ad gangen), eller når mange tråde forsøger at opnå en lås i SH-tilstand, og en anden tråd holder låsen i EX-tilstand.

Oversigt

Jo flere tråde i systemet, der kæmper om en "hot" lås, jo højere er påstanden, og jo mere negativ vil effekten på arbejdsbyrdes gennemløb være. Du har sandsynligvis hørt om velkendte latch-konflikter, for eksempel omkring tempdb-tildelingsbitmaps, men strid kan også ske for ikke-sidelåse.

Nu har jeg givet dig tilstrækkelig baggrund til at forstå låse, og hvordan de virker. I de næste par artikler vil jeg undersøge nogle virkelige problemer med ikke-sidelåse-konflikter og forklare, hvordan man forebygger eller omgår dem.


  1. Konverter BufferedInputStream til billede

  2. [01000][unixODBC][Driver Manager]Kan ikke åbne lib '/usr/local/easysoft/oracle/InstantClient112/lib/libsqora.so':fil blev ikke fundet

  3. Saml en enkelt kolonne i forespørgslen med mange kolonner

  4. ListView Kontrol Træk-Drop Sorter begivenheder