CLR-integreringsarkitektur – CLR-värdbaserad miljö
gäller för:SQL Server
Azure SQL Managed Instance
SQL Server-integrering med .NET Framework common language runtime (CLR) gör det möjligt för databasprogram programmerare att använda språk som C#, Visual Basic .NET och Visual C++. Funktioner, lagrade procedurer, utlösare, datatyper och aggregeringar hör till de typer av affärslogik som programmerare kan skriva med dessa språk.
CLR har skräpinsamlat minne, förebyggande trådning, metadatatjänster (typreflektion), kodverifierbarhet och kodåtkomstsäkerhet. CLR använder metadata för att hitta och läsa in klasser, lägga ut instanser i minnet, lösa metodanrop, generera intern kod, framtvinga säkerhet och ange kontextgränser för körning.
CLR och SQL Server skiljer sig åt som körningsmiljöer på samma sätt som de hanterar minne, trådar och synkronisering. Den här artikeln beskriver hur dessa två körningstider är integrerade så att alla systemresurser hanteras enhetligt. Den här artikeln beskriver också hur CLR-kodåtkomstsäkerhet (CAS) och SQL Server-säkerhet integreras för att tillhandahålla en tillförlitlig och säker körningsmiljö för användarkod.
Grundläggande begrepp inom CLR-arkitektur
I .NET Framework skriver en programmerare på ett högnivåspråk som implementerar en klass som definierar dess struktur (till exempel fälten eller egenskaperna för klassen) och metoder. Vissa av dessa metoder kan vara statiska funktioner. Kompilering av programmet skapar en fil som kallas en sammansättning som innehåller den kompilerade koden på det gemensamma mellanliggande språket (CIL) och ett manifest som innehåller alla referenser till beroende sammansättningar.
Not
Sammansättningar är ett viktigt element i CLR-arkitekturen. De är enheter för paketering, distribution och versionshantering av programkod i .NET Framework. Med hjälp av sammansättningar kan du distribuera programkod i databasen och tillhandahålla ett enhetligt sätt att administrera, säkerhetskopiera och återställa fullständiga databasprogram.
Sammansättningsmanifestet innehåller metadata om sammansättningen och beskriver alla strukturer, fält, egenskaper, klasser, arvsrelationer, funktioner och metoder som definierats i programmet. Manifestet upprättar sammansättningsidentiteten, anger de filer som utgör sammansättningsimplementeringen, anger vilka typer och resurser som utgör sammansättningen, specificerar kompileringstidsberoendena på andra sammansättningar och anger den uppsättning behörigheter som krävs för att sammansättningen ska köras korrekt. Den här informationen används vid körning för att lösa referenser, framtvinga en versionsbindningsprincip och verifiera integriteten för inlästa sammansättningar.
.NET Framework stöder anpassade attribut för att kommentera klasser, egenskaper, funktioner och metoder med ytterligare information som programmet kan samla in i metadata. Alla .NET Framework-kompilatorer använder dessa anteckningar utan tolkning och lagrar dem som sammansättningsmetadata. Dessa anteckningar kan undersökas på samma sätt som andra metadata.
Hanterad kod körs i CLR i stället för direkt av operativsystemet. Hanterade kodprogram hämtar CLR-tjänster, till exempel automatisk skräpinsamling, körningstypkontroll och säkerhetsstöd. Dessa tjänster hjälper till att tillhandahålla enhetligt plattforms- och språkoberoende beteende för hanterade kodprogram.
Designmål för CLR-integrering
När användarkoden körs i den CLR-värdbaserade miljön i SQL Server (kallas CLR-integrering) gäller följande designmål:
Tillförlitlighet (säkerhet)
Användarkod bör inte tillåtas utföra åtgärder som äventyrar integriteten i databasmotorprocessen, till exempel att poppa en meddelanderuta som begär ett användarsvar eller avslutar processen. Användarkod ska inte kunna skriva över databasmotorns minnesbuffertar eller interna datastrukturer.
Skalbarhet
SQL Server och CLR har olika interna modeller för schemaläggning och minneshantering. SQL Server stöder en samarbetsinriktad, icke-förebyggande trådningsmodell där trådarna frivilligt ger körning med jämna mellanrum, eller när de väntar på lås eller I/O. CLR stöder en förebyggande trådningsmodell. Om användarkod som körs i SQL Server direkt kan anropa primitiver för operativsystemets trådning integreras den inte i SQL Server-schemaläggaren och kan försämra systemets skalbarhet. CLR skiljer inte mellan virtuellt och fysiskt minne, men SQL Server hanterar direkt fysiskt minne och krävs för att använda fysiskt minne inom en konfigurerbar gräns.
De olika modellerna för trådning, schemaläggning och minneshantering utgör en integrationsutmaning för ett relationsdatabashanteringssystem (RDBMS) som skalar för att stödja tusentals samtidiga användarsessioner. Arkitekturen bör se till att systemets skalbarhet inte komprometteras av användarkod som anropar programprogramprogramgränssnitt (API:er) för trådning, minne och synkroniseringspri primitiver direkt.
Säkerhet
Användarkod som körs i databasen måste följa SQL Server-autentiserings- och auktoriseringsregler vid åtkomst till databasobjekt som tabeller och kolumner. Dessutom bör databasadministratörer kunna styra åtkomsten till operativsystemresurser, till exempel filer och nätverksåtkomst, från användarkod som körs i databasen. Den här metoden blir viktig eftersom hanterade programmeringsspråk (till skillnad från icke-hanterade språk som Transact-SQL) ger API:er för åtkomst till sådana resurser. Systemet måste tillhandahålla ett säkert sätt för användarkod att komma åt datorresurser utanför databasmotorprocessen. Mer information finns i CLR-integreringssäkerhet.
Föreställning
Hanterad användarkod som körs i databasmotorn bör ha beräkningsprestanda som är jämförbara med samma kodkörning utanför servern. Databasåtkomst från hanterad användarkod är inte lika snabb som intern Transact-SQL. Mer information finns i Prestanda för CLR-integreringsarkitektur.
CLR-tjänster
CLR tillhandahåller flera tjänster för att uppnå designmålen för CLR-integrering med SQL Server.
Typsäkerhetsverifiering
Typsäker kod är kod som endast har åtkomst till minnesstrukturer på väldefinierade sätt. Med en giltig objektreferens kan exempelvis typsäker kod komma åt minnet vid fasta förskjutningar som motsvarar faktiska fältmedlemmar. Men om koden kommer åt minnet vid godtyckliga förskjutningar inom eller utanför det minnesintervall som tillhör objektet är det inte typsäkert. När sammansättningar läses in i CLR, innan CIL kompileras med jit-kompilering (just-in-time), utför körningen en verifieringsfas som undersöker kod för att fastställa dess typsäkerhet. Kod som klarar verifieringen kallas verifierbart typsäker kod.
Programdomäner
CLR stöder begreppet programdomäner som körningszoner i en värdprocess där hanterade kodsammansättningar kan läsas in och köras. Programdomängränsen ger isolering mellan sammansättningar. Sammansättningarna är isolerade när det gäller synlighet för statiska variabler och datamedlemmar och möjligheten att anropa kod dynamiskt. Programdomäner är också mekanismen för att läsa in och ta bort kod. Koden kan endast tas bort från minnet genom att programdomänen tas bort. Mer information finns i Application Domains and CLR Integration Security.
Kodåtkomstsäkerhet (CAS)
CLR-säkerhetssystemet ger ett sätt att styra vilka typer av åtgärder som hanterad kod kan utföra genom att tilldela behörigheter till kod. Behörigheter för kodåtkomst tilldelas baserat på kodidentitet (till exempel signaturen för sammansättningen eller kodens ursprung).
CLR tillhandahåller en datoromfattande princip som kan anges av datoradministratören. Den här principen definierar behörighetsbidragen för all hanterad kod som körs på datorn. Dessutom finns det en säkerhetsprincip på värdnivå som kan användas av värdar som SQL Server för att ange ytterligare begränsningar för hanterad kod.
Om ett hanterat API i .NET Framework exponerar åtgärder för resurser som skyddas av en kodåtkomstbehörighet, kräver API:et den behörigheten innan resursen används. Det här kravet gör att CLR-säkerhetssystemet utlöser en omfattande kontroll av varje kodenhet (sammansättning) i anropsstacken. Åtkomst till resursen beviljas endast om hela anropskedjan har behörighet.
Möjligheten att generera hanterad kod dynamiskt med hjälp av Reflection.Emit
-API:et stöds inte i den CLR-värdbaserade miljön i SQL Server. Sådan kod skulle inte ha CAS-behörighet att köra och skulle därför misslyckas vid körning. Mer information finns i CLR-integreringskodåtkomstsäkerhet.
Värdskyddsattribut (HPA)
CLR tillhandahåller en mekanism för att kommentera hanterade API:er som ingår i .NET Framework med vissa attribut som kan vara av intresse för en värd för CLR. Exempel på sådana attribut är:
SharedState
, som anger om API:et gör det möjligt att skapa eller hantera delat tillstånd (till exempel statiska klassfält).Synchronization
, som anger om API:et gör det möjligt att utföra synkronisering mellan trådar.ExternalProcessMgmt
, som anger om API:et visar ett sätt att styra värdprocessen.
Med dessa attribut kan värden ange en lista över HPA:er, till exempel attributet SharedState
, som inte ska tillåtas i den värdbaserade miljön. I det här fallet nekar CLR försök av användarkod att anropa API:er som kommenteras av HPA:erna i listan över förbjudna. Mer information finns i Värdskyddsattribut och CLR-integreringsprogrammering.
Så här fungerar SQL Server och CLR tillsammans
I det här avsnittet beskrivs hur SQL Server integrerar modeller för trådning, schemaläggning, synkronisering och minneshantering i SQL Server och CLR. I det här avsnittet går vi särskilt igenom integreringen med avseende på skalbarhet, tillförlitlighet och säkerhetsmål. SQL Server fungerar i princip som operativsystemet för CLR när det finns i SQL Server. CLR anropar lågnivårutiner som implementeras av SQL Server för trådning, schemaläggning, synkronisering och minneshantering. Dessa rutiner är samma primitiver som resten av SQL Server-motorn använder. Den här metoden ger flera skalbarhets-, tillförlitlighets- och säkerhetsfördelar.
Skalbarhet: Vanlig trådning, schemaläggning och synkronisering
CLR anropar SQL Server-API:er för att skapa trådar, både för att köra användarkod och för egen intern användning. För att synkronisera mellan flera trådar anropar CLR SQL Server-synkroniseringsobjekt. Med den här metoden kan SQL Server-schemaläggaren schemalägga andra uppgifter när en tråd väntar på ett synkroniseringsobjekt. När CLR till exempel initierar skräpinsamling väntar alla dess trådar på att skräpinsamlingen ska slutföras. Eftersom CLR-trådarna och synkroniseringsobjekten som de väntar på är kända för SQL Server-schemaläggaren, kan SQL Server schemalägga trådar som kör andra databasuppgifter som inte omfattar CLR. Detta gör det också möjligt för SQL Server att identifiera dödlägen som omfattar lås som tas av CLR-synkroniseringsobjekt och använda traditionella tekniker för borttagning av dödlägen.
Hanterad kod körs förebyggande i SQL Server. SQL Server-schemaläggaren har möjlighet att identifiera och stoppa trådar som inte har gett under en betydande tid. Möjligheten att koppla CLR-trådar till SQL Server-trådar innebär att SQL Server-schemaläggaren kan identifiera "skenande" trådar i CLR och hantera deras prioritet. Sådana skenande trådar pausas och sätts tillbaka i kön. Trådar som upprepade gånger identifieras som skenande trådar får inte köras under en viss tidsperiod så att andra kör arbetare kan köras.
Det finns vissa situationer där långvarig hanterad kod ger automatiskt, och vissa situationer där den inte gör det. I följande situationer ger långvarig hanterad kod automatiskt:
- Om koden anropar SQL OS (till exempel för att fråga efter data)
- Om tillräckligt med minne allokeras för att utlösa skräpinsamling
- Om koden går in i förebyggande läge genom att anropa OS-funktioner
Kod som inte utför någon av dessa åtgärder, till exempel snäva loopar som endast innehåller beräkning, ger inte automatiskt schemaläggaren, vilket kan leda till långa väntetider för andra arbetsbelastningar i systemet. I dessa situationer är det upp till utvecklaren att uttryckligen ge upp genom att anropa funktionen System.Thread.Sleep()
i .NET Framework, eller genom att uttryckligen ange förebyggande läge med System.Thread.BeginThreadAffinity()
, i alla kodavsnitt som förväntas vara tidskrävande. Följande kodexempel visar hur du manuellt ger med var och en av dessa metoder.
Exempel
Ge manuellt avkastning till SOS-schemaläggaren
for (int i = 0; i < Int32.MaxValue; i++)
{
// *Code that does compute-heavy operation, and does not call into
// any OS functions.*
// Manually yield to the scheduler regularly after every few cycles.
if (i % 1000 == 0)
{
Thread.Sleep(0);
}
}
Använd ThreadAffinity för att köra förebyggande
I det här exemplet körs CLR-koden i förebyggande läge inom BeginThreadAffinity
och EndThreadAffinity
.
Thread.BeginThreadAffinity();
for (int i = 0; i < Int32.MaxValue; i++)
{
// *Code that does compute-heavy operation, and does not call into
// any OS functions.*
}
Thread.EndThreadAffinity();
Skalbarhet: Vanlig minneshantering
CLR anropar SQL Server-primitiver för att allokera och frigöra dess minne. Eftersom det minne som används av CLR redovisas i systemets totala minnesanvändning kan SQL Server hålla sig inom sina konfigurerade minnesgränser och se till att CLR och SQL Server inte konkurrerar med varandra om minne. SQL Server kan också avvisa CLR-minnesbegäranden när systemminnet är begränsat och be CLR att minska minnesanvändningen när andra uppgifter behöver minne.
Tillförlitlighet: Programdomäner och oåterkalleliga undantag
När hanterad kod i .NET Framework-API:erna stöter på kritiska undantag, till exempel out-of-memory eller stack overflow, är det inte alltid möjligt att återställa från sådana fel och säkerställa konsekvent och korrekt semantik för implementeringen. Dessa API:er skapar ett undantag för tråd abort som svar på dessa fel.
När den hanteras i SQL Server hanteras sådana tråd aborter på följande sätt: CLR identifierar alla delade tillstånd i programdomänen där tråden avbryts. CLR identifierar detta genom att söka efter förekomsten av synkroniseringsobjekt. Om det finns delat tillstånd i programdomänen tas själva programdomänen bort. Avlastningen av programdomänen stoppar databastransaktioner som för närvarande körs i programdomänen. Eftersom förekomsten av delat tillstånd kan öka effekten av sådana kritiska undantag till andra användarsessioner än den som utlöser undantaget, har SQL Server och CLR vidtagit åtgärder för att minska sannolikheten för delat tillstånd. Mer information finns i .NET Framework.
Säkerhet: Behörighetsuppsättningar
MED SQL Server kan användarna ange tillförlitlighet och säkerhetskrav för kod som distribueras till databasen. När sammansättningar laddas upp till databasen kan författaren till sammansättningen ange en av tre behörighetsuppsättningar för den sammansättningen: SAFE
, EXTERNAL_ACCESS
och UNSAFE
.
Funktionalitet | SAFE |
EXTERNAL_ACCESS |
UNSAFE |
---|---|---|---|
Code Access Security |
Kör endast | Kör + åtkomst till externa resurser | Obegränsad |
Programming model restrictions |
Ja | Ja | Inga begränsningar |
Verifiability requirement |
Ja | Ja | Nej |
Ability to call native code |
Nej | Nej | Ja |
SAFE
är det mest tillförlitliga och säkra läget med tillhörande begränsningar när det gäller den tillåtna programmeringsmodellen.
SAFE
sammansättningar har tillräcklig behörighet för att köra, utföra beräkningar och ha åtkomst till den lokala databasen.
SAFE
sammansättningar måste vara verifierbart typsäkra och får inte anropa ohanterad kod.
UNSAFE
är för mycket betrodd kod som bara kan skapas av databasadministratörer. Den här betrodda koden har inga säkerhetsbegränsningar för kodåtkomst och kan anropa ohanterad (intern) kod.
EXTERNAL_ACCESS
tillhandahåller ett mellanliggande säkerhetsalternativ som tillåter kod att komma åt resurser utanför databasen men fortfarande har tillförlitlighetsgarantierna för SAFE
.
SQL Server använder CAS-principlagret på värdnivå för att konfigurera en värdprincip som ger en av de tre uppsättningarna behörigheter baserat på behörighetsuppsättningen som lagras i SQL Server-kataloger. Hanterad kod som körs i databasen hämtar alltid en av dessa kodåtkomstbehörighetsuppsättningar.
Begränsningar för programmeringsmodell
Programmeringsmodellen för hanterad kod i SQL Server omfattar att skriva funktioner, procedurer och typer som vanligtvis inte kräver användning av tillstånd i flera anrop eller delning av tillstånd över flera användarsessioner. Dessutom kan förekomsten av delat tillstånd orsaka kritiska undantag som påverkar programmets skalbarhet och tillförlitlighet.
Med tanke på dessa överväganden avråder vi från att använda statiska variabler och statiska datamedlemmar i klasser som används i SQL Server. För SAFE
och EXTERNAL_ACCESS
sammansättningar undersöker SQL Server metadata för sammansättningen vid CREATE ASSEMBLY
tidpunkt och misslyckas med att skapa sådana sammansättningar om den hittar användningen av statiska datamedlemmar och variabler.
SQL Server tillåter också anrop till .NET Framework-API:er som kommenteras med SharedState
, Synchronization
och ExternalProcessMgmt
värdskyddsattribut. Detta förhindrar SAFE
och EXTERNAL_ACCESS
sammansättningar från att anropa api:er som aktiverar delningstillstånd, utför synkronisering och påverkar integriteten i SQL Server-processen. Mer information finns i begränsningar för CLR-integreringsprogrammeringsmodellen.