Scott Seely
Microsoft Corporation
November 7, 2001
日本語版最終更新日 2002 年 12 月 2 日
はじめに
以前、このコラムのゲスト紹介で述べたように、
私は Marcelo Uemura と David Willson と共同で、
ColdStorage
と呼ばれるファイル ストレージ XML Web サービスの作業をしていました。
私たちは、数週間前にこのサンプル サービスの最初のバージョンをリリースしました。
私たちがその設計中に遭遇した主要な問題点の 1 つは、
SOAP を使って、大量データ トランザクションを処理する方法でした。
私たちは数少ない選択肢を議論し、
結局、手作業でチャンキングする手法に決めました。
私は、これがいくつか検証を要するトピックであると考えました。
Web サービスがより普及するようになるにつれ、
Web サービスが実行する作業の複雑さも増加せざるをえません。
また相応して、Web サービスが扱うデータの量も同様に増加していくでしょう。
そのデータの転送を扱う方法をどのように選択するかによっては、
Web サービスの有用性に直接影響を及ぼします。
定義と設計の問題点
大量データとは、マルチメガバイトのデータ、あるいはマルチメガバイトのデータ ストリームのことです。
データのソースとは無関係です。
それは、ビデオ クリップ、法律文書、または医学用画像のことを指すかもしれません。
データは、必ずしもファイル形式である必要はありません。
E.T. を検索する衛星無線データを処理しているかもしれませんし、
分散環境で癌細胞との薬物相互作用をモデル化しているかもしれません。
データの量は、これらの異なるデータ ソースと相互に結び付いている特性の 1 つです。
大量のデータについて設計することは、
データ量の問題をそれ以外の問題よりも詳しく検討する必要があることを意味します。
ここでは、その問題点を一覧します。
一覧した順序に特別な意味はありません。
パフォーマンスと使用法のシナリオ
大量データは、まさにその性質により、
以前は見落としがちであったオーバーヘッドのコストを拡大します。
たとえば、パフォーマンス テストでは、
20 KB の配列パラメータのエンコーディングはほんの些細な問題にしかなりませんが、
20 MB の配列パラメータのエンコーディングは間違いなく大きな問題を引き起こします。
セキュリティで保護されたチャネルで大量のデータを配信することは、
エンコーディングのコストに加えて、暗号化のコストもかかることを意味します。
実際には、
このようなパフォーマンスの問題点にどのように対応するかは、
Web サービスを顧客がどのように使用することを期待するかによって異なります。
十分に計画された設計は、前もって使用法のシナリオを検討しているでしょう。
たとえば、その Web サービスは B2B の内部で使用されることが多いでしょうか。
あるいは、その Web サービスはユーザー インターフェイスと結び付いているでしょうか。
明らかに、この種のデータ転送は、クライアント側での非同期設計の候補になります。
ColdStorage サンプルの場合のように、
Web サービスを呼び出すユーザー インターフェイスが存在する場合、
コンピュータがデータ転送を行っている何時間もの間、
何もせずにただ傍観していたいと思う顧客はいないでしょう。
タイミングが Web サービスの重要な要因になりますか。
たとえば、Web サービス メソッドの呼び出しはリアルタイムに完了する必要がありますか。
または、結果の配信を遅延して、後で配信することが可能ですか。
重大な障害とエラーの復旧
データを 1 つの大きなブロックとして送信している場合、
タイムアウトや接続障害は特に痛切な問題になりえます。
大量データの転送中にタイムアウトまたは接続障害が発生すると、
最初から転送を再開するのではなく、
接続を再確立し、残っているデータを転送するのが最善のメカニズムですか。
容量の計画
大量データの容量計画は困難です。
非常に大きなファイルのアップロードやダウンロードでは、
転送の間、TCP/IP 接続を開いたままにすることになるでしょう。
多くのユーザーがこれを行うとなると、
スケーラビリティはまったくなくなります。
わずか数キロバイトからマルチメガバイトまでデータのサイズが変化するときに、
実際に生じるパフォーマンスをモデル化すると、
現実的な結果を示さない可能性があります。
着信または送信されるデータの実質的な平均サイズを示すには何らかの安定した統計が必要になるでしょう。
テスト
一般的には、
SOAP の元になるトランスポート メカニズムが大量データの転送を扱う可能性があると想定する必要があります。
結局、テスト チームは、Web サービス自体がその想定に対して正しく機能することを確認する必要があります。
ただし、それでもまだテストには問題が残ります。
たとえば、Web サービスがマルチメガバイトのサイズのデータを定常的に扱うと仮定します。
テスト チームは同じサイズのファイルを使ってテストする必要があるでしょうか。
それとも、比較的小さなデータが高速にテスト結果を返せば問題ないでしょうか。
このような問題の答えは、Web サービスが大量のデータ ブロックを使って何を行うかによって異なります。
最低でも、サービスの開発スケジュールを設定するときに、
長時間の遅延を許可するテスト時間を推定してください。
XML Web サービスはこのジョブにとって最適なツールですか。
釘を打つのにドライバを使う人はいません。
いつまでたっても釘は打ち込めませんし、ドライバはだめになってしまいます。
もしも、何も加工しないビットをそのままサーバーに転送するのであれば、
このことをはるかに効果的に行う低レベルのプロトコルが存在します。
たとえば、FTP や WebDAV などです。
このことはいずれ変わっていくかもしれませんが、今のところこの現実は否定できないでしょう。
HTTP 経由の SOAP ではオーバーヘッドが生じます。
考慮する 1 つの点は、
データがサーバー上転送された後に何が行われるかということです。
データに属性を付けて、そのデータを SQL データベースにアーカイブしますか。
この場合には、サーバー側で別のコードが必要になります。
他の転送手法を使用することを計画している場合は、
どこに接続し、そのアカウントを使用し、どこでそのファイルを削除するかを、
ユーザーはどのようにして知ればよいでしょうか。
この種の問題が持ち上がると、
最も高速なアップロード手法に関連付けられたその他のコストの存在がより明確になります。
このような場合には、適切な転送先への大量データのルーチング扱うツールを利用できます。
(あつかましいようですが、ここで Microsoft® BizTalk? Server を宣伝させてください)。
Web サービスに直接大量のデータ オブジェクトを送信するときに取り除いておく点は、
そのデータを使って何を行うかが明確にわかっているコード ロジックにデータを手渡しすることです。
設計パターン
では、大量データの設計対象に関する問題を解決し、
大量データ ブロックを送受信するのに XML Web サービスが適切な方法であると決定したと仮定しましょう。
ここでは、何を行えばよいでしょうか。
大量データの転送には 2、3 の基本的なアプローチがあります。
大量データをバイトのバッファとして渡すことができます。
あるいは、より効果的なメカニズムに転送の負荷を下げることができます。
データ バッファ
これは、結果的には Web サービス メソッドのパラメータの 1 つに、
バイトの配列の形式で何も加工しないデータを渡すことになります。
一般的には、別のパラメータの 1 つでそのバッファの大きさに関する情報を提供するでしょう。
これは最も容易なアプローチですが、
危険がないわけではありません。
Web サービスのコンシューマの観点からは、
送信されるブロックの最大サイズは実際にはわかりません。
受け取るであろうあまり根拠のない最大サイズを設定しておかないと、
実行時にメモリが不足したり、
コンピュータの仮想メモリが消費されるにつれて、
パフォーマンスはどんどん低下していくことになるでしょう。
サーバーの観点からは、
メモリが不足する危険性はそんなに高くはありませんが、
ファイルの任意の最大サイズを設定しておく必要はあります。
これを設定しておかないと、
自分自身で過度に大きなファイルが原因でサービス拒否攻撃に陥る可能性があります。
その他の危険性として、顧客がデータ バッファのサイズを超えるデータを提供すると、
注意深く処理していないと、システムがクラッシュしたり、
セキュリティの問題が生じる可能性があります。
パラメータの任意の最大サイズに関しては、
.NET Framework を使って最大サイズを設定するためのヒントを挙げておきます。.
Visual Studio .NET Beta 2 に同梱されているバージョンの .NET Framework では、
Web サービスの SOAP メッセージの最大サイズは 4 MB に制限されています。
Web サービスの Web.Config ファイルの httpRuntime セクションで、
maxRequestLength 設定を変更することによって、
この最大サイズを増加できます。
以下の例では、maxRequestLength が 8096 KB に設定されています。
<configuration>
<system.web>
<httpRuntime maxRequestLength="8096"
useFullyQualifiedRedirectUrl="true"
executionTimeout="45"/>
</system.web>
</configuration>
"1 つの大きなバッファ" シナリオには、バリエーションがあります。
ここで考える 1 つの戦略は、ColdStorage で採用したアプローチです。
このアプローチでは、
アップロードおよびダウンロードする大量データを固定サイズの小さなチャンクに分割することです。
この戦略には、次のようにいくつか利点があります。
- 各メソッド呼び出しは、固定最大量のメモリを使用します。
- システム リソースが、長時間、1 つの任意の呼び出しに占有されません。
代わりに、1 つの大きな要求を小さな要求に分割することにより、
別の小さな要求がサービスを受けられるようになります。
サービスを受ける要求の合計の全体的なスループットは向上します。
- エラー復旧のメカニズムを提供します。
配信中にいずれかの個別のチャンクが失敗した場合は、
そのチャンクだけを再送信できます。
- サーバー ファームのシナリオでより適切なスケーラビリティを提供します。
おそらく、利用度が低いハードウェアを適切に使用して、
利用可能な任意のサーバーが着信する要求をサービスできます。
このアプローチには、次のような欠点もあります。
- サーバーとの接続を確立するために別の処理時間が必要になります。
1 つの大きなバッファを使ったアプローチでは、
接続を閉じずに保持できます。
- Web サービスのコンシューマでは、
アップロードとダウンロードを管理するためにやや処理が必要になります。
- 非常に大量の転送では、
小さな転送が数多く発生し、長い遅延に悩まされる可能性があります。
大多数の転送がほぼ同じ量のデータを持っているときは、
このシナリオでもそんなに悪い結果にはなりません。
このような場合は、すべての転送が均一に遅延されることになるでしょう。
考慮できるもう 1 つの選択肢は、
サーバーにアップロードする前、
または Web サービスのコンシューマにダウンロードする前にデータを圧縮することです。
当然、この戦略は Web サービスの有用性を制限します。
つまり、サービスのコンシューマはデータの圧縮に使用されている手法を知る必要があり、
ファイルを圧縮および圧縮解除するために必要なソフトウェアにアクセスできる必要があります。
転送負荷の低減
このアプローチは、
W3C SOAP with Attachments
仕様で取り組まれた概念の 1 つのバリエーションです。
つまり、SOAP メッセージ内でファイルの実際のバイトを送信するのではなく、
ダウンロードするファイルの URL を送信します。
URL の受信者は、SOAP 外部で独立した形式でその URL にバインドし、
データをダウンロードします。
このアプローチはダウンロードでは機能しますが、
インターネット上で HTTP サーバーからこの Web サービスを呼び出していない場合は、
データのアップロードは不可能です。
Web サービスはバインドしようとしている URL を解決できないでしょう。
また、以下の手順に従って 2 段階で転送を行えば、アップロードが可能になります。
- クライアントがファイルのアップロードを要求する We サービスを呼び出します。
- Web サービスは、アップロードする場所、
使用するプロトコルに関する情報、
およびログオンのクレデンシャルを応答します。
- Web サービスのコンテキストの外部で、
指定されたクレデンシャルを使ってその場所にログオンし、
指定されたプロトコルを使って転送を完了します。
- 転送が完了するときに、
Web サービスがそのファイルを適切にルーティングします。
転送が完了したことを通知するために、
サービスがその場所で動作状況を監視するか、
UploadComplete メソッドを呼び出すことを要求することもできます。
特定のサーバーにログオンし、
アクセスが制限された場所にファイルを配置することを指示されれば、
このアプローチは適切に機能するでしょう。
その他のハイブリッド アプローチ
既存の SOAP 標準に完全には準拠しないというテーマでは、
その他のバリエーションが存在します。
たとえば、以前チャット グループで話題になったメソッドで、
接続する TCP/IP アドレスとソケットを Web サービスに送信するというのがあります。
その後のデータの転送は TCP/IP レベルで行われるので、
パフォーマンスが劇的に向上します。
このアプローチの欠点は、Web サービスのリソースを拘束し、
クライアント側での信頼を必要とすることです。
主な転送は HTTP プロトコルの外部で行われるので、
特別な構成を行わないとファイアウォール経由では簡単には機能しません。
もう 1 つバリエーションとして、
サーバー対サーバー環境で作業している場合は、
Web サービス呼び出しのパラメータの 1 つとして IStream ポインタを渡せる可能性があります。
そのポインタの受信者は、
一度に大量のデータ ブロックを転送するのではなく、
ストリームに対して読み書きを行うメソッドを呼び出せます。
この手法の難点は、
サーバー対一般クライアント モデルでは機能しないであろうということです。
この種の通信では、
クライアントはその IStream ポインタでの Web サービス呼び出しを表現する SOAP 要求を受け入れることができる必要があります。
一般的には、
このハイブリッド アプローチでは、パフォーマンスはそれほど劇的には向上しません。
ファイル内のすべてのバイトがあるサーバーから別のサーバーにマーシャリングされるときに、
依然としてそのファイル内のすべてのバイトがエンコーディングされます。
ただし、受け取るデータのボリュームは制御可能になります。
最終的に、.NET Framework を使用して利用できる別のソリューションが存在します。
Web サービスとクライアントの両方を制御している場合は、
Framework が提供する .NET Remoting と Channels Services を使用できます。
クライアントとサーバー間の通信は、
ファイアウォールに別ポートを開く必要なしに、
TCP と同程度の低レベルで行われます。
.NET Remoting を使用すると、
より高いパフォーマンスを実現でき、
その他の高度な機能にアクセスできます。
この形式のデータ転送の交換条件は、オープンな標準を使用しないことです。
.NET Framework 専用のデータ転送です。
まとめ
XML Web サービス内で大量データを扱う場合は、
容易にすべてに答えることはできない多くの疑問を生じます。
SOAP サポートが成長していくにつれて、
大量データを扱うことに関するパフォーマンスの問題の一部はうまくいけば解決されるでしょう。
当面の間は、試みることができる多くの異なるアプローチが存在します。
純粋な SOAP 実装から逸脱することを選択すれば、選択肢は広がります。
理想的には、
Web サービスとそのクライアント間で、
最も効果的なアップロードおよびダウンロード メカニズムをネゴシエートする標準化された方法が存在することです。
今のところ、現実には 2 つの選択肢しかありません。
1 つは、多少のパフォーマンスの低下を受け入れて、
SOAP 標準の方法で大量データを転送することです。
もう 1 つは、独自の手法を考案し、
この記事で説明した選択肢の 1 つのような何かを試みることです。
At Your Service
Allen Wagner は MSDN Architectural Samples チームのメンバで、
ColdStorage サンプルに関する新しい記事を書いています。
Allen が仕事をしていないときは、
彼が最新式の減光スイッチを設置した後、
息子の部屋の配線が焦げ、オゾン臭がするようになった原因を突き止めようと必死で考えています。