近年、SOAは巨大な進歩を遂げてきました。それは、ソフトウェアに熱中している人による実験的な実装から、今日のITのメインストリームへと移りました。その発展の背後にいる主要な原動力の一つは、サービスインターフェースの後ろにある既存の企業のIT資産を合理化し仮想化する力にあります。そして、それはエンタープライズビジネスモデルと、現在と将来のエンタープライズプロセスに大きく協調するものです。さらに、SOAの発展は、サービス基盤の仮想化のパターンである、エンタープライズサービスバスによって達成されました。それは、メディエーション、サービスロケーションの解決、サービスレベルの合意などを活用しています。ESBは、ソフトウェアアーキテクトがサービス基盤を非常に単純なものにすることを可能にします。包括的なSOAの実装で欠けている最後のピースが、エンタープライズデータアクセスです。この問題に対する可能な解決法は、エンタープライズデータバス(エンタープライズデータをどこからでもアクセスするためのパターン)で、参考[1,2]で紹介されています。EDBは、SOAの仮想化に3次元の考えを追加します。そして、以下のように、ブレイクダウンすることができます
- サービス - IT資産の仮想化;
- ESB - 企業サービスアクセスの仮想化
- EDB - 企業データアクセスの仮想化
他のSOA開発では、いくつかの出版物(参考[3,4,5])がSOA実装でのスケーラビリティ、高可用性、スループットを改善するためにグリッド技術の利用を提案しています。本稿では、SOAアーキテクチャ全体の中でグリッドをどのように利用できるかを説明し、サービスの実装におけるグリッド活用のためのプログラミングモデルを紹介します。さらに、ここで要求されたアーキテクチャをサポートすることのできる、経験から得たグリッドの実装も紹介します。
EDBを用いたSOA - アーキテクチャ全体
[1,2]では、EDBを用いたSOAのアーキテクチャ全体が図1のように表わされています。
図1: エンタープライズデータバスとSOAアーキテクチャ
ここでは、ESBはサービスの適切な呼び出しに対して責任があります。それは、サービスが要求している全てのエンタープライズデータ [1] にアクセスするためにEDBを利用することで実装されます。このアーキテクチャには、次のメリットがあります。
- サービス機能(ビジネスロジック)の実装とエンタープライズデータのアクセスロジックの関心事の明確な分離
エンタープライズデータバスは、抽象レイヤーを効果的に作ります。そして、エンタープライズデータアクセスの詳細を隠蔽し、サービスの実装に「標準化されたインターフェース」を提供します。 - EDBは、サービスによって使用されるエンタープライズのセマンティックなデータモデル[2]と、エンタープライズデータへのすべてのアクセスを隠蔽しているエンタープライズアプリケーションのデータモデル間のすべての変換に対し、単一の場所を提供します。
その結果、サービスの実装はSOAのセマンティックなモデルを使用したエンタープライズデータにアクセスすることができます。こうすることで、エンタープライズサービスの設計と実装を大きく単純化します。 - EDBによって提供された所要のエンタープライズデータへのアクセスがあるサービス実装は、サービスのインターフェースを大きく単純化することができ、サービスコンシューマとプロバイダの間を疎結合にします。
- サービス(コンシューマ)はデータ [2] に直接アクセスすることができるので、たとえば、サービスの呼び出しはその一部として送信されるパラメータ(インプット/アウトプット)の実際の値を必要としません。その結果、サービスのインターフェースは実際のデータの代わりにデータ参照(キー)として表わすことができます。
- SOA実装が成熟するにつれてエンタープライズサービスモデルが発展するので、データ参照定義の変更はほとんどないでしょう。その結果、キーのデータをベースとしたサービスインターフェースは、より安定したものとなるでしょう。
- 追加のデータを使用するためにサービス実装を拡張する際は、そのコンシューマへ影響を及ぼすことなく実装することができます。
グリッドを追加する
実装可能なEDBの一つに、WebsphereのeXtreme Scale、OracleのCoherenceデータグリッド、GigaSpacesのデータとアプリケーショングリッド、NCacheの分散データグリッドといった、グリッドの利用が挙げられます。
データグリッドは、単純なインメモリデータベースから、数千台のサーバーに拡張した強力に分散された整合性のとれたキャッシュに至るまで、ソリューションを構築するために設計されたソフトウェアシステムです。典型的なデータグリッドの実装では、データを複数のマシン全体のメモリに記憶された重複の無い塊に分割します。結果として、非常に高レベルなパフォーマンスとスケーラビリティが、標準的なプロセスを使用して得られます。複数のマシンに同じデータが複製されることで、スケーラビリティとフォールトトレランスが得られ、更新と問い合わせの並列実行(別々のデータ部が、別々のマシンで同時にアクセスされます)により、パフォーマンスが得られます。
図2は、EDB実装としてのグリッドの利用を示しています。グリッドはエンタープライズデータのインメモリの複製を保持し、それはエンタープライズデータベースとアプリケーションの状態を表します。
図2 EDBとしてのグリッド
グリッドの導入により、複数のデータベースとアプリケーションに存在するデータの再分割を可能にします。そして、それはエンタープライズのセマンティックモデルを順守します。この必然的結果は、エンタープライズに必然的に存在する正当化した重複データと共に、エンタープライズの異なるアプリケーション/データベースから、ある凝集性のあるデータ表現へと、論理的に関係のあるデータをまとめます。
グリッドの実装は、一般的に、パブリッシュ/サブスクライブのメカニズムによってサポートされます。そして、データの変更によりグリッドメモリと既存のエンタープライズアプリケーションとデータの間を同期化します。グリッドベースの仲介役は、サービスの利用に最適化されたデータモデルを使用しているエンタープライズデータへの非常に速いアクセスを可能とします。
グリッドベースのEDB(図2)は、エンタープライズデータのハイスピードなアクセスを単純化しますが、潜在的に、EDBとサービス実装の間の大きなデータ交換を必要とします。あるサービスは必要とされるすべてのデータをロードしてから、その処理を実行しなければなりません。そして、グリッドへ結果を格納します。
より良いアーキテクチャは、エンタープライズデータにより近いサービスの実行をもたらすことです。つまり、エージェント[7]の調整役としてサービスを実行し、それらはエンタープライズデータを含んだメモリ空間の中で実行されます(図3)。このケースでは、あるサービスの実装がリクエストを受け取り、1つ以上のエージェントが起動します。それらはグリッドノードのコンテキスト内で実行され、サービスの実装に結果を返します。そして、エージェントの結果を組み合わせ、サービスの実行結果を返します。
図3 エージェントの協調役としてのサービス
このアプローチは、パブリッシュ/サブスクライブのデータ交換モデルに勝る以下の利点を提供します。
- 特に、大量のデータ(メガバイトやギガバイトのデータ)を処理するときなど、全体的なサービス実行のパフォーマンスを大きく改善できるローカルデータの操作を可能にします。
- データ分割と同様に、実際の実行は複数のグリッドノード間に分割されます。したがって、そのアーキテクチャによるパフォーマンス、スケーラビリティ、可用性がより一層改善します。
- すべてのサービスが同じデータにアクセスすることができるので、サービスの実行が最小のリクエスト/リプライでデータ操作をおこなえば、データを渡す必要が全くありません。
ソフトウェアエージェント
エージェントの概念は、分散人口知能(DAI)の研究の初期に遡ります。それは、自律的かつインタラクティブで、非同期で実行するオブジェクトの概念を導入しました。このオブジェクトは、ある隠蔽された内部状態を持ち、別のよく似たオブジェクトからのメッセージに答えることができます。[7]によれば、「エージェントはソフトウェア/ハードウェアのコンポーネントであり、そのユーザーに代わってタスクを達成するために正確に動作することができます。」とあります。
[7]で分類されているものとして、エージェントにはいくつかのタイプがあります。
- 協調エージェント
- インターフェースエージェント
- モバイルエージェント
- 情報/インターネットエージェント
- 反応的エージェント
- 知的エージェント
サービス実装(図3)のアーキテクチャに基づいて、私たちは複数のカテゴリに属しているエージェントについて説明します。
- 協調 - 1つ以上のエージェントが、サービス機能を共に実行します.
- モバイル - エージェントは、サービスコンテキスト外のグリッドノード上で実行されます
- 情報 - エージェントの実行で、グリッドノードに配置されたデータを直接利用します
残りの記事で、私たちは、グリッドベースのEDBとエージェントベースのサービス実装を構築するために利用することのできる、グリッドの簡単な実装とプログラミングモデルについて議論します。
グリッドの実装
グリッド実装における非常に困難な問題の中に、高可用性、スケーラビリティ、データ/実行の分割メカニズムがあります。
グリッドの高可用性とスケーラビリティを保障するための最も簡単な方法の一つは、内部グリッド通信のメッセージングを利用することです。グリッド実装は、ポイントツーポイントとパブリッシュ/サブスクライブメッセージの両方から利点を享受することができます。
- ポイントツーポイント通信のメッセージングの使用により、プロバイダからコンシューマの分離をサポートします。リクエストは、直接プロバイダに送信されるのではなく、キューがプロバイダによって監視されます。その結果、キューイングは次のことをもたらします。
- グリッドノード数を増やすことによって透過的に増加しているスループット全体は、同じキューでリスンされます。
- スレッドの数を制御することによるグリッドノードのロードの単純な抑制は、キューでリスンします。
- ロードバランシングの簡素化。コンシューマがどのプロバイダを呼び出すかを決める代わりに、キューにリクエストを書き込みます。スレッドがリクエスト処理として利用可能になるとき、プロバイダはリクエストを取り出します。
- 透過的なフェールオーバーのサポート。同じキューでリスンしているプロセスのいくつかが終了すると、残りが取り出され、メッセージを処理し続けます。
- パブリッシュ/サブスクライブメッセージの利用により、グリッド基盤の中の「ブロードキャスト」実装の簡素化を可能にします。そのようなサポートはグリッド構成の中で変更を同期化する際に、非常に役に立つでしょう。
グリッド実装によって、データ/実行の分割アプローチは、純粋なロードバランスのポリシー(同一ノードの場合)からグリッドデータの動的なインデックス化まで及びます。このメカニズムは、グリッド実装の中にハードコードするか、特殊なグリッドサービスパーティションマネージャを具体化するかのどちらかとなるでしょう。パーティションマネージャの役割は、ノード間のグリッドデータを分割し、リクエストをルーティングするためのノード(ノードのキュー)を配置する「レジストリ」の役目をすることです。分離しているサービスの中のパーティションマネージャの具体化は、「プラガブル」なパーティションマネージャの実装か、あるいは、複数のパーティションマネージャ(異なるタイプのリクエストに対する異してルーティングメカニズムを実装しています)の利用によって、アーキテクチャ全体にさらなる柔軟性をもたらします。
パーティションマネージャとグリッドノードの通信を含んだ全体的なグリッド基盤は、グリッドのリクエスト送信の一部として利用されるAPI形式でグリッドコンシューマに直接公開されるか、特別なグリッドノード - グリッドマスター(コントローラ)のセットの中に隠蔽されるかのいずれかです。最初のケースでは、リクエスト分散の実装と、(オプションで)リプライの組み合わせに責任を負っている個別のグリッドのライブラリが、グリッドコンシューマの実装と関連していなければなりません。このオプションは、理論上、最高の全体パフォーマンスをもたらします。しかし、それは、通常グリッドの実装とそのコンシューマ [3] 間のより密な結合を作ります。第2のケースでは、グリッドマスターは、パターンのあらゆる利点とそのグリッドのためにfacadeパターン [8] を実装します。それは、グリッドコンシューマからのグリッド機能(と、インフラ)の完全な隠蔽です。グリッドマスターの実装は、さらなるネットワークホップ(とそこから生じるいくつかのパフォーマンスオーバーヘッド)を生じますが、疎結合の達成の方が一般的にはより重要です。
2つのレベル(マスター/ノード)の実装をサポートしている高レベルなグリッドアーキテクチャの全体は、図4で表わされます。
図4 グリッドの高レベルなアーキテクチャ
上述したコンポーネントに加えて、提唱したアーキテクチャ(図4)には、さらに2つのもの(グリッド管理とコードリポジトリ)を含んでいます。
グリッド管理は、グラフィカルなインタフェースを提供します。そして、現在起動しているノード、それらのロード、メモリ使用、サポートされたデータ、などを表しています。
グリッドノード/マスタの再起動は非常にコストがかかることがある [4] ので、私たちは、それらを再起動せずにグリッドマスタ/ノードに新しいコードを取り込むことができるようにしなければなりません。これは、コードリポジトリの利用によっておこなわれます。現時点では、Webで利用可能なjarの集まりとして実装されています。開発者がグリッド環境で実行したい新たなコードを実装するたびに、彼らはリポジトリにコードを格納し、実行の一部として(JavaのURLClassLoaderを使用して)それを動的にロード/呼び出します(下記参照)
プログラミングモデル
グリッド上で動いているアプリケーションの作成を単純化するために、私たちはグリッド上で実行するための、ジョブ-アイテムのプログラミングモデル(図5)を設計しました。このモデルはMap/Reduce[9]パターンの変形で、以下のように動作します。
図5 ジョブ項目のモデル
- グリッドコンシューマは、(ジョブコンテナの形式で)ジョブのリクエストをグリッドマスターに送信します。ジョブコンテナは、ジョブをインスタンス化するために必要な情報のすべてをマスター環境に提供します。これは、ジョブのコードロケーション(Javaのjar、空文字、ローカルで処理されたもの、静的にリンクされたコードのロケーション)、ジョブの起動クラス、ジョブの入力データ、ジョブのコンテキストタイプを含み、ジョブの実行を分けるための複数のパーティションマネージャからの選択を可能にします。
- グリッドマスターのランタイムは、適切なジョブコンテキスト(分割マネージャ)を通して、ジョブのクラスとコンシューマへのリプライをサポートしているリプライヤオブジェクトをインスタンス化します。一度、ジョブのオブジェクトが作成されると、ランタイムはその実行を起動します。
- ジョブ起動の実行メソッドは、ジョブをアイテムに分けるために分割マネージャを使用します。そして、それぞれは実行(マップの段階)のために特定のグリッドノードへ送信されます。
- 各々の送信先グリッドノードは、(アイテムコンテナの形式で)アイテムの実行のリクエストを受けます。そのアイテムコンテナは、ジョブコンテナに類似していて、アイテムをインスタンス化して実行するためのグリッドノードへの十分な情報を提供します。これには、アイテムのコードロケーション、アイテムの起動クラス、アイテムの入力データ、アイテムのコンテキストタイプを含みます。
- グリッドノードのランタイムはアイテムのクラスをインスタンス化し、適切なアイテムコンテキストや、元のジョブへ戻るのをサポートしているリプライヤオブジェクトを渡します。一度、そのアイテムオブジェクトが作られると、ランタイムはその実行を開始します。
- アイテムの実行は、ジョブに部分的な結果を返すためにリプライオブジェクトを使用します。これにより、それらが利用可能になるとすぐに、ジョブ実装がアイテムの部分的な結果(reduceの段階)の処理を開始することができるようになります。必要であれば、さらにアイテムが作られ、この処理の間にグリッドノードに送信することができます。
- ジョブは、それらが利用可能になると、部分的な結果をコンシューマに送信するためにリプライヤを使用することができます。
実行の全体は、以下のようになります。(図6)
図6 ジョブ項目の実行
グリッドマスターとノードに対する実行の詳細は、図7で表わされます。
図7 実行の詳細
Map/Reduce パターンを実装することに加えて、このプログラミングモデルは、すべてのレベルで完全に非同期なデータ配信をサポートします。これは、ジョブのコンシューマが部分的なリプライを使用するときに、全体的なパフォーマンスを大きく改善することができるだけでなく、メッセージ(メッセージの塊) [5] のサイズを制限することによって、システム全体のスケーラビリティやスループットを改善することもできます(例:部分的な情報をブラウザに配信する)。
グリッドを結びつける
ジョブ呼び出しのメカニズムとしてのジョブコンテナの利用によって、ジョブをグリッド [6] に送信するための標準的なインターフェースも可能にします(図8)。私たちは、このWebサービスのインターフェースに対し、invokeJobRawとinvokeJobXMLの機能的に全く同じ2つのメソッドを提供します。
図8 GridJobServiceのWSDL
両方のメソッドは、グリッド上のジョブの呼び出しを可能にします。最初のアプローチは、バイナリにシリアライズされたJobContainerクラスを渡すためにMTOMを使用し、2つめはJobContainerのすべての要素についてXMLのマーシャリングをサポートします(図5)。 JobContainerに加えて、両方のメソッドは、2つの追加パラメータをグリッドに渡します。
- リクエストハンドルは、リクエストを一意的に識別し、リクエストとリプライを一致させるためにコンシューマによって利用されます(後で説明します)。
- リプライURL - どのコンシューマがリプライをリスンしているかのURLです。このURLは、GridJobServiceRepliesサービスを公開しなければなりません(図9)。
図9 グリッドジョブサービスがWSDLを返す
グリッドマスターの実装
グリッドマスターのクラス図は、図10で表わされます。上述した基本的なジョブのランタイムを実装することに加えて、マスターのソフトウェアとしてスレッド [7] 、リクエスト/レスポンスの整合性、リクエストのタイムアウト、などを含む基本的なフレームワークの機能も実装します。
アイテム実行のための、リクエスト/並列のリプライパラダイムに対応するために、「待ちながらリプライを得る」(メッセージングを使用する際の一般的なパターン)のではなく、私たちは単一リスナーを使用し、独自のリプライ整合メカニズムを構築することを決断しました。最終的に、私たちはタイムアウトのメカニズムを実装し、対象ジョブが、(ジョブコンテナの中で定義された)事前定義されたデータの中のすべてのアイテムから、「最初の」リプライを得ることを保証しています。
図10 グリッドマスターの実装
グリッドノードの実装
グリッドノードのクラス図は、図11で表わされます。マスターのランタイムと同様に、ここで、私たちはスレッド、実行タイムアウト、などを含むフレームワークのサポートで基本的なアイテムの実行を補完します。
図11 グリッドノードの実装
常に実行しているアイテムによってノードリソースが滞留することをさけるために、私たちは、アイテムの実行時間に基づいた、アイテムを追いたてるポリシーを実装しました。(アイテムコンテナの中で)通知された時間よりも長く実行しているアイテムの実行は終了されて、ジョブに対してタイムアウト例外が送信されます。
グリッドコンシューマフレームワーク
私たちは、コンシューマの実装もおこないました。単純なJavaAPI(図12)と共にWebサービス(図8、図9)をラップし、組み込みのJetty Webサーバーを利用して、ジョブリクエストをグリッドに送信し、受け取ったリプライに対してコールバックをすることができます。
図12 グリッドコンシューマ
結論
EDB の導入は、サービスの実装からエンタープライズデータまでの「標準化された」アクセスを導入することにより、アーキテクトがSOAの実装をさらに単純化することができるようになります。それは、サービス呼び出しと実行モデルの両方を単純化し、サービスのさらなる分離をもたらします。EDB実装のためにグリッドを使用することで、EDBのスケーラビリティや高可用性に対応します。最終的に、グリッド内で直接実行するサービスエージェントの利用により、スケーラビリティやパフォーマンスを大きく改善します。本稿で説明したグリッドの高レベルなアーキテクチャとプログラミングモデルは、それらの実装に対して、単純でありながら堅牢な基盤を提供します。
謝辞
Navteqの同僚、特に、グリッドとそのプログラミングモデルの実装の議論や支援をしてくれたMichael Frey、Daniel Rolf、Jeffrey Herrに感謝します。
参考
1. B. Lublinsky、http://www.infoq.com/articles/SOA-enterprise-data">Incorporating Enterprise Data into SOA。2006年11月、InfoQ。
2. Mike Rosen、Boris Lublinsky、Kevin Smith、 Mark Balcer、 Applied SOA: : Service-Oriented Architecture and Design Strategies (リンク) (2008年Wiley出版、ISBN: 978-0-470-22365-9)
3. Art Sedighi. Enterprise SOA Meets Grid (リンク) (2006年6月)
4. David Chappell and David Berry. SOA - Ready for Primetime: The Next-Generation, Grid-Enabled Service-Oriented Architecture (リンク). (SOAマガジン、2007年9月)
5. David Chappell. Next Generation Grid Enabled SOA (PDF).
6. データグリッド (リンク)
7. Hyacinth S. Nwana. ソフトウェアエージェント:概要 (リンク)
8. ファサードパターン (リンク)
9. Map Reduce (リンク)
[1] エンタープライズデータのリソースは、データベースか既存のエンタープライズアプリケーションとなります。その結果、EDBは、データベースアクセスと、既存のエンタープライズアプリケーション/システムと共にサービスのデータの同期化している統合レイヤーの両方として実装されます。
[2] この規則の例外は、最終的なサービスクライアントかもしれません。たとえば、サーブレットは、ブラウザでサービスの実行結果をユーザーに配信します。
[3] この場合の高レベルな結合は、大きく2つの理由によります。初めに、グリッドの特定のコードがグリッドのコンシューマの実装の中で直接実行され、それがコードのすべての変更に対して、コンシューマの再構築/再起動を要求するからです。次に、この場合のコンシューマは、グリッドノードの通信に使用されるネットワークプロトコルを直接サポートする必要があるからです。
[4] キャッシュされたデータの量のために
[5] メッセージチャンキング(塊)の利用は、大きなメッセージを扱うための「標準的な」技術です。それにより巨大なメッセージ送信をさけることで、直前のメッセージ処理に必要なメモリ量とネットワークの待ち時間の両方を軽減することができます。
[6] (図8)で示したWebサービスのインターフェースは同期インターフェースですが、ジョブ呼び出しは非同期です。その結果は、ジョブの受信が完了した後でなく、ジョブのstartExecucution メソッドの呼び出しの後でジョブコンシューマに返されます。このケースでの同期(リクエスト/リプライ)呼び出しの利用は、ジョブの初期化とジョブコンシューマの起動の間のすべての例外を配信することができます。
[7] 多くのメッセージングソリューションは、スレッドを直接サポートします。一般的に、すべてのメッセージリスナーは、それ自身のスレッドから起動(そして、実行)します。その結果、多くの場合、メッセージリスナーの量の制御が、ジョブの実行スレッドの制御を可能にします。不運にも、このサポートはメッセージングの実装とは異なります。結果として、私たちはメッセージングのスレッドを利用することを決断するのではなく、単一のリスナーを利用して自身のスレッドプールをつくります。
原文はこちらです:http://www.infoq.com/articles/lublinsky-soa-grid
(このArticleは2008年12月11日に原文が掲載されました)