Share via


CLR ホスト環境

Microsoft .NET Framework 共通言語ランタイム (CLR) は、Microsoft Visual C#、Microsoft Visual Basic、Microsoft Visual C++など、多くの最新のプログラミング言語を実行する環境です。 CLR の特色には、ガベージ コレクションが行われるメモリ、プリエンプティブなスレッド処理、メタデータ サービス (型リフレクション)、コードの検証可能性、コード アクセス セキュリティなどがあります。 CLR では、クラスの検索と読み込み、メモリ内でのインスタンスのレイアウト、メソッド呼び出しの解決、ネイティブ コードの生成、セキュリティの設定、およびランタイム コンテキスト境界の設定にメタデータが使用されます。

CLR と SQL Serverは、メモリ、スレッド、および同期の処理方法でランタイム環境と異なります。 このトピックでは、すべてのシステム リソースが統一的に管理されるように、これら 2 つのランタイムを統合する方法について説明します。 このトピックでは、CLR コード アクセス セキュリティ (CAS) とSQL Server セキュリティを統合して、ユーザー コードの信頼性とセキュリティで保護された実行環境を提供する方法についても説明します。

CLR アーキテクチャの基本概念

.NET Framework では、プログラマは高級言語を使ってクラスを実装し、そのクラスの構造 (クラスのフィールドやプロパティなど) とメソッドを定義します。 このようなメソッドの一部は、静的関数にすることができます。 プログラムのコンパイルにより、Microsoft 中間言語 (MSIL) のコンパイル済みコードを含むアセンブリと呼ばれるファイルと、依存アセンブリへのすべての参照を含むマニフェストが生成されます。

Note

アセンブリは CLR アーキテクチャの不可欠な要素です。 アセンブリは、.NET Framework のアプリケーション コードのパッケージ化、配置、およびバージョン管理の単位になります。 アセンブリを使用して、データベース内部にアプリケーション コードを配置し、完全なデータベース アプリケーションの管理、バックアップ、および復元を行うための統一された方法を提供できます。

アセンブリ マニフェストには、アセンブリに関するメタデータが含まれており、プログラムで定義されているすべての構造体、フィールド、プロパティ、クラス、継承関係、関数、およびメソッドの情報が記述されています。 マニフェストでは、アセンブリ ID の確立、アセンブリの実装を構成するファイルの指定、アセンブリを構成する型やリソースの指定、他のアセンブリに対するコンパイル時の依存関係の列挙、およびアセンブリを正しく実行するために必要な権限セットの指定を行います。 この情報を実行時に使用して、参照の解決、バージョン バインド ポリシーの設定、および読み込まれたアセンブリの整合性の検証が行われます。

.NET Framework では、アプリケーションがメタデータでキャプチャできる追加情報により、クラス、プロパティ、関数、およびメソッドに注釈を付けるためのカスタム属性がサポートされます。 すべての .NET Framework コンパイラでは、このような注釈を解釈せずに使用し、アセンブリ メタデータとして格納します。 このような注釈は、他のメタデータと同じ方法で調べることができます。

マネージド コードは、オペレーティング システムが直接実行するのではなく、CLR で MSIL として実行されます。 マネージド コード アプリケーションは、自動ガベージ コレクション、ランタイム型チェック、セキュリティ サポートなどの CLR サービスを使用します。 これらのサービスは、プラットフォームや言語に依存しない統一的な動作を、マネージド コード アプリケーションに提供するのに役立ちます。

CLR 統合の設計目標

ユーザー コードがSQL Server (CLR 統合と呼ばれます) の CLR ホスト環境内で実行される場合、次の設計目標が適用されます。

信頼性 (安全性)

ユーザーからの応答を要求するメッセージ ボックスの表示やプロセスの終了など、データベース エンジン プロセスの整合性に影響を与える操作は、ユーザー コードから実行できないようにする必要があります。 ユーザー コードからデータベース エンジンのメモリ バッファーや内部データ構造体への上書きを許可しないでください。

スケーラビリティ

SQL Serverと CLR には、スケジュールとメモリ管理のための異なる内部モデルがあります。 SQL Serverでは、スレッドが定期的に、またはロックまたは I/O を待機しているときに、スレッドが自発的に実行を生成する協調的でプリエンプティブでないスレッド モデルがサポートされています。 CLR では、プリエンプティブなスレッド モデルがサポートされます。 SQL Server内で実行されているユーザー コードがオペレーティング システムのスレッド プリミティブを直接呼び出すことができる場合、SQL Server タスク スケジューラにうまく統合されず、システムのスケーラビリティが低下する可能性があります。 CLR は仮想メモリと物理メモリを区別しませんが、SQL Serverは物理メモリを直接管理し、構成可能な制限内で物理メモリを使用する必要があります。

このようにスレッド処理、スケジュール設定、およびメモリ管理のモデルが異なるため、数千の同時実行ユーザー セッションをサポートするまで規模が拡大された RDBMS (リレーショナル データベース管理システム) では統合が課題になります。 アーキテクチャでは、スレッド処理、メモリ、および同期プリミティブの API (アプリケーション プログラミング インターフェイス) を直接呼び出すユーザー コードによってシステムのスケーラビリティが損なわれないことを保証する必要があります。

セキュリティ

データベースで実行されているユーザー コードは、テーブルや列などのデータベース オブジェクトにアクセスするときに、SQL Server認証と承認の規則に従う必要があります。 また、データベース管理者は、データベースで実行しているユーザー コードからファイルやネットワーク アクセスなどのオペレーティング システム リソースへのアクセスを制御できる必要があります。 (Transact-SQL などの非マネージド言語とは異なり) このようなリソースにアクセスする API が用意されているマネージド プログラミング言語ではこのことが重要になります。 システムは、ユーザー コードがデータベース エンジン プロセス外のマシン リソースにアクセスするための安全な方法を提供する必要があります。 詳細については、「 CLR 統合のセキュリティ」を参照してください。

パフォーマンス

データベース エンジンで実行されているマネージド ユーザー コードの計算パフォーマンスは、サーバーの外部で実行されるのと同じコードと同等である必要があります。 マネージド ユーザー コードからのデータベース アクセスは、ネイティブ Transact-SQL ほど高速ではありません。 詳細については、「 CLR 統合のパフォーマンス」を参照してください。

CLR サービス

CLR には、CLR とSQL Serverの統合の設計目標を達成するのに役立つさまざまなサービスが用意されています。

タイプセーフ検証

タイプ セーフなコードとは、メモリ構造にアクセスする際に適切に定義された方法のみを使用するコードのことです。 たとえば、有効なオブジェクト参照を例として考えると、タイプ セーフなコードでは、実際のフィールド メンバーに対応してメモリの固定オフセット位置にアクセスできます。 一方、オブジェクトに属するメモリの範囲の内外を問わず、任意のオフセット位置でメモリにアクセスするコードは、タイプ セーフではありません。 アセンブリを CLR に読み込むと、JIT (Just-In-Time) コンパイルを使用して MSIL にコンパイルされる前に、ランタイムによって、コードのタイプ セーフティを判断するためにそのコードを調べる検証フェーズが実行されます。 この検証に正常に合格するコードを、検証可能なタイプ セーフなコードと呼びます。

アプリケーション ドメイン

CLR では、マネージド コード アセンブリを読み込み、実行できるホスト プロセス内の実行領域として、アプリケーション ドメインの概念がサポートされます。 アプリケーション ドメインの境界でアセンブリどうしが分離されます。 アセンブリは、静的変数やデータ メンバーの可視性、およびコードを動的に呼び出す機能に関して分離されます。 また、アプリケーション ドメインはコードのロードとアンロード用のメカニズムでもあります。 アプリケーション ドメインをアンロードしないと、コードをメモリからアンロードできません。 詳細については、「 アプリケーション ドメインと CLR 統合セキュリティ」を参照してください。

コード アクセス セキュリティ (CAS)

CLR セキュリティ システムには、マネージド コードに権限を割り当てて、そのコードで実行できる操作の種類を制御する方法が用意されています。 コード アクセス権限は、コード ID (アセンブリの署名やコードの作成元など) に基づいて割り当てられます。

CLR では、コンピューター管理者が設定できるコンピューター全体のポリシーが規定されます。 このポリシーでは、コンピューターで実行される任意のマネージド コードに許可される権限が定義されます。 さらに、マネージド コードに対する追加の制限を指定するために、SQL Server などのホストで使用できるホスト レベルのセキュリティ ポリシーがあります。

.NET Framework のマネージド API により、コード アクセス権限で保護されているリソースでの操作が公開される場合、そのリソースへのアクセスが行われる前に、API がそのアクセス権限を要求することになります。 この要求により、CLR セキュリティ システムが呼び出し履歴内のすべての単位のコード (アセンブリ) を包括的にチェックします。 この処理は、リソースにアクセスする権限が呼び出しチェーン全体に許可されている場合にのみ行われます。

Reflection.Emit API を使用してマネージド コードを動的に生成する機能は、SQL Serverの CLR ホスト環境内ではサポートされていないことに注意してください。 このようなコードには実行するための CAS 権限がないので、コードは実行時に失敗します。 詳細については、「 CLR 統合コード アクセス セキュリティ」を参照してください。

HPA (ホスト保護属性)

CLR には、.NET Framework の一部であるマネージド API に、特定の属性で注釈を付けるメカニズムが用意されています。このような属性は CLR のホストにとって意味のある属性です。 次に、このような属性の例を示します。

  • SharedState。共有状態 (静的なクラス フィールドなど) を作成または管理する機能が API で公開されるかどうかを示します。

  • Synchronization。スレッド間で同期を実行する機能が API で公開されるかどうかを示します。

  • ExternalProcessMgmt。ホスト プロセスを制御する方法が API で公開されるかどうかを示します。

これらの属性を例として考えると、ホストされている環境で禁止される必要がある SharedState 属性などの HPA の一覧をホストで指定できます。 この場合、CLR では禁止一覧の HPA で注釈が付けられている API がユーザー コードから呼び出されることを拒否します。 詳細については、「 ホスト保護属性」と「CLR 統合プログラミング」を参照してください。

SQL Server と CLR の連携方法

このセクションでは、SQL Server SQL Serverと CLR のスレッド、スケジュール、同期、およびメモリ管理モデルを統合する方法について説明します。 特に、スケーラビリティ、信頼性、およびセキュリティの目標に照らし合わせて、この統合について解説します。 SQL Serverは基本的に、CLR が SQL Server 内でホストされている場合にオペレーティング システムとして機能します。 CLR は、スレッド処理、スケジュール設定、同期、メモリ管理のために、SQL Serverによって実装された低レベルのルーチンを呼び出します。 これらは、SQL Server エンジンの残りの部分で使用されるのと同じプリミティブです。 このアプローチを使用すると、スケーラビリティ、信頼性、およびセキュリティに関するいくつかの利点が得られます。

スケーラビリティ : 一般的なスレッド処理、スケジュール設定、および同期

CLR はSQL Serverユーザー コードの実行と独自の内部使用の両方のために、スレッドを作成するための API を呼び出します。 複数のスレッド間で同期するために、CLR は同期オブジェクトSQL Server呼び出します。 これにより、SQL Server スケジューラは、スレッドが同期オブジェクトで待機しているときに他のタスクをスケジュールできます。 たとえば、CLR からガベージ コレクションが開始されると、CLR のすべてのスレッドがガベージ コレクションの終了を待機します。 待機している CLR スレッドと同期オブジェクトは、SQL Server スケジューラに認識されるため、SQL Serverは CLR を含まない他のデータベース タスクを実行しているスレッドをスケジュールできます。 また、これにより、SQL Serverは CLR 同期オブジェクトによって取得されたロックを含むデッドロックを検出し、デッドロックの削除に従来の手法を採用できます。

マネージド コードは、SQL Serverでプリエンプティブに実行されます。 SQL Server スケジューラには、長時間生成されていないスレッドを検出および停止する機能があります。 CLR スレッドをSQL Serverスレッドにフックする機能は、SQL Server スケジューラが CLR 内の "暴走" スレッドを識別し、その優先順位を管理できることを意味します。 このようなランナウェイ スレッドは中断され、キューに戻されます。 繰り返しランナウェイ スレッドとして識別されたスレッドは、実行中の他のワーカーを実行できるように、一定期間実行が許可されません。

Note

データにアクセスしたり、ガベージ コレクションを起動するのに十分なメモリを割り当てる実行時間の長いマネージド コードは、自動的に処理が明け渡されます。 データにアクセスしない、またはガベージ コレクションを起動するのに十分なマネージド メモリを割り当てない、実行時間の長いマネージド コードは、.NET Framework の System.Thread.Sleep() 関数を呼び出して、明示的に実行を明け渡す必要があります。

スケーラビリティ : 一般的なメモリ管理

CLR はSQL Serverプリミティブを呼び出して、メモリの割り当てと割り当て解除を行います。 CLR によって使用されるメモリは、システムのメモリ使用量の合計で考慮されるため、SQL Serverは構成されたメモリ制限内に留まり、CLR とSQL Serverが相互にメモリと競合しないようにすることができます。 SQL Serverは、システム メモリが制約されている場合に CLR メモリ要求を拒否し、他のタスクでメモリが必要な場合に CLR にメモリ使用量を減らすように求めることもできます。

信頼性 : アプリケーション ドメインと回復できない例外

.NET Framework API のマネージド コードで、メモリ不足やスタック オーバーフローなどの重大な例外が発生した場合、必ずそのようなエラーから回復し、API の実装に対して一貫性のある正しいセマンティクスを保証できるとは限りません。 これらの API により、このようなエラーへの応答でスレッドを中断する例外が発生します。

SQL Serverでホストされている場合、このようなスレッドの中止は次のように処理されます。CLR は、スレッドの中止が発生したアプリケーション ドメイン内の共有状態を検出します。 CLR では、同期オブジェクトが存在するかどうかを確認することで、この処理を行います。 アプリケーション ドメインに共有状態が存在する場合は、アプリケーション ドメイン自体がアンロードされます。 アプリケーション ドメインをアンロードすると、そのアプリケーション ドメインで現在実行されているデータベース トランザクションが停止します。 共有状態が存在すると、このような重大な例外が例外をトリガーするセッション以外のユーザー セッションへの影響を拡大する可能性があるため、SQL Serverと CLR は共有状態の可能性を減らす手順を実行しました。 詳細については、.NET Framework のドキュメントを参照してください。

セキュリティ : 権限セット

SQL Serverを使用すると、ユーザーはデータベースにデプロイされるコードの信頼性とセキュリティの要件を指定できます。 データベースにアセンブリをアップロードするとき、アセンブリの作成者は SAFE、EXTERNAL_ACCESS、および UNSAFE の 3 つの権限セットのうちのいずれかをアセンブリに指定できます。

アクセス許可セット SAFE EXTERNAL_ACCESS UNSAFE
コード アクセス セキュリティ 実行のみ 実行および外部リソースへのアクセス 無制限
プログラミング モデルの制限事項 はい はい 制限事項なし
検証可能性の要件 はい はい いいえ
ネイティブ コードを呼び出す機能 いいえ いいえ はい

SAFE は、許可されているプログラミング モデルの中でも多くの制限事項が関連付けられており、最も信頼性が高く、セキュリティで保護されたモードです。 SAFE アセンブリには、実行、計算の実行、およびローカル データベースへのアクセスを行うには十分な権限が許可されます。 SAFE アセンブリは検証可能なタイプ セーフである必要があり、アンマネージ コードを呼び出すことはできません。

UNSAFE は、データベース管理者のみが作成できる信頼性の高いコードに指定します。 この信頼性の高いコードにはコード アクセス セキュリティに関する制限がなく、アンマネージ (ネイティブ) コードを呼び出すことができます。

EXTERNAL_ACCESS には、両者の中間に位置するセキュリティ オプションが提供されます。このオプションにより、SAFE の信頼性保証を備えたまま、コードからデータベース外部のリソースにアクセスできます。

SQL Serverは、ホスト レベルの CAS ポリシー レイヤーを使用して、SQL Server カタログに格納されているアクセス許可セットに基づいて、3 つのアクセス許可セットのいずれかを許可するホスト ポリシーを設定します。 データベース内部で実行するマネージド コードには、これらのコード アクセス権限セットのうちのいずれかが必ず許可されます。

プログラミング モデルの制限

SQL Serverのマネージ コードのプログラミング モデルには、関数、プロシージャ、型の記述が含まれます。通常、複数の呼び出しで保持されている状態の使用や、複数のユーザー セッション間での状態の共有は必要ありません。 さらに、既に説明したように、共有状態が存在すると、アプリケーションのスケーラビリティや信頼性に影響を与える重大な例外が発生する可能性があります。

これらの考慮事項を考慮して、SQL Serverで使用されるクラスの静的変数と静的データ メンバーを使用しないことをお勧めします。 SAFE アセンブリと EXTERNAL_ACCESS アセンブリの場合、SQL Serverは CREATE ASSEMBLY 時にアセンブリのメタデータを調べ、静的データ メンバーと変数の使用が見つかると、そのようなアセンブリの作成に失敗します。

SQL Serverでは、、ホスト保護属性で注釈が付SharedStateSynchronizationけられた.NET Framework API の呼び出しExternalProcessMgmtも禁止されます。 これにより、SAFE アセンブリとEXTERNAL_ACCESS アセンブリが、共有状態を有効にし、同期を実行し、SQL Server プロセスの整合性に影響を与える API を呼び出すのを防ぐことができます。 詳細については、「 CLR 統合プログラミング モデルの制限」を参照してください。

参照

CLR 統合のセキュリティ
CLR 統合のパフォーマンス