概要
JSR 208で定められるJava Business Integration(JBI)は、Enterprise Service Bus(ESB:ミドルウェアの連携基盤)とその相互作用についての仕様です。それら相互作用は、情報交換をおこなうためにソフトウェアバス(ESBのようなソフトウェアを仲介するソフトウェア)へプラグインされるコンポーネントに関して記述されています。その構造からすると、全てのパーツが同一プロセスあるいは同一のバーチャルマシン上に存在するシステムになるように思えます。しかしオープンソースのJBI実装であるOpenESBでは、ひとつの GlassFish Application Server上のJBIインスタンスをクラスタ化した均質なクラスタ形態をサポートしています。これによりクラスタのインスタンス数を増やすことでスケーラビリティと負荷分散を確保できます。そして、最近出てきたProxy Bindingというコンポーネントを使うと、バスをネットワーク全体に拡張したかのように、均質でないクラスタ形態でもOpenESBインスタンスをリンクさせることができます。これからOpenESB環境で用いられるこの2つの分散形態について、それぞれの長所短所を説明し、最終的に両者を補完し合うようにする方法をご紹介します。
はじめに
JBI 仕様は単一のJava Virtual Machine(JVM)に制限されたものだと思われがちです。しかしこの仕様では分散したJBIがどのように機能すべきかを明示してはいません。つまり胸躍る新しい領域の探索を妨げるものではないのです。実際、2つの異なるシステム形態(このシステム形態・構造を今回トポロジと呼びます)がJBIの承認後に登場しました。どちらの場合でも、高レベルでの管理機能において少しばかりの拡張を、低レベルな情報フックにおいてもある程度軽微な拡張をおこなうことだけ必要でした。そのような変更だけで、他のJBIを使ったシステムと同様に、この相異なるトポロジをほぼ透過的に利用できるようになったのです。
以降の章の流れは次のようになります。まず図で2つの異なるトポロジとその両方を組み合わせたトポロジを示します。そして各トポロジについて個別に詳細を説明し、トポロジを決定する上で種々のJBIコンポーネントの具体的実装法がどう関わるかを説明します。最も重要なのは、2つのトポロジそれぞれが有益であるものの、両者を組み合わせるとメリットがさらに大きくなるということを理解してもらうことです。その中で、この方法をベースにしたコンポーネントが総合的な機能面でどれほど恩恵をもたらすかも明らかにしていきましょう。
トポロジの概要
まず2つのトポロジについて例を挙げ、それから2つを組み合わせた形態の例を挙げましょう。この2つのトポロジは歴史的な経緯から均質と不均質(homogeneousとheterogeneous)と呼ばれます。その実例をGlassFish環境で動くOpenESBを使って挙げていきましょう。
均質トポロジ
均質トポロジの例は、その名前が示すように、同質なJBIコンテンツをもつOpenESBインスタンスから成るトポロジとなります。
図1:均質トポロジ
不均質トポロジ
不均質トポロジの例は、その名前が示すように、異なりうるJBIコンテンツをもつOpenESBインスタンスから成るトポロジとなります。基本的なアプリケーションフローは同じで、HTTPリクエストがBPELプロセスを起動してレスポンスを返します。このトポロジはProxy Binding(図中の「PB」)という特別なコンポーネントにより実現します。
図2:不均質トポロジ
合成トポロジ
この例は先の2つの例を混合したもので、重複しないサービスをもったJBIインスタンスが現れます。
図3:合成トポロジ
OpenESBトポロジの仕様
どのトポロジを選ぶかを決める要因は多くあります。OpenESBの場合、その初期の実装で均質トポロジが用いられていました。その時はGlassFish をデフォルトのホスト環境としていて、GlassFishの性能を生かすのによかったからです。しかし不均質トポロジについても最初のプロトタイプがありました。そのプロトタイプは現在のOpenESBでも利用できます。実装された順番は問題ではなく、どちらもそれぞれ実用的ですし、一緒に使えばお互いを補完しあうことができます。
均質なトポロジ
均質なトポロジでは、同質なJBIコンテンツをもつOpenESBが生成されます。そのJBIコンテンツには、複合的アプリケーションを構成するコンポーネント、サービスアセンブリ(構成物)、設定情報の集合が含まれます。これらJBIインスタンスは基底にあるGlassFishのクラスタインスタンスにマッピングされ、必要に応じて生成・破棄や開始・停止をおこなうことができます。またGlassFishクラスタインスタンスは単一のOSイメージをもつ各マシン上に一つあるいは複数生成することができます。このような柔軟性によってCPUリソースを有効活用したり、Web用によく用いられるマルチスレッド化されたプロセッサの性能を引き出すことができます。新たに生成されたインスタンスや、クラスタに変更があった時点において稼働していなかったインスタンスは、クラスタ全体の設定をもつ中央管理サーバ(CAS)に従って自身の設定を起動時に同期させます。このようにして全てのクラスタインスタンスが同様に機能するようになっています。
スケーラビリティ
このタイプのトポロジは大量の入力を受けるWeb向けサービスのようなシステムを水平スケーリング(複数のシステムによってスケーリングすること)するのに向いています。その際の一番の利点は負荷の変化に簡単に順応できることです。加えて、GlassFishが持っているソフトウェアロードバランサがクラスタで使えることもWebでの用途を助けます。
管理
GlassFish アプリケーションサーバではこのトポロジがデフォルトでサポートされています。またOpenESBにはCASの管理ツールがあり、設定変更をローカルに保存してその後で変更をアクティブなインスタンスに反映させることができます。これにより特定のインスタンスあるいはインスタンスグループ、または全てのインスタンスに対して、というように操作の対象を変えてJBIの管理をおこなうことができます。厳密に均質なトポロジというのはあまり求められることはありませんが、このような利用法は典型的なものの一つです。
例の説明
上で示した均質なトポロジの例は、単純な2つのインスタンスから成るクラスタです。それぞれのクラスタインスタンスはWeb向けのHTTPバインディングコンポーネントとBPELサービスエンジンの2つのコンポーネントを持ちます。通常アプリケーションは他にも多くのコンポーネントがあります(データベースアクセス、e-mailプロトコル、場合によってはHL7やSAPのような特殊なプロトコル、など)。HTTPとBPELのコンビネーションはある程度の処理をおこなうために必要な最低限の構成です。また、このクラスタのフロントとしてソフトウェアHTTPロードバランサが置いてあります。図にはクラスタ管理サーバ(cluster admin server)も描いてあります。
ここで重要なのは次の点です。:
- 通常各クラスタインスタンスは同質なものです。ただし、同一のOSイメージかつ同一のネットワークインターフェース上で動かすような場合に、各HTTPインスタンスに違うポート番号を使わせるように設定することも可能です。
- サービスのエンドポイントはクラスタ内で重複していますが、そのスコープは各インスタンス内にとどまります。
- クラスタインスタンスの数は随時変化させることができます。この特性によりこのタイプのトポロジは水平スケーリングすることができます。クラスタインスタンスは同一な物理マシン上にあっても異なる物理マシンにあってもよく、その両方ともであっても構いません。ただ通常は物理的に同一な環境に置かれます。
不均質なトポロジ
不均質なトポロジでは互いに異なるJBIコンテンツをもったOpenESBインスタンスが作られます。このトポロジはProxy Bindingと呼ばれる特別なコンポーネントによって実現されます。Proxy Bindingを使うと、あるインスタンスのコンポーネントによってホストされるサービスを別のインスタンスのコンポーネントから利用することができるようになります。Proxy Bindingはそのような疎な関係を結ぶインスタンスのそれぞれで実行されることになります。また、クラスタ内の全てのコンポーネントは同じサービスエンドポイント名によってサービスを利用することができます。各Proxy Bindingインスタンスは、クラスタ内のインスタンスによって提供されるサービスの参照用マップを構築・管理します。Proxy Bindingのデフォルト設定では、もし複数のインスタンスが同じサービスを提供する場合、それらのインスタンスでそのサービスへのリクエストを負荷分散するように動作します。今のところ不均質なシステムは単一のシステムとして管理されるということになります。
Proxy Bindingが対処する主な事項は、アウェアネス(awareness:気付き、という意味)と伝達です。アウェアネスはProxy Bindingが自インスタンスのサービスを共有可能であることを知らせ、また同じような行動をおこなっているProxy Bindingが他にないかを探すことができるようにすることです。アウェアネスの問題が解決した後で問題になるのは、 NormalizedMessage(NM)を含むJBI MessageExchange(ME:MEとNMはメッセージヘッダを含む全体とメッセージ本体のような関係にある)をインスタンス間でどのように転送するかです。
アウェアネス
アウェアネスは長い間研究されてきた問題です。JXTAとJGropusはシステムの低レベルにおいてこれを良く実現しています。最近出た Shoal/GMSでは、JXTAやJGroupsを含む低レベル技術をカバーする高レベルなソリューションを提供しています。Shoalは強力かつ利用が簡単で、スタンドアローンで動かすこともできますし、GlassFishアプリケーションサーバのサービスとして動かすこともできます。 GlassFishアプリケーションサーバ自体もShoalをクラスタに対するアウェアネスの管理や、クラスタインスタンスでエラーがあった場合のXAトランザクション(分散環境でトランザクションをおこなうためのトランザクションモデル)での自動リカバリ機構、そしてEJBの分散状態キャッシングに利用しています。
Proxy Bindingではデフォルトのアウェアネス機構としてShoalを利用しています。このProxy Bindingのアウェアネス機構は変更が可能なように設計されています。これにより将来別のアウェアネス機構を使うことができるようになっています。
転送
Proxy Bindigでは多くの転送プロトコルを扱うことができます。デフォルトでは、Shoalを転送に使います。Shoalはpoint-to- point(1対1)、one-to-many(1対多)、one-to-all(1対全)のメッセージングを提供します。Proxy Bindingではone-to-allをサービスエンドポイントの変更に関するメッセージングに、point-to-pointをME+NMコンテンツを含んだメッセージのコンポーネント間転送に利用しています。他にも多くの転送プロトコルの利用が検討されていますが、その際にキーとなるのがパフォーマンスと信頼性です。
転送のパフォーマンスは秒当たりのメッセージ数と全スループットのバイト数で測られます。その点からいってHTTPは当然ながら候補となります。パフォーマンスは詰まるところ低レベルのTCP/UDP転送をどのように使うかによるところが大きいでしょう。またセキュリティと機密性についてはSSL/TLSによる転送が大抵の要件を満たすでしょう。基本的に、信頼性が必要とされない、あるいは転送以外で信頼性を担保する場合には大量の転送をおこなうことができます。
転送の信頼性でも同様なパフォーマンスの問題がありますが、興味深い方法としてonce-and-only-once(「同じ事は2回しない」)デリバリがあります。これは通常、永続ストレージを使った方法で実現されます。分散システムで用いられる具体例としてはメッセージ・キューがあります。メッセージ・キューの仕組みを用いれば、受け手側が利用可能になるまでメッセージを保存しておくことができ、それにより可用性の問題を表面化させないことができます。転送におけるこのような可用性は、不均質なトポロジ上にあるアプリケーションの全体的な性能を大いに向上させます。GlassFishにはJMSのメッセージ・キューの仕組みが備わっています。そのため当然ながらJMSが通常の転送の対象となります。XAトランザクションに対するアウェアネスを備える JMSを用いると、Proxy Bindingをトランザクションに加えることができます。これによりProxy Bindingの性能は遥かに向上します。さらに、JMS転送を利用することで得られる効果は、2つのコンポーネントをJMS Binding Componentですることに似ています。転送でこの方法を取り入れることはオーバヘッドを削減することにつながります。
転送レベルでの選択肢があることで、プラットフォームの性能に合わせてアプリケーションの要件を柔軟に決めることができます。ME内のQoSアノテーションに応じて転送の種類を変えることも可能です。Proxy Bindingの場合は、複数の転送を同時におこなえ、手に入れた何かしら情報に応じてどの転送を利用するかを選べるという意味を持ちます。
例の説明
上で示した不均質なトポロジの図には3つの異なるOpenESBインスタンスがあります。このトポロジでも均質なトポロジの例と同じようにアプリケーションを実装できるはずです。このトポロジで異なっているのは、Web向けのHTTPバインディングコンポーネントが一つであることと、同じサービス(epB)を実装するBPELサービスエンジンのコンポーネントが別々に2つあることです。
ここで重要なのは次の点です。:
- 各インスタンスはProxy Bindingコンポーネントを持ちます。このコンポーネントは分散アウェアネスを管理し、インスタンス間のメッセージングを透過的におこなえるようにします。
- Instance- 1のNMR(Normalized Message Router)はエンドポイントepBへのメッセージをルーティングしますが、epBはInstance-2のものとInstance-3のものがあります。デフォルトでは、NMRは利用可能なインスタンス間で負荷分散をさせます。そのためルーティング先はアクティブなMEの数が一番少ないインスタンスになります。
- 不均質なクラスタでのインスタンスの配置箇所はさまざまです。同一のOSイメージに置くことも、クラスタの端と端に置くことも、任意のインスタンス間に置くこともできます。
合成トポロジ
先に図を示した合成トポロジでは均質なトポロジと不均質なトポロジが混ざり合っています。まずWeb向けのインスタンスからなるクラスタから見ていきましょう。このクラスタのフロントにはロードバランサがあります。それぞれのクラスタインスタンスは不均質な分散システムを構成していて、どちらも第3のインスタンスと接続しています。
ここで重要なのは次の点です。:
- 均質なトポロジと不均質なトポロジは合成できます。そこでProxy Bindingコンポーネントはグルーピングをおこないます。理論的には、ひとつのインスタンスが複数のグループに属することができます(ですが、きちんとテストはされていません)。
- 合成トポロジを選ぶ理由はさまざまです。サードパーティ製ソフトウェアのライセンス制限、レガシーシステムのアクセス、読み込み負荷の軽減、コンポーネントのアーキテクチャ的な制約(たとえばクラスタでは性能が落ちる、など)、物理的に離れた場所にある、などが考えられます。
- BPELリソースへのHTTPリクエストを受けたときNMRのルーティング先の候補は、ローカルのBPELインスタンスとリモートのBPELインスタンスの2つがあります。デフォルトでは、ローカルのインスタンスの方が選択されます。この選択はProxy Bindingコンポーネントを関与させないで決めることができます。もし何かの理由でローカルのBPELが停止した時は、残っているインスタンス(つまりリモート先のインスタンス)にリクエストが中継されます。
コンポーネントの特質
全てのコンポーネントは内部コンポーネント間メッセージを送受信するためにESBを使うことになりますが、 Normalized Message Router(NMR)はそのESBの機能のひとつです。NMRの役割はコンポーネント間でメッセージを素早く交換することです。MEは完了または停止のいずれかを実行しますが、この仕組み自体は永続化や修復をおこなうように設計されてはいません。しかしXAトランザクションの情報をMEが格納することで、MEのアクションをトランザクション管理することができるのです。このようにOpenESBで使うことのできるコンポーネントの多くが中間層を持ち、コンポーネント自体の特性の他にもさまざまなシステム的特性を追加することができるようになっています。その中でも信頼性はもっとも重要な特質です。そして信頼性の中でも、ユニークID、再試行、重複の検出、トランザクション処理は最も関心を集める事柄です。
ほとんどのコンポーネントはこのうちのユニークID、再試行、重複の検出を組み合わせて使うことでat-least-once(「少なくとも1回」)メッセージングをサポートしています。メッセージングに失敗した場合は、レスポンスが返ってくるまで、あるいは失敗が閾値に達するまで再試行をおこないます。ユニークIDはMEにアタッチされて受け側のコンポーネントを発見したり重複リクエストをしないように用いられます。そしてこれら一連のアクションが at-least-onceのサービスレベルを持つことになるのです。
一部のコンポーネントはトランザクション処理をサポートします。よくあるのは、その実装法がためにコンポーネントが永続化の特質を持ち、さらにXAトランザクションをサポートすることで、副作用的にトランザクション処理が可能になっているケースです。トランザクション処理ができると、2つのコンポーネントにまたがるMEのアクションでもトランザクション管理ができます。複数のMEを単一トランザクションで扱い、かつそれを複数のコンポーネントに広げることも可能ですが、トランザクションの範囲や回数が大きくなりすぎると扱いも難しくなりがちです。MEのトランザクションはonce-an-only-once のサービスレベルを持つことになります。
コンポーネントには、一元的な状態情報を共有することで異なるクラスタにある同一コンポーネントを同時に実行できるものあります。共有される状態情報は、インスタンスがエラーを起こした時に中断した処理を別のインスタンスにフェイルオーバするのに用いることもできます。このようなコンポーネントは信頼性の観点からみて最も柔軟といえるコンポーネントです。そのようなコンポーネントに分類できるものの中では、JavaEE EngineとBPEL Engineが有名です。またこの2つほどではありませんがJMS Bindingも知られています。
例
以下の図では2つのインスタンスから成るクラスタがあり、そのコンポーネントはクラスタ内で自身が実行していることに気付いるものもあれば気付いてないものもあります。
図4:コンポーネントの特質
ここで重要なのは次の点です。:
- 「XLST」はステートレスなコンポーネントで、XML文書にXSLT変換を適用します。この変換は元の文書を変更しないため再実行することができます。
- Enterprise Java Beans(「EJB」)は状態をデータベースに永続化し、その状態をメモリにキャッシュします。また複数のインスタンスからのアクセスが可能です。
- 「JMS」はファイルやデータベースといった永続ストレージにあるメッセージキューを管理します。複数のインスタンスを管理するために、クラスタ化したインスタンスは別プロセスで管理されます。
- 「BPEL」は、フローの内部状態をデータベースに保存するように設定することができます。BPELインスタンスでエラーが起きた時には別のクラスタで復旧ができます。その際、処理中のフローを参照する一連のアクションという形で処理対象が利用可能なBPELに移行されます。
- 「EJB」、「JMS」、「BPEL」はどれもXAトランザクションをサポートします。そのことで自動的におこなわれるアクションもJBI Exchangeの一部として実行することができます。たとえば、JMSキューから情報を取り出し、それをBPELエンジンに送ってフローにおける変数として保存させることをトランザクション化できます。
まとめ
このArticleの目的は、OpenESBが単一のJVM環境から分散性を備えた2つのトポロジまでをカバーできることをお見せすることでした。またその2つのトポロジが相互補完的であることも示しました。
メッセージングの品質は、単一環境より分散環境でより重要なものになります。そのベースとなるNMRはインメモリのメッセージング機構を使います。NMR上のコンポーネントは外部プロトコルを追加することになります。この外部プロトコルの中にはJMSのようにコンポーネント自体よりも信頼性を確保できる方法でコンポーネント間を接続するのに便利なものがあります。分散型の転送法としてのJMSは今回のことに関連した使い方にも向いています。また、メッセージをトランザクションの一部とする方法を使えばシステム全体の可用性を向上できます。
そして、コンポーネントが最終的な全体の機能性を向上させるキーとなりうることも示しました。設定変更可能なシステム的特性を備えるコンポーネントを用いることで、複合アプリケーションの設計者が巨大なシステム全体を扱うことができます。必ずしも大きければ良いというものではありませんが、既存システムを統合する時には特に統合先のシステムが大きな方が役立ちます。統合はJBI誕生の背景にあった最初の理由ですが、それ以外の状況においても有益であることが証明されることでしょう。
参考リンク
- JBI - http://jcp.org/en/jsr/detail?id=208 (リンク)
- OpenESB - https://open-esb.dev.java.net/ (リンク)
- GlassFish - https://glassfish.dev.java.net/ (リンク)
- Shoal/GMS - https://shoal.dev.java.net/ (リンク)
- JXTA - https://jxta.dev.java.net/ (リンク)
- JGroups - http://www.jgroups.org/javagroupsnew/docs/index.html (リンク)
- BPEL SE(Service Engine) - http://wiki.open-esb.java.net/Wiki.jsp?page=BPELSE (リンク)
- JMS BC(Binding Component) - http://wiki.open-esb.java.net/Wiki.jsp?page=JMSBC (リンク)
- Proxy BC(Binding Component) - http://wiki.open-esb.java.net/Wiki.jsp?page=FujiDJBI (リンク)
著者について
Derek Frankforth氏はSun Microsystems社のSOA/BI担当上級エンジニアで、JBIの策定やそのリファレンス実装に関わったチームの一員でもあります。また OpenESBやGlassFish ESBの開発チームにも参加し、現在はProject Fuji(OpenESBのJBIコア)に携わっています。氏はForteというIDEのコアランタイムや分散ランタイムを開発し、Forte Software社がSunに買収されたことでSunの一員となりました。その前にはIngres社のデータベースシステムを商業化した経歴があります。