Freigeben über


Gehostete CLR-Umgebung

Die Microsoft .NET Framework Common Language Runtime (CLR) ist eine Umgebung, die viele moderne Programmiersprachen ausführt, einschließlich Microsoft Visual C#, Microsoft Visual Basic und Microsoft Visual C++. Die CLR bietet der Garbage Collection unterworfenen Arbeitsspeicher, präemptives Threading, Metadatendienste (geben Sie „reflection“ ein), Codeüberprüfbarkeit und Codezugriffssicherheit. Die CLR verwendet Metadaten zum Suchen und Laden von Klassen, Anordnen von Instanzen im Speicher, Auflösen von Methodenaufrufen, Generieren von systemeigenem Code, Erzwingen von Sicherheit und zum Festlegen von Begrenzungen im Laufzeitkontext.

CLR und SQL Server unterscheiden sich als Laufzeitumgebungen in der Art und Weise, wie sie Arbeitsspeicher, Threads und Synchronisierung verarbeiten. Dieses Thema beschreibt, wie die beiden Laufzeiten integriert werden, sodass alle Systemressourcen einheitlich verwaltet werden. In diesem Thema wird auch erläutert, wie CLR-Codezugriffssicherheit (CAS) und SQL Server Sicherheit integriert werden, um eine zuverlässige und sichere Ausführungsumgebung für Benutzercode bereitzustellen.

Grundlegende Konzepte der CLR-Architektur

In .NET Framework schreibt ein Programmierer in einer Hochsprache, die eine Klasse implementiert, die die Struktur (z. B. die Felder oder Eigenschaften der Klasse) und Methoden definiert. Einige dieser Methoden können statische Funktionen sein. Die Kompilierung des Programms erzeugt eine Datei namens Assembly, die den kompilierten Code in der Microsoft Intermediate Language (MSIL) enthält, und ein Manifest, das alle Verweise auf abhängige Assemblys enthält.

Hinweis

Assemblys sind ein wichtiges Element in der Architektur der CLR. Sie sind die Einheiten für Verpackung, Bereitstellung und Versionsverwaltung des Anwendungscodes in .NET Framework. Durch die Verwendung von Assemblys können Sie Anwendungscode in der Datenbank verfügbar machen und eine einheitliche Methode zur Verwaltung, Sicherung und Wiederherstellung kompletter Datenbankanwendungen bereitstellen.

Das Assemblymanifest enthält Metadaten über die Assembly, die sämtliche Strukturen, Felder, Eigenschaften, Klassen, Vererbungsbeziehungen, Funktionen und Methoden beschreiben, die im Programm definiert sind. Das Manifest legt die Identität der Assembly fest, gibt die Dateien an, aus denen die Assemblyimplementierung besteht, gibt die Typen und Ressourcen an, aus denen die Assembly besteht, legt die Abhängigkeiten von anderen Assemblys für die Kompilierungszeit einzeln fest und gibt den Berechtigungssatz an, der für die ordnungsgemäße Ausführung der Assembly erforderlich ist. Diese Informationen werden zur Laufzeit verwendet, um Verweise aufzulösen, Versionsbindungsrichtlinien zu erzwingen und die Integrität geladener Assemblys zu validieren.

.NET Framework unterstützt benutzerdefinierte Attribute zum Hinzufügen von Anmerkungen zu Klassen, Eigenschaften, Funktionen und Methoden in Form von zusätzlichen Informationen, die von der Anwendung in Metadaten erfasst werden können. Alle .NET Framework-Compiler verwenden diese Anmerkungen ohne Auslegung und speichern sie als Assemblymetadaten. Diese Anmerkungen können auf die gleiche Weise wie beliebige andere Metadaten untersucht werden.

Verwalteter Code ist MSIL-Code, der in der CLR anstatt direkt vom Betriebssystem ausgeführt wird. Anwendungen mit verwaltetem Code verfügen über CLR-Dienste, z. B. automatische Garbage Collection, Typüberprüfung zur Laufzeit, Sicherheitsunterstützung usw. Diese Dienste ermöglichen ein einheitliches plattform- und sprachunabhängiges Verhalten von Anwendungen mit verwaltetem Code.

Entwurfsziele der CLR-Integration

Wenn Benutzercode in der CLR-gehosteten Umgebung in SQL Server (clR-Integration genannt) ausgeführt wird, gelten die folgenden Entwurfsziele:

Zuverlässigkeit (Sicherheit)

Vom Benutzercode sollten keine Vorgänge ausgeführt werden dürfen, die die Integrität des Prozesses der Datenbank-Engine gefährden, z. B. die Anzeige eines Meldungsfelds, in dem eine Benutzerantwort verlangt wird, oder in dem der Prozess beendet wird. Benutzercode sollte nicht in der Lage sein, Arbeitsspeicherpuffer der Datenbank-Engine oder interne Datenstrukturen zu überschreiben.

Skalierbarkeit

SQL Server und die CLR verfügen über unterschiedliche interne Modelle für die Planung und Speicherverwaltung. SQL Server unterstützt ein kooperatives, nicht präemptives Threadingmodell, bei dem die Threads in regelmäßigen Abständen oder wenn sie auf Sperren oder E/A warten. Die CLR unterstützt ein präemptives Threadingmodell. Wenn Benutzercode, der in SQL Server ausgeführt wird, die Threadinggrundsätze des Betriebssystems direkt aufrufen kann, kann er sich nicht gut in den SQL Server Aufgabenplaner integrieren und die Skalierbarkeit des Systems beeinträchtigen. Die CLR unterscheidet nicht zwischen virtuellem und physischem Arbeitsspeicher, sondern SQL Server verwaltet den physischen Arbeitsspeicher direkt und muss physischen Arbeitsspeicher innerhalb eines konfigurierbaren Grenzwerts verwenden.

Die unterschiedlichen Modelle für Threading, Planung und Arbeitsspeicherverwaltung stellen eine Integrationsherausforderung für ein relationales Datenbankverwaltungssystem (RDBMS) dar, das durch Skalierung Tausende von gleichzeitigen Benutzersitzungen unterstützt. Durch die Architektur sollte sichergestellt werden, dass die Skalierbarkeit des Systems nicht durch Benutzercode beeinträchtigt wird, der APIs (Application Programming Interfaces, Schnittstellen zur Anwendungsprogrammierung) für Threading-, Arbeitsspeicher- und Synchronisierungsgrundelemente direkt aufruft.

Sicherheit

Benutzercode, der in der Datenbank ausgeführt wird, muss SQL Server Authentifizierungs- und Autorisierungsregeln beim Zugriff auf Datenbankobjekte wie Tabellen und Spalten befolgen. Darüber hinaus sollten Datenbankadministratoren in der Lage sein, den Zugriff auf Ressourcen des Betriebssystems, wie Dateien und Netzwerkzugriff, vom Benutzercode aus zu steuern, der in der Datenbank ausgeführt wird. Dies ist wichtig, da verwaltete Programmiersprachen (im Gegensatz zu nicht verwalteten Sprachen wie Transact-SQL) APIs zum Zugreifen auf diese Ressourcen bereitstellen. Das System muss eine sichere Möglichkeit für Benutzercode bieten, um auf Computerressourcen außerhalb des Datenbank-Engine-Prozesses zuzugreifen. Weitere Informationen finden Sie unter CLR Integration Security.

Leistung

Verwalteter Benutzercode, der in der Datenbank-Engine ausgeführt wird, sollte eine Berechnungsleistung aufweisen, die mit demselben Code vergleichbar ist, der außerhalb des Servers ausgeführt wird. Der Datenbankzugriff über verwalteten Benutzercode ist nicht so schnell wie native Transact-SQL. Weitere Informationen finden Sie unter Leistung der CLR-Integration.

CLR Services

Die CLR bietet eine Reihe von Diensten, um die Entwurfsziele der CLR-Integration mit SQL Server zu erreichen.

Typsicherheitsüberprüfung

Als typsicherer Code wird Code bezeichnet, der nur auf genau definierte Weise auf Arbeitsspeicherstrukturen zugreift. Bei typsicherem Code ist z. B. bei einem gültigen Objektverweis der Speicherzugriff an festen Offsets möglich, die tatsächlichen Feldmembern entsprechen. Wenn der Code jedoch auf den Speicher an beliebigen Offsets innerhalb oder außerhalb des Gültigkeitsbereichs des Speichers zugreift, der zu dem Objekt gehört, ist er nicht typsicher. Wenn Assemblys in die CLR geladen werden, bevor die MSIL mithilfe der JIT-Kompilierung (Just-In-Time) kompiliert wurde, führt die Laufzeit eine Überprüfungsphase aus, die den Code hinsichtlich seiner Typsicherheit untersucht. Code, der diese Überprüfung erfolgreich besteht, wird nachweisbar typsicherer Code genannt.

Anwendungsdomänen

Die CLR unterstützt die Definition von Anwendungsdomänen als Ausführungszonen in einem Hostprozess, bei dem verwaltete Codeassemblys geladen und ausgeführt werden können. Die Anwendungsdomänengrenze bietet Isolierung zwischen Assemblys. Die Assemblys werden hinsichtlich der Sichtbarkeit von statischen Variablen und Datenelementen und der Möglichkeit, Code dynamisch aufzurufen, isoliert. Anwendungsdomänen sind auch der Mechanismus zum Laden und Entladen von Code. Code kann aus dem Arbeitsspeicher durch das Entladen der Anwendungsdomäne entfernt werden. Weitere Informationen finden Sie unter Anwendungsdomänen und CLR-Integrationssicherheit.

Codezugriffssicherheit (Code Access Security, CAS)

Das CLR-Sicherheitssystem bietet eine Methode zum Steuern der Vorgangstypen, die von verwaltetem Code ausgeführt werden können, indem dem Code Berechtigungen zugewiesen werden. Codezugriffsberechtigungen werden auf der Grundlage der Identität des Codes (z. B. die Signatur der Assembly oder die Quelle des Codes) zugewiesen.

Die CLR sorgt für eine Richtlinie, die auf dem gesamten Computer gilt und vom Computeradministrator festgelegt werden kann. Diese Richtlinie definiert die Berechtigungen für den gesamten verwalteten Code, der auf dem Computer ausgeführt wird. Darüber hinaus gibt es eine Sicherheitsrichtlinie auf Hostebene, die von Hosts wie SQL Server verwendet werden kann, um zusätzliche Einschränkungen für verwalteten Code anzugeben.

Wenn eine verwaltete API in .NET Framework Operationen für Ressourcen verfügbar macht, die durch eine Codezugriffsberechtigung geschützt sind, fordert die API vor dem Zugriff auf die Ressource diese Berechtigung an. Diese Anforderung löst im CLR-Sicherheitssystem eine umfangreiche Überprüfung jeder Codeeinheit (Assembly) in der Aufrufliste aus. Nur wenn die ganze Aufrufkette über eine Berechtigung verfügt, wird der Zugriff auf die Ressource gewährt.

Beachten Sie, dass die Möglichkeit, verwalteten Code mithilfe der Reflection.Emit-API dynamisch zu generieren, in der CLR-gehosteten Umgebung in SQL Server nicht unterstützt wird. Solcher Code hätte die CAS-Berechtigungen zum Ausführen nicht und würde deshalb zur Laufzeit fehlschlagen. Weitere Informationen finden Sie unter Zugriffssicherheit für CLR-Integrationscode.

Hostschutzattribute (HPAs)

Die CLR stellt einen Mechanismus zur Verfügung, um verwaltete APIs, die Teil von .NET Framework sind, mit Anmerkungen in Form von bestimmten Attributen zu versehen, die für einen Host der CLR interessant sein können. Beispiele für solche Attribute:

  • SharedState - gibt an, ob die API die Fähigkeit zur Verfügung stellt, einen Freigabezustand (z. B. statische Klassenfelder) zu erstellen oder zu verwalten.

  • Synchronization - gibt an, ob die API die Fähigkeit zur Verfügung stellt, die Synchronisierung zwischen Threads auszuführen.

  • ExternalProcessMgmt - gibt an, ob die API eine Möglichkeit zur Kontrolle des Hostprozesses zur Verfügung stellt.

Anhand dieser Attribute kann der Host eine Liste mit Hostschutzattributen festlegen, wie das SharedState-Attribut, die in der gehosteten Umgebung nicht zugelassen werden. In diesem Fall weist die CLR Versuche des Benutzercodes zurück, APIs aufzurufen, die mit nicht zugelassenen Hostschutzattributen aus der Liste versehen sind. Weitere Informationen finden Sie unter Hostschutzattribute und CLR-Integrationsprogrammierung.

Zusammenarbeit von SQL Server und der CLR

In diesem Abschnitt wird erläutert, wie SQL Server die Threading-, Planungs-, Synchronisierungs- und Speicherverwaltungsmodelle von SQL Server und der CLR integriert. Genauer wird in diesem Abschnitt auf die Integration im Hinblick auf Skalierbarkeit, Zuverlässigkeit und Sicherheit eingegangen. SQL Server fungiert im Wesentlichen als Betriebssystem für die CLR, wenn sie in SQL Server gehostet wird. Die CLR ruft Routinen auf niedriger Ebene auf, die von SQL Server für Threading, Planung, Synchronisierung und Speicherverwaltung implementiert werden. Dies sind dieselben Grundtypen, die der Rest der SQL Server-Engine verwendet. Dieser Ansatz bietet mehrere Vorteile für Skalierbarkeit, Zuverlässigkeit und Sicherheit.

Skalierbarkeit: Allgemeines Threading, Planung und Synchronisierung

CLR ruft SQL Server APIs zum Erstellen von Threads auf, sowohl für die Ausführung von Benutzercode als auch für die eigene interne Verwendung. Um zwischen mehreren Threads zu synchronisieren, ruft die CLR SQL Server Synchronisierungsobjekte auf. Dadurch kann der SQL Server-Planer andere Aufgaben planen, wenn ein Thread auf ein Synchronisierungsobjekt wartet. Wenn die CLR beispielsweise die Garbage Collection initiiert, warten alle zugehörigen Threads auf die Fertigstellung der Garbage Collection. Da die CLR-Threads und die Synchronisierungsobjekte, auf die sie warten, dem SQL Server-Planer bekannt sind, können SQL Server Threads planen, die andere Datenbanktasks ausführen, die die CLR nicht betreffen. Dadurch können SQL Server auch Deadlocks erkennen, die Sperren umfassen, die von CLR-Synchronisierungsobjekten vorgenommen wurden, und herkömmliche Techniken zum Entfernen von Deadlocks verwenden.

Verwalteter Code wird in SQL Server präventiv ausgeführt. Der SQL Server-Planer kann Threads erkennen und beenden, die für einen erheblichen Zeitraum nicht zurückgegeben wurden. Die Möglichkeit, CLR-Threads mit SQL Server Threads zu verbinden, impliziert, dass der SQL Server Scheduler "auslaufende" Threads in der CLR identifizieren und ihre Priorität verwalten kann. Solche Ausreißerthreads werden angehalten und in die Warteschlange zurückgestellt. Threads, die mehrfach als Ausreißerthreads identifiziert werden, dürfen für einen gewissen Zeitraum nicht ausgeführt werden, damit andere Arbeitsthreads ausgeführt werden können.

Hinweis

Verwalteter Code mit langer Laufzeit, der auf Daten zugreift oder genug Arbeitsspeicher zuordnet, um Garbage Collection auszulösen, wird automatisch aktiv. Verwalteter Code mit langer Laufzeit, der nicht auf Daten zugreift oder nicht genug Arbeitsspeicher zuweist, um Garbage Collection auszulösen, sollte explizit durch Aufrufen der Funktion System.Thread.Sleep() von .NET Framework aktiv werden.

Skalierbarkeit: Allgemeine Arbeitsspeicherverwaltung

Die CLR ruft SQL Server Grundtypen zum Zuweisen und Aufheben der Zuweisung des Arbeitsspeichers auf. Da der von der CLR verwendete Arbeitsspeicher in der Gesamtspeicherauslastung des Systems berücksichtigt wird, können SQL Server innerhalb der konfigurierten Speichergrenzwerte bleiben und sicherstellen, dass clR und SQL Server nicht miteinander um Arbeitsspeicher konkurrieren. SQL Server können auch CLR-Speicheranforderungen ablehnen, wenn der Systemspeicher eingeschränkt ist, und CLR bitten, die Arbeitsspeicherauslastung zu reduzieren, wenn andere Aufgaben Arbeitsspeicher benötigen.

Zuverlässigkeit: Anwendungsdomänen und nicht behebbare Ausnahmen

Wenn in verwaltetem Code in .NET Framework-APIs schwerwiegende Ausnahmen auftreten, wie nicht genügend Arbeitsspeicher oder Stapelüberlauf, ist es nicht immer möglich, diese Fehler zu beheben und konsistente und korrekte Semantik für die Implementierung zu gewährleisten. Diese APIs lösen als Reaktion auf diese Fehler eine Threadabbruchausnahme aus.

Wenn sie in SQL Server gehostet werden, werden solche Threadabbrüche wie folgt behandelt: Die CLR erkennt jeden freigegebenen Zustand in der Anwendungsdomäne, in der der Threadabbruch auftritt. Die CLR überprüft dazu das Vorhandensein von Synchronisierungsobjekten. Wenn es einen Freigabezustand in der Anwendungsdomäne gibt, dann wird die Anwendungsdomäne selbst entladen. Die Entladung aus der Anwendungsdomäne beendet Datenbanktransaktionen, die gerade in dieser Anwendungsdomäne ausgeführt werden. Da das Vorhandensein eines freigegebenen Zustands die Auswirkungen solcher kritischen Ausnahmen auf andere Benutzersitzungen als die, die die Ausnahme auslösen, erweitern kann, haben SQL Server und die CLR Schritte unternommen, um die Wahrscheinlichkeit eines freigegebenen Zustands zu verringern. Weitere Informationen hierzu finden Sie in der .NET Framework- Dokumentation.

Sicherheit: Berechtigungssätze

SQL Server können Benutzer die Zuverlässigkeits- und Sicherheitsanforderungen für den in der Datenbank bereitgestellten Code angeben. Beim Hochladen von Assemblys in die Datenbank kann der Verfasser der Assembly für diese einen von drei Berechtigungssätzen angeben: SAFE, EXTERNAL_ACCESS und UNSAFE.

Berechtigungssatz SAFE EXTERNAL_ACCESS UNSAFE
Codezugriffssicherheit Nur ausführen Ausführen + Zugriff auf externe Ressourcen Nicht eingeschränkt
Beschränkungen des Programmiermodells Yes Yes Keine Einschränkungen
Überprüfbarkeit erforderlich Yes Ja Nein
Aufrufbarkeit von systemeigenem Code No Nein Ja

SAFE ist der zuverlässigste und sicherste Modus, der mit Einschränkungen hinsichtlich des zulässigen Programmiermodells einhergeht. Assemblys der Stufe SAFE verfügen über ausreichende Berechtigungen für die Ausführung, die Durchführung von Berechnungen und den Zugriff auf die lokale Datenbank. Assemblys der Stufe SAFE müssen nachweislich typsicher sein und dürfen keinen nicht verwalteten Code aufrufen.

UNSAFE ist für hoch vertrauenswürdigen Code vorgesehen, der nur von Datenbankadministratoren erstellt werden kann. Dieser vertrauenswürdige Code verfügt über keine Codezugriffs-Sicherheitsbeschränkungen und kann nicht verwalteten (systemeigenen) Code aufrufen.

EXTERNAL_ACCESS stellt eine mittlere Sicherheitsebene dar, bei der Code auf Ressourcen außerhalb der Datenbank zugreifen kann, die aber dennoch so zuverlässig wie SAFE ist.

SQL Server verwendet die CAS-Richtlinienebene auf Hostebene, um eine Hostrichtlinie einzurichten, die eine der drei Berechtigungssätze basierend auf dem in SQL Server Katalogen gespeicherten Berechtigungssatz gewährt. Verwaltetem Code, der in der Datenbank ausgeführt wird, wird immer einer dieser Codezugriffsberechtigungssätze abgerufen.

Einschränkungen des Programmiermodells

Das Programmiermodell für verwalteten Code in SQL Server umfasst das Schreiben von Funktionen, Prozeduren und Typen, die in der Regel nicht die Verwendung des Zustands für mehrere Aufrufe oder die Freigabe des Zustands über mehrere Benutzersitzungen erfordern. Darüber hinaus kann ein Freigabezustand, wie bereits erläutert, zu schwerwiegenden Ausnahmen führen, die die Skalierbarkeit und Zuverlässigkeit der Anwendung gefährden können.

Aufgrund dieser Überlegungen wird davon abgeraten, statische Variablen und statische Datenmember von Klassen zu verwenden, die in SQL Server verwendet werden. Für SAFE- und EXTERNAL_ACCESS assemblys untersucht SQL Server die Metadaten der Assembly zur CREATE ASSEMBLY-Zeit und schlägt bei der Erstellung solcher Assemblys fehl, wenn die Verwendung von statischen Datenmembern und Variablen gefunden wird.

SQL Server lässt auch Aufrufe von .NET Framework APIs nicht zu, die mit den SharedStateAttributen , Synchronization und ExternalProcessMgmt Hostschutz versehen sind. Dadurch wird verhindert, dass SAFE- und EXTERNAL_ACCESS-Assemblys APIs aufrufen, die den Freigabestatus aktivieren, die Synchronisierung durchführen und die Integrität des SQL Server-Prozesses beeinträchtigen. Weitere Informationen finden Sie unter Einschränkungen des Programmiermodells für die CLR-Integration.

Weitere Informationen

Sicherheit der CLR-Integration
Leistungsfähigkeit der CLR-Integration