ASP コンポーネント ガイドライン
J.D. Meier
Microsoft Corporation
January 24, 2000
日本語版最終更新日 2000 年 4 月 24 日
この記事は、次のいずれかの作業を行うユーザーを対象にしています。
- ASP (Active Server Pages) コードからコンポーネントを呼び出す。
- ASP コードから呼び出されるコンポーネントを設計する。
- ASP コードのコンポーネントを使用する。
内容
はじめに
コンポーネントを使用する理由
ステート (状態) 管理
スコープ (適用範囲)
サービスの分割
スレッド モデル
セキュリティ
Server.CreateObject と CreateObject
パラメータの引き渡し
イベント
OnStartPage/OnEndPage と ObjectContext
エラー処理
グローバル変数
コンポーネントの配布
結論
はじめに
コンポーネントが大好きなユーザーもいれば、コンポーネントを恐れるユーザーもいます。そしてコンポーネントを恐れるユーザーは、常にコンポーネントの恐ろしさについて話を共有しようとするものです。ぜひ、コンポーネントに立ち向かいましょう。 特に ASP のコンポーネントを使用する場合、知識がないためにユーザーが苦しめられることがあります。つまずいて転んでも、立ち上がり、ほこりを払って、前へ進んでいきましょう。この記事では、より優れたコンポーネント ベースの ASP ソリューションを構築するために必要な、経験から学んだ一般的なガイドラインをご紹介します。
コンポーネントを使用する理由
コンポーネントのガイドラインについて議論する前に、コンポーネントが ASP アプリケーションに与える付加価値についてご紹介します。コンポーネントに馴染みのない多くの開発者たちは、何をそれほど大騒ぎしているのかと不思議に思うことでしょう。コンポーネントを使用することにより、ASP アプリケーションに与えられる利点には次のようなものがあります。
- 機能のカプセル化および詳細な実装の隠蔽
- 再利用性 (別のクライアント アプリケーションによる再利用も含む)
- 知的所有権の保護
- スケーラビリティ (拡張性) (複数のマシンへアプリケーションの配布が可能)
- 設定および展開の柔軟性
- パフォーマンス (特に、アーリーバインディングが重要な要因である場合)
- Win32® API 呼び出し、あるいはプログラミング言語におけるそのほかの低レベル機能のようなシステムへのアクセス
- 明示的な型指定 (Visual Basic® Scripting Edition [VBScript] では明示的な型指定を行いません。だからといって、JScript® がより優れているというわけではありません。)
- ユーザー インターフェイスからのビジネス ロジックの分割、あるいは Web 開発者からの Web 設計者の分離
これらの利点にはコストがかかる場合があります。コンポーネントを利用するソリューションでは開発工程がより複雑になるために、ほかの開発に比べてコストが必要です。展開およびトラブルシューティングもより面倒になり、これらが現実的な要因になります。しかし、短期的な障害によって長期的な投資効果を妨げるべきではありません。次の項目を確認して、コストをかけるべきかどうか検討してください。
- 現行のコード ベース
- 開発チームの専門知識および技術
- ホスト サーバーに対する制御のレベル
- 特定のタスクに使用するツールおよび言語の選択
- 現存する相互運用可能性に関する問題
- パフォーマンスおよびスケーラビリティに関する要因の有無
- プロジェクトのタイムフレーム
- アプリケーションの維持およびサポートを行う人材について。たとえば、開発チームによる引き継ぎが可能かどうか。
これらの検討事項を調査した上で、前提を検査してください。プロトタイプを作成すると、現状を即座に把握することができます。
コンポーネントの利点について少し理解したところで、次へ移りましょう。次のガイドラインに従うことにより、これらの利点を最大限引き出すことが可能になります。これらを足掛かりとして、より安定した、スケーラビリティのある、パフォーマンスに優れた ASP コンポーネント アプリケーションを構築してください。
ステート (状態) 管理
推奨する方法
一般には、状態を保持しないコンポーネントおよび状態を保持しない ASP ページをできる限り使用してください。コンポーネントはメソッドの呼び出しごとに、その状態を要求するべきではありません。複雑な状態はデータベースに保存してください。単純なデータについては、Cookie、QueryString、あるいは隠しフォーム フィールドを利用してページに渡してください。
理由
サーバーのリソースは限られています。コンポーネントの状態を維持するということは、リソースの競合および同時実行の問題にアプリケーションをさらし、重要なリソースを消費してしまうことを意味します。状態を保持しないコンポーネントを使用することにより、これらの問題を避けることができます。また、複数のクライアントによるリソースの共有を増やし、より多くの展開法を提供することが可能になります。
共通のトラップ
よく開発者が陥る落とし穴として、状態を保持しなければならないコンポーネントを設計したり、使用してしまうことがあります。このデスクトップ的な考え方には気を付けてください。多くの場合、デスクトップ環境から開発しようとする開発者たちは、状態に依存するコンポーネントを設計してしまいます。
詳細情報
ASP セッションの使用を避けることにより、プログラムの処理を簡潔にし、サーバー リソースの消費を減らして、サーバーのパフォーマンスを向上させることができます。ASP セッションを使用しない場合は、インターネット サービス マネージャ (インターネット サービス マネージャ [IIS] ドキュメントを参照してください) においてセッションの状態を無効にしてください。セッションを要求しない ASP ページでは次のタグを使用し、ページごとにセッションの状態を無効にすることもできます。
<%@ENABLESESSIONSTATE=False %>
特に Web ファームにおいてアプリケーションを実行する場合には、柔軟性のある展開がもう 1 つの重要な側面になります。ASP セッションに依存している場合、セッションの状態はサーバー固有のものであるため、ユーザーからの要求は特定の Web サーバーへ送信されます。中間層および Web サーバーにおいて状態を持たず、データベースを使用することにより、ファームにおいて利用可能なあらゆる Web サーバーで ASP 要求が処理されます。その結果として競合が減り、より高い冗長性が提供され、配布におけるオプションが増えます。
ASP セッションを使用せずに複数のページへデータを引き渡す方法については、次の KB (Knowledge Base) の記事を参照してください。
Don Box はまた、「ActiveX®
Q&A article 」においても、MTS に関する状態管理について詳細な洞察を行っています。
スコープ (適用範囲)
推奨する方法
一般に、コンポーネントはページ スコープで使用してください。つまり、オブジェクトの作成、使用、および解放をすべて同じページで行います。
"Both" あるいは "Apartment" に設定されているコンポーネントは、ページ スコープ内で有効に動作します。ページ スコープのみで使用する場合は、Visual Basic のコンポーネントのような、アパートメント モデルのコンポーネントを使用してください。コンポーネントをアプリケーションあるいはセッションに保存する場合は "Both" モデルをお勧めします。両方に設定されているコンポーネントはセッション スコープあるいはアプリケーション スコープに保存することができますが、スレッド セーフなコンポーネントである必要があります。
理由
ページ スコープにおいてコンポーネントを使用することにより、サーバー リソースを増やすことができます。また、リソースを解放することにより同時実行の問題を最小限に押さえ、プール可能なリソースを複数のクライアント間で共有することが可能になります。さらに、ページ スコープのコンポーネントを使用することにより、セッション スコープあるいはアプリケーション スコープのオブジェクトが起因するスレッドに関する問題を回避することができます。スレッドに関する問題の詳細については「スレッド モデル」において紹介しています。
共通のトラップ
最もよくある問題として、Visual Basic あるいはほかのアパートメント モデルのオブジェクトを、アプリケーション スコープに保存してしまうことがあります。Server.CreateObject を使用して作成したアパートメント モデルのオブジェクトをアプリケーション スコープに保存しようとすると、次のようなエラーが表示されます。
アプリケーション オブジェクト エラー 'ASP 0197: 80004005'
許可されていないオブジェクトの使用
/VirDir/global.asa, 行 7
アパートメント モデルの動作を含むオブジェクトは、アプリケーションの組み込みオブジェクトに追加できません。
ただし、<OBJECT> タグを使用してアパートメント モデルのオブジェクトをアプリケーション スコープに保存すると、実行時エラーは表示されません。代わりに、特別な STA (シングルスレッド アパートメント) スレッド上にオブジェクトが作成され、すべての呼び出しはそのスレッドに対してマーシャリングされてシリアル化されます。これは、そのコンポーネントに対するスレッド モデルが選択されていないために起こります。残念ながら、この場合は実行時に問題が発生します。
よくあるもう 1 つの問題は、アパートメント モデルのオブジェクトをセッション スコープに保存してしまうことです。これにより、ユーザーのセッションは特定のスレッドに連結されます。これはサーバーのパフォーマンスに大きく影響します。そのオブジェクトを作成したスレッドに対してすべての呼び出しがシリアル化されるため、基本的にスレッド プールの意味はなくなります。
詳細情報
詳細については、次の KB の記事を参照してください。
サービスの分割
推奨する方法
プレゼンテーション、ビジネス、およびデータ サービスを切り離してください。ビジネス コンポーネントではビジネス ルールを強制的に適用し、データ アクセス テクノロジーを包含するべきではありません。これはデータ層におけるコンポーネントの役割です。また、ビジネス コンポーネントから ASP オブジェクトを参照してはいけません。
ASP ではプレゼンテーション サービスを提供しています。ASP を参照するオブジェクトは HTML を処理する必要があります。その結果として、これらのオブジェクトは MTS/COM+ に登録されたビジネス コンポーネントを呼び出すことができます。
理由
アプリケーションを独立した個別のサービス毎に分割することには、次のような利点があります。
- より効率的なコンポーネントの再利用
- Windows DNA モデル
のサポート
- トラブルシューティングのためのより効率的な分離
- より柔軟性のある展開 (サービスをきちんと切り離すことにより、複数のマシンにアプリケーションを配布することが可能になります)
共通のトラップ
よくある落とし穴として "Swiss Army" コンポーネントと呼ばれているものがあります。Swiss Army コンポーネントとは、ちょうどナイフと栓抜き、つま楊枝、そのほかに 17 のツールを 1 つにするように、ユーザーのすべてのサービスを 1 つにして提供します。関連のないサービスを 1 つのコンポーネントにグループ化すると取り扱いが難しく、それを理解して維持していくことは困難になります。
陥りやすいもう 1 つの落とし穴として、ビジネス コンポーネントから ASP を参照してしまうことがあります。Request または Response オブジェクトを使用するか、あるいは内部に HTML を組み込むことにより ASP をビジネス ロジックに結合すると、異なるクライアントによるコンポーネントの再利用およびスケールアウトが制限されてしまいます。ASP 組み込みオブジェクトを参照する複数のオブジェクトは、Web サーバーとして同一のコンピュータ上に配置するべきではありません。スケールアウトのために、理論的にはビジネス コンポーネントを異なるコンピュータへ配布することは可能です。ASP スクリプトに直接プレゼンテーション サービスを提供するか、あるいは ASP 組み込みオブジェクトを参照するコンポーネントを処理する HTML を構築して、これらのコンポーネントを IIS のコンピュータに保持します。
詳細情報
優れた設計パターンは、一般的なビジネスの問題を処理するモデルとして利用することができます。たとえば、CRUD (Create、Read、Update、Delete) 操作を処理するパターンにより、アプリケーションをプレゼンテーション、ビジネス ルール、およびデータ アクセスなどの独立した論理サービスに分割することができます。
アプリケーションのモデルとして利用する設計パターンの具体例については、次の記事を参照してください。
- 「FMStocks Application: Start Here (英語)」
スレッド モデル
推奨する方法
コンポーネントのスコープあるいはコンポーネントのスレッド モデル、どちらを優先しますか ? どちらを優先するとしても、ページ スコープにおいてアパートメント モデルあるいは Both モデルのコンポーネントを使用することに固執しない限り、スレッドによる影響について検討する必要があります (スレッド モデルの選択に迷っている Visual Basic のプログラマは、常にアパートメント モデルを選択してください)。
アプリケーションあるいはセッションにオブジェクトを保存する場合、両方モデルに設定されたコンポーネントを使用して FTM (フリースレッド マーシャラ) を集成する必要があります。
シングル スレッドのコンポーネントは使用しないでください。また ASP においてフリー スレッドのコンポーネントを使用することは避けてください。
注意 : 不注意により Visual Basic においてシングル スレッドのコンポーネントを生成してしまう場合があります。プロジェクトのプロパティにおいて、[全般] タブの [スレッド モデル] を必ず [アパートメント スレッド] に設定してください。また、同じタブ上にある [対話型インターフェイスの抑制] および [メモリに保持] も忘れずにオンにしてください。
理由
Visual Basic を使用している場合は簡単です。Visual Basic はアパートメント モデルに制限されています。Visual Basic のアパートメント モデルのオブジェクトは、ページ スコープにおけるパフォーマンスが非常に優れているため、これが大きな制限とはなりません。Fitch and Mathers Stock 2000 により、このパフォーマンスに対する先入観は一掃されました。さらに、ASP、SQL、および Visual Basic により構築された頻繁にアクセスされる多くのサイトにおいて、日々、ページ スコープにおけるアパートメント モデルのコンポーネントから、十分なスケーラビリティおよびパフォーマンスを得ることができることは立証されています。
Both モデルに設定されているコンポーネントに FTM を統合すると、マーシャリングあるいはスレッド スイッチを使用せずにスレッド間の呼び出しを行うことができます。Both モデルに設定されているコンポーネントに FTM が統合されていない場合、ASP はコンポーネントを Visual Basic コンポーネントのようにアパートメント スレッドのオブジェクトとして扱います。COM+ オブジェクト プールを利用する場合は FTM を統合しないよう注意してください。オブジェクト プールの規則については、プラットフォーム SDK ドキュメントを参照してください。
シングル スレッドおよびフリー スレッドのコンポーネントは、システムのセキュリティ コンテキストにおいて実行されます。さらに悪いことに、シングル スレッドのコンポーネントはデッドロックを起こしやすいのです。
共通のトラップ
おそらく最もよくある落とし穴として、シングル スレッドのコンポーネントを使用してしまうなど、ASP における使用を目的として設計されていないコンポーネントを使用してしまうことがあります。多くの開発者は、デスクトップ アプリケーションを ASP へ移行する場合、あるいはサード パーティ製のコントロールを使用して作業を行う場合にこの落とし穴に陥ります。コンポーネントのスレッド モデルが明確でない場合は、コンポーネントのレジストリ エントリを確認してください (ただし、これが常に正しいとは限りません)。
詳細情報
スレッド モデル、およびスレッド モデルが ASP に与える影響に関する詳細については、次の記事を参照してください。
さらに次の KB の記事において、スレッドに関する問題についての詳細が紹介されています。
セキュリティ
推奨する方法
コンポーネントは、そのコンポーネントを使用するユーザー コンテキストに関して、いかなる前提も立てるべきではありません。HKEY_CURRENT_USER あるいはデスクトップに固有のリソースなど、ユーザーを特定した情報はコンポーネントにおいて使用できないためアクセスしないでください。SendKeys を使用したりユーザー インターフェイスに依存するコンポーネントを呼び出してダイアログ ボックスを起動するなど、アプリケーションは、デスクトップの操作を必要とする動作を直接行うべきではありません。
理由
コンポーネントは、セキュリティで保護された異なるデスクトップにおいて実行されます。つまりアプリケーションは、ダイアログを起動したり、ほかの GUI エンティティと (たとえば SendKeys を使用して) 対話することはできません。既定では、Inetinfo.exe はデスクトップと対話することができません。異なるユーザー コンテキストにおいても、コンポーネントが特定のリソース (主にレジストリの HKEY_CURRENT_USER セクション) にアクセスすることはできません。
共通のトラップ
よくある誤りとして、HKEY_CURRENT_USER 下のキーを参照してしまうことがあります。たとえば、HKEY_CURRENT_USER ハイブ下のキーを参照するために、ASP において Visual Basic の GetSetting 関数および SaveSetting 関数を使用すると失敗します。次の KB においてこの詳細が説明されています。
デスクトップ クライアントからではなく ASP からコンポーネントが呼び出される場合、プリンタ、MAPI 情報、およびネットワーク共有は一般的に "切断" されます。
詳細については、次の KB の記事を参照してください。
詳細情報
セキュリティに関して検討するべき項目がいくつかあります。
- いずれの IIS 認証方式が有効なのか ?
- Web アプリケーションを、インプロセスあるいはアウトプロセスのどちらに設定するか ?
- コンポーネントが MTS あるいは COM+ に登録されている場合、サーバーあるいはライブラリ パッケージのどちらにあるのか ?
- ローカル DLL、リモート DLL、ローカル EXE、リモート EXE のどれを呼び出しているのか ?
セキュリティに関する詳細な説明はこの記事には含まれていません。ただしこのトピックは複雑なため、次の記事を参照して ASP コンポーネントの観点からこの問題に関する理解を始めてください。
次の記事に IIS を使用したセキュリティの優れた概要が紹介されています。
- 「Authentication and Security for Internet Developers (英語)」
Server.CreateObject と CreateObject
推奨する方法
Server.CreateObject を使用してください。特にMTS/COM+ ライブラリ パッケージを使用している場合は Server.CreateObject を使用してスレッドのブロッキングを避けてください。
理由
スクリプト エンジンにより、CreateObject は CoCreateInstance の呼び出しと等しくなります。Server.CreateObject の代わりに CreateObject を使用すると、次のようなことが起こります。
- ASP がオブジェクトを認識しない。
- OnStartPage/OnEndPage ページ メソッドが呼び出されない。
- ASP がオブジェクトのスレッド モデルを識別しない。
Server.CreateObject は GetObjectContext.CreateInstance と同じです。つまり ASP によりオブジェクトが認識され、スレッド モデルが識別されます。さらに Server.CreateObject を呼び出すことにより、ASP ページがトランザクション可能な場合、コンポーネントと ASP ページは同じトランザクション内に存在します (トランザクションが可能なページには、ビジネス ルールおよびプレゼンテーション層の回避できる結合が含まれている可能性があることに注意してください)。
共通のトラップ
オブジェクトがファイアウォールに隠されている場合、CreateObject を呼び出す必要があります。詳細については、「Q193230 PRB:
Server.CreateObject Fails when Object is Behind Firewall (英語) 」を参照してください。
詳細情報
IIS 4.0 におけるパフォーマンスは、Server.CreateObject よりも CreateObject の方が速いのですが、IIS 5.0 では変わりません。また、MTS/COM+ のライブラリ パッケージあるいはアプリケーションを使用している場合、Server.CreateObject によりスレッドのブロッキングを避けることができます。
パラメータの引き渡し
推奨する方法
"出力" パラメータを "バリアント型 (Variant)" に宣言してください。これは Visual Basic において、"参照渡し" のパラメータが "バリアント型" になることを意味しています。"値渡し" により渡されるパラメータ ("入力" パラメータ) を "バリアント型" に制限する必要はありませんが、"バリアント型" との互換性は必要です。
理由
スクリプト作成クライアントは "バリアント型" を認識します。また COM サーバーは特定のデータ型を認識することができます。特定のデータ型を "値渡し" により COM サーバーへ渡すと COM サーバーは問題なくそれらを受け取ります。しかし "バリアント型" の場合、"参照渡し" の引数はエラーとなり、ASP スクリプトへ "返送" されます。
共通のトラップ
最もよくある誤りの 1 つに型の不一致があります。これは通常、変数が "バリアント型" 以外のものとして COM オブジェクトへ "参照渡し" により渡されることが原因です。一般的な回避策として、パラメータを "値渡し" により渡すか、あるいは "バリアント型" へ変更します。
詳細情報
コンポーネントを複数のマシンへ配布したり、あるいはアウトプロセスで実行する場合、"値渡し" を行うことによりパフォーマンスが大幅に向上します。"参照渡し" によりパラメータを渡すと、データが往復するために、複数のプロセスあるいはマシンにより多くのマーシャリング オーバーヘッドがかかります。また "参照渡し" を実際に必要としない場合は、"値渡し" によってパラメータを引き渡すと正確さおよび効率性が向上します。既定では、Visual Basic は "参照渡し" によりパラメータを渡していることに注意してください。
次の KB の記事では、ASP から COM オブジェクトへのパラメータの引き渡しについて紹介しています。
イベント
推奨する方法
イベントを返すためにほかのコンポーネントを待っているコンポーネントは呼び出さないでください。
コンポーネント メソッドは、できる限り早く ASP へ実行処理を返す必要があります。非同期の呼び出しを行う場合、あるいは作業に時間がかかりオンラインで実行する必要がない場合には、MSMQ あるいは COM+ キュード コンポーネントを使用してください。
時間のかかる処理が完了するまで ASP を待たせるよりも、非同期的に作業項目をディスパッチしてください。そして ASP からクライアントへ応答を返します。作業項目が完了すると、電子メールあるいはほかの手段を利用してクライアントに通知を行うことができます (次を参照してください)。
理由
ASP はイベントを処理するように設計されていません。最適なサーバー パフォーマンスのために、HTTP 要求に対してできる限り早く応答を返してください。
共通のトラップ
状態フラグを確認するためにサーバーをループすることは、ブラウザへの通知を行う方法としてサーバー にとって良い方法ではありません。
詳細情報
開発者たちがイベントに注意する一般的な理由は、サーバー上で処理されている作業に関してブラウザへ通知を行うためです。ソケットをとおしてサーバー上のもう 1 つのポートを開くなど、ブラウザへの複雑な通知システムを構築することもできますが、次に紹介するテクニックを利用することもできます。
- 電子メールによる通知を行う。
- サーバーのポーリングを行う Meta-Refresh タグをページに追加する。
- ブラウザへリンクを送信し、クライアントにおいて手作業により保留中の要求の状態を確認する。
次の KB の記事において、これらの問題に関して紹介しています。
OnStartPage/OnEndPage と ObjectContext
推奨する方法
ISS 4.0 以降では、ObjectContext を使用して ASP 組み込みオブジェクト (たとえば Response、Request、Server など) へアクセスしています 。ScriptingContext オブジェクト、OnStartPage、および OnEndPage はできる限り使用しないでください。
理由
OnStartPage、OnEndPage、および ScriptingContext オブジェクトはレガシ サポート用に提供されています。
共通のトラップ
ASP オブジェクトを挿入すると、ATL ウィザードは OnStartPage および OnEndPage を使用します。
詳細情報
両方モデルあるいはアパートメント モデルのコンポーネントを MTS/COM+ に登録せずに ObjectContext を取得します。ローカルの ActiveX EXE に対しては ObjectContext を使用できないため、OnStartPage/OnEndPage が必要になります。フリー スレッドあるいはシングル スレッドのコンポーネントのコンテキストを使用するには、これらのコンポーネントを MTS/COM+ へ登録する必要があります。登録を行わない場合は、OnStartPage を使用してください。
エラー処理
推奨する方法
エラー処理ルーチンでは、予期しないエラーを想定する必要があります。アプリケーションのあらゆるセクションにおけるエラーを把握し、できる限り詳細にログを作成してください。詳細なログは、例外的および突発的な状況においてエラーを追跡し、分離して、トラブルシューティングを行うために非常に重要になります。これらのログはテキスト ファイルに作成されるか、あるいは NT イベント ログに書き込まれます。多くの場合、呼び出し側に問題の発生を通知する際に、情報を追加しながらエラーの詳細を浮き上がらせる (下位でのエラー内容を上位へと確実に伝える) と効果的です。これにより、呼び出し側は、特別な問題に対して特別な方法で対処することが可能になります。
エラーを記録する場合、できる限り有用な情報を提供することが重要です。次にその例を示します。
- 現在のユーザー コンテキスト (Win32 API への呼び出しを行います -- GetUserName)
- 現在のスレッドの ID (Win32 API への呼び出しを行います -- GetCurrentThreadId、あるいは Visual Basic の App.ThreadId)
- 現在の時刻 (ミリ秒を取得するには Win32 の GetTickCount を使用します)
- メソッドに引き渡された引数
- エラーを起こしたソース、およびメソッド名
理由
経験から言うと、適切なエラー処理およびログ作成を行うことにより、最も効果的に問題を分離して解析することができます。
共通のトラップ
ASP 0115 エラーを覚えていますか ? 皆さんが苦しめられていなければいいのですが。この問題に苦戦しているユーザーは、「Troubleshooting
with the IIS Exception Monitor (英語)」を参照することをお勧めします。
ASP 0115 エラーは常に開発者の制御下にあるわけではありません。しかし大半の場合、ヘルプによってエラーが解決されるように、エラー処理により多くのエラーを防ぐことができます。
要するに、最も大きな落とし穴は、エラー処理をすべて一緒にして飛ばしたり、あるいは有用な診断情報を無視してしまうことにあります。
COM において、コンポーネントの境界を越えて例外を広めることは賢明な方法ではありません。例外を把握してください。ただし、エラーを呼び出し側に伝える場合は HResults を返してください。
詳細情報
次の記事に、効果的なエラー処理の実用例が紹介されています。
- 「Bulletproofing Your ASP Components (英語)
」 Charles Alexander 著
- 「Fitch &
Mather Stocks: Web Application Design (英語)」
グローバル変数
推奨する方法
コンポーネントにおいてグローバル変数を使用することは避けてください。これは Visual Basic において、標準の .BAS モジュールにパブリック変数あるいはグローバル変数を持たないことを意味します。
理由
グローバル変数は実際にはグローバルではありません。スレッドにはそれぞれ独自のコピーがあります。複数のメソッドを同一のスレッド上で実行する場合、これらのメソッドは同じ変数を参照するか、それぞれの独自のコピーにアクセスします。つまり、たとえばあるユーザーがスレッド A のグローバル変数に値を書き込んだとしても、スレッド B において実行している別のユーザーによりその新しい値が参照されることはありません。
これは、Visual Basic がその内部において TLS (スレッドローカル ストレージ) を使用し、グローバル変数を参照していることに起因します。つまり、各スレッドはパブリック変数の独自のコピーを持っており、このような複数のコピーが存在するために、グローバルなデータが実際には "グローバル" ではないのです。またユーザーの要求にかかわらず、同じスレッド上で実行するユーザーは同じ変数にアクセスします。
共通のトラップ
異なるスレッドによって、同じデータを再度要求する別のユーザー要求に対してサービスを提供する場合、標準の .BAS モジュールにおいてパブリック変数を使用するとデータを破損する可能性があります。
詳細情報
1999 年 6 月版、Matt Curland の「Visual Basic Programmer's Journal (英語) 」 にある次の記事は必見です。
- 「Black Belt Programming - Create Worker Threads in DLLs」
- 「COMponent Builder - Create Efficient Multithreaded Apps」
さらに Daniel Appleman の「A Thread to Visual Basic (英語) 」には、Visual Basic におけるマルチスレッド機能の概要がわかりやすく紹介されています。
コンポーネントの配布
推奨する方法
コンポーネントの配布には、パフォーマンス、スケーラビリティ、およびセキュリティに関する問題が含まれます。同一コンポーネントの異なる配布バージョンでは、より高いパフォーマンスおよび優れたスケーラビリティを持つ、より管理しやすい構成を実現することができます。
複数のマシンにコンポーネントを配布する場合、次のガイドラインに従うことにより、パフォーマンスおよびスケーラビリティを向上させることができます。
- 同一のコンピュータ上にある ASP 組み込みオブジェクトを参照するコンポーネントを IIS として実行する。
- 1 つあるいは複数のデータベース コンポーネントをアプリケーション サーバー上で実行する。
- 最も意味のあるマシンにおいてビジネス コンポーネントを実行する。ASP からビジネス コンポーネントを切り離した場合、アプリケーションの設計、マシンの有効性、およびテストに基づいてこれらを自由に選択することが可能。
もちろん例外はあります。しかしこれらはガイドラインとしては適しています。
理由
複数のマシンにコンポーネントを配布することにより、アプリケーションはスケーラビリティに関する要求を維持することができます。また、上記のガイドラインに従うことにより、アプリケーションのパフォーマンスおよびスケーラビリティに関する目標を達成することが可能になります。
ASP 組み込みオブジェクトを参照するオブジェクトは、何度も Web サーバーとの対話を行います。またこれらのオブジェクトはプレゼンテーション層の一部であるため、そこに属します。
データベース、あるいは極端なデータ集約型のロジックは、おそらくデータベース内のストアド プロシージャに属しています。データ アクセス コンポーネントをデータベースの代わりにアプリケーション サーバーに配置することにより、コストのかかるコンポーネント間の DCOM 呼び出しを避けることができます。その代わりにデータ アクセス コンポーネントは TCP/IP のような SQL Server 通信を使用し、データベースとより効果的に対話を行うことができます。
共通のトラップ
次に回避可能な落とし穴についていくつかご紹介します。
- スケールアウトがより適切な場合において、スケールアップを追求する。
- ファイアウォールに関する検討事項を考慮していない (適切に対処してください。開発環境のマシン間にファイアウォールが存在する場合は、テスト シナリオにもファイアウォールを追加してください)。
- ASP 埋め込みオブジェクトを参照するコンポーネントを、IIS サーバーから独立した複数のマシンへ配置する (ASP 埋め込みオブジェクトのコールバックおよびマーシャリングはコストがかかります)。
- コンポーネント内からのレイトバインディングを使用する (これにより、別途 GetIdsOfNames が呼び出されます。これは配布されたアプリケーションにおいてコストがかかる可能性があります。できる限り、アーリーバインディングを使用してください)。
- パラメータを "参照渡し"で使用する (これにより、より多くのマーシャリング オーバーヘッドがかかります。できる限り値渡しを行ってください)。
また、リモートの MTS コンポーネントを IIS から呼び出す方法も複雑になる可能性があります。パフォーマンスを向上させセキュリティの問題を単純にする簡単でより効果的なソリューションは、中間 MTS/COM+ パッケージあるいはアプリケーションを呼び出すことです。アーリーバインディングによりネットワーク Hops を軽減し、パフォーマンスを向上させることができます。またサーバー パッケージあるいはアプリケーションを使用することにより、パッケージあるいはアプリケーションを同様に稼動させるための ID を設定することができます。このテクニックについては、KB の記事 「Instantiating Remote Components in Microsoft Transaction Server and Internet Information Server (英語)」で紹介しています。
詳細情報
サービスどうしを切り離し、特にビジネス コンポーネントから ASP を切り離すことにより、その配布作業はかなり柔軟になります。問題に対してより多くのコンピュータを導入し、必要に応じてコンポーネントを分散させ、スケーラビリティとそれに伴うパフォーマンスに関する問題を処理することが可能になります。テストを行い確認してください。テストの方法については、次の基本的なガイドラインを参照してください。
- エラーを起こす操作を行い、実際に出るエラーを確認して、Web ファームの信頼性をテストする。
- 1 秒ごとに処理される ASP 要求の数を確認し、パフォーマンスをテストする。
- 1 秒ごとに処理する必要のある ASP 要求のしきい値を設定し、スケーラビリティをテストする。ストレス ツールを使用し、パフォーマンスがその許容量を超えるまでユーザーを追加して、アプリケーションのテストを行う。
- アプリケーションのストレス テストを行い、単一のブラウザを使用したテストでは明確にならない競合およびそのほかの問題を明らかにする。
アプリケーションのストレス テストの詳細については、「I Can't Stress It Enough − ASP アプリケーションのロード テスト」を参照してください。
結論
これまで見てきたように、開発サイクルにおいては想定しておくべきいくつかの留意事項があります。ここで事前に紹介したアプリケーションのガイドラインをできる限り参考にしてください。これにより、コストのかかる間違いを未然に防ぐことができます。開発サイクル全体において、ここで概説したいくつかのガイドラインに従うことにより、いくつかの繰り返しを防ぐだけでなく、実際にスケーラビリティおよび信頼性のある、パフォーマンスの高い ASP コンポーネント ベースのソリューションを提供することが可能になります。
|