TRMIのアーキテクチャ

TRMIは, Java言語で分散システムを開発する際に, アプリケーションロジックと分散処理のためのコードを独立して開発することを可能とするシステムである. TRMIを用いると, スタンドアロンのソフトウェアを, それとは別に開発した分散処理部品と組み合わせることにより, 分散型のソフトウェアに発展させることができるようになる.

アプリケーションロジックと分散処理を分離して開発する際には, アプリケーションロジックから分散処理が透過的に使用できることが望ましい. アプリケーションロジックから分散処理を意識したコーディングをしなければいけないようであれば, 両者を分離したとしても, その効果が半減してしまう. TRMIを用いると, アプリケーションロジック中の各々のオブジェクトには分散システムであることを意識したコードを組み込むことなく, 分散化させることができる. 即ち, クライアントであるオブジェクトは, 別のJava仮想マシン(JVM)上のサーバのメソッドを, あたかも同一のJVM上にそのサーバが存在するかのように呼び出すことが可能になる. しかも, クライアントやサーバには, 他の分散オブジェクト技術では必要であった, 分散処理のための特別のコードを追加する必要がない.

TRMIにおいてアプリケーションロジックと組み合わせることのできる部品には,dispatcher, receptor, exception handler, scheduler および factoryがある.

ネットワーク処理は, dispatcherreceptorと呼ばれる2つの部品により処理される. Dispatcherオブジェクトは, クライアント側の部品であり receptorオブジェクトはサーバ側の部品である.Dispatcherreceptorは, ネットワークに関する処理を全て担当する. Dispatcherreceptorが通信する手順は, これらのオブジェクト間のみで決められており, 他のオブジェクトからは隠蔽されている. 従って, dispatcherreceptorをペアで入れ換えることにより, 任意の通信プロトコルを使用できるようになる. なお, TRMIが標準で使用するプロトコルはJava RMIである.

exception handlerオブジェクトは, サーバのメソッドをネットワーク化されたマルチスレッド環境で実行する際に発生する例外を処理する機能を持つ. もとのスタンドアロンのアプリケーションロジックは, 通常, 分散処理に関連する例外を処理する機能は持っていない. exception handlerは, これらの例外を実行時に捕捉し, アプリケーションロジックの手を煩わすことなく処理する. あるいは, アプリケーションロジックが処理可能な例外へと変換してアプリケーションロジックに渡すなどの処理を行う.

schedulerオブジェクトは, サーバのメソッドを同時に実行する複数のスレッドの同期制御を行う役割を持っている. TRMIを用いると, 1つのサーバを複数のクライアントから同時アクセスすることが容易に可能となる. それは, シングルスレッド環境用に設計されたアプリケーションロジックが, 複数の計算機から構成されるマルチスレッド環境で実行されることに他ならない. 複数のクライアントによる同時アクセスは, 何らかの競合状態を発生させる場合がある. scheduler オブジェクトは, 複数のクライアントからの同時アクセスにより発生する複数のスレッドの同期制御を行うことにより, サーバのメソッドが安全に実行できるようにする役割を持つ.

Factoryオブジェクトは, 分散環境におけるサーバオブジェクトの生成や配置の機能を持つ. もとのスタンドアロンのアプリケーションロジックは, サーバとクライアントが同一のホスト上で実行されることを前提としている場合がほとんどである. また, サーバとクライアントは共に1つずつ存在することを仮定している場合も多い. しかし, TRMIを使用することにより, サーバやクライアントは, 以上のような位置的あるいは数量的な制約から解放される. サーバとクライアントは, 異るホスト上に存在したとしても, それらのホストがネットワークで接続されていれば問題ない. 複数のサーバやクライアントが複数のホスト上に存在し, お互いに連携しあって共通の処理を実現する場合もある. サーバは, クライアントが開始される前に生成される場合もあるし, クライアントからの要求に従って生成されることもある. サーバは, クライアントからの要求に従って, あるいは, 自分の判断で, 他のホストへ移動するかもしれない. いずれの場合にしても, サーバの位置はクライアントの位置により制約を受けることはない. Factory オブジェクトは, サーバを生成するホストを決定し, そのホスト上にサーバを生成する.

分散化の形式

スタンドアロンシステムを分散システム化すると言っても, 様々な方式が考えられる. TRMIの分散システムへの変換の方式は, 基本的に2つに分類できる. 第1の方式は, 図2に示すように, スタンドアロンプログラムとして正しく動作するシステムのオブジェクトを分散処理部品と組み合わせてネットワーク経由で別の計算機からアクセスできるようにすることにより, 元のシステムと等価な分散システムを開発する方式である. 言わば, もともと一体のシステムをネットワークを用いて複数の計算機上に分割して協調動作させる方式である. この方式を分離型と呼ぶ. 図2は, 分散処理部品と組み合わされたスタンドアロンのサーバYが, クライアントXからネットワーク経由でアクセスできるように分散化される様子を表している.

図2:分離型の分散化

第2の方式は, 逆に統合型と呼ぶ. この方式では, 図3に示すように, まず開発対象の分散システムをいくつかのスタンドアロンのサブシステムとして開発する. そして, それらのサブシステム中のオブジェクトを分散化して複数のサブシステムに共有させ, サブシステムが協調動作できるように統合する方式である. 図3は, オブジェクトYをアクセスする2つのサブシステムが, Yが分散化されることにより統合される様子を表している.

図3:統合型の分散化

上記の2つは, ひとつのオブジェクトを分散化する場合を例として示しているが, 複雑なシステムにおいては, ひとつのオブジェクトをネットワーク経由でアクセスできるようにするだけでは不十分で, システム中の複数のオブジェクトを同時に分散化させる必要が出てくる. その際には, 各オブジェクトのシステム中での役割や位置づけに応じて, 分散化の方式を決定する必要がある. 従って, システム全体としては, 分離型あるいは統合型を組み合わせた方式となる.

なお, 現在のTRMIでは, 分離型あるいは統合型のどちらを用いて分散システムを構築するかは, 開発者に任せている. これは, factoryオブジェクトを用いた配備機能により制御できる.

TRMIの分散化手法

Java RMIなどのような既存の分散オブジェクトフレームワークでは, スタブとスケルトンと呼ばれるオブジェクトが, クライアントがサーバのメソッドをネットワーク経由で呼び出す際に, メソッド呼び出しを中継する機能を有していた. RMIなどの既存の方式の問題点は, これらのスタブやスケルトンといったオブジェクトを, クライアントやサーバが直接アクセスしなければならない点である. そのため, スタンドアロンのアプリケーションロジックを分散化しようとすると, どうしても, スタンドアロンの場合は必要がなかったスタブやスケルトンへのアクセスを行うコードの追加や, それに伴う他の部分の変更が発生してしまう.

TRMIでもRMIなどの既存の分散オブジェクト技術と同様, TRMIスタブとTRMIスケルトンが存在する. TRMI では, スタンドアロンのアプリケーションロジックをdispatcher , receptor, exception handler, schedulerおよびfactory といった部品と組み合わせて使用することにより, 分散オブジェクト化する. クライアントおよびサーバと, これらの部品を透過的に結合させる役割を果たしているのが, TRMIスタブとTRMIスケルトンである.

図4:TRMI を用いた分散システムのアーキテクチャ

図4にTRMIを用いて開発した分散システムのアーキテクチャを示す. TRMIはプロキシパターンに基づいている. 一般に, プロキシとは, サーバと同一の外部インタフェースを持つオブジェクトである. 即ち, サーバのメソッドと同じ名前のメソッドを持ち, それらのメソッドの引数の型も, サーバの同名のメソッドと同一である. これらのメソッドを代理メソッドと呼ぶ. クライアントは, プロキシの代理メソッドをサーバのメソッドと思ってアクセスする. 代理メソッドの基本機能は, クライアントからのサーバのメソッド呼び出し要求をサーバに中継(委譲)し, その実行結果をクライアントへ返すことである. しかし, 代理メソッドでは, サーバのメソッドを呼び出す直前と, 実行終了直後に独自の処理を追加して行なうことが可能である. これにより, サーバとクライアント間にプロキシを挿入することにより, サーバに無かった様々な機能を追加することができる.

TRMIスタブはクライアント側のプロキシで TRMIスケルトンはサーバ側のプロキシである. TRMIスタブとTRMIスケルトンはtrmicと呼ばれるTRMIが提供するツールによりサーバのソースコードあるいはバイトコードから自動生成される.

透過的リモートメソッド呼び出し

クライアントがサーバのメソッドを呼び出すと, 代わりにTRMIスタブの代理メソッドが呼び出される. TRMIスタブの代理メソッドは, dispatcherに対してTRMI スケルトンの代理メソッドを呼び出すように依頼する. Dispatcherは, receptorを経由してTRMI スケルトンのメソッドを呼び出す.

さらに, サーバ側では, TRMI スケルトンがschedulerのメソッドを呼び出す. schedulerもサーバのプロキシであり, サーバの代理メソッドを持つ. schedulerの代理メソッドを実行するスレッドと, それが呼び出すサーバのメソッドを実行するスレッドは同一である. 従って, schedulerの代理メソッドを実行するスレッドを制御することにより, サーバのメソッドを実行するスレッドを制御することができる.

最も単純なスレッド制御は, 代理メソッドをすべてsynchronizedメソッドとして, 逐次実行することである. それ以外にも, FIFOの順に実行したり, 完全に並列に実行したりといった制御が, それに応じたschedulerを記述することで可能となる.

サーバのメソッドをネットワーク経由で実行する際に, ネットワークで問題が発生する可能性がある. 発生した例外は, dispatcherにより捕捉され, exception handlerへ送られる. exception handlerは, これらの例外を, アプリケーションロジックの手を煩わすことなく処理したり, アプリケーションロジックが処理可能な例外へと変換してアプリケーションロジックに渡すなどの処理を行う.

配置制御

クライアントがサーバ, 正確にはサーバクラスのインスタンス, を生成しようとした場合でも, 実際に生成されるのは, TRMIスタブのインスタンスとなる. TRMI スタブのコンストラクタは, factoryに対して, サーバを生成するように要求を出す. Factoryは, receptordispatcherを経由して, TRMIスケルトンに対して, サーバを生成するように要求する.

サーバを生成する要求を受けとるホストを決定するのも, factoryの役割である. Factoryが全く独立して自分で判断しても良いし, TRMIスケルトンに相談して決定することもできる. 相談を受けたTRMIスケルトンは, schedulerに判断を委譲する.従って, 適切なschedulerを定義しておけば, 自由にサーバを生成するホストの位置を制御することができる.

例えば, 統合の形でシステムを開発する際には, 統合対象のサブシステムの内部では個別に生成していたサーバを, システム全体で1つだけ生成する形に変更する必要がある. その場合には, サーバ生成要求は, 最初の要求で実際にサーバを生成し, それ以後の要求では, サーバを新たには生成せずに, 既存のサーバの参照を返すといった処理をfactoryに行わせることにより, 実現できる. なお, 分離型でシステムを開発する際に, 1つのサーバに対して複数のクライアントのアクセスを許すような場合でも, 同様な処理がfactoryで必要となる.

また, 行列計算のような科学技術計算を行うようなプログラムには, 同一の計算処理を異るデータに対して複数回行い, その結果を統合して最終的な計算結果とするものが存在する. このようなプログラムでは, 計算処理を一つのオブジェクトに行わせるように記述しておき, そのオブジェクトを複数生成して同時に実行させるような形で記述すれば, メモリ共有型のマルチプロセッサシステムでは効率良く実行することができる. そのようなプログラムを, TRMI を用いて分散化し, 各オブジェクトを別のホスト上に配置するようなfactoryオブジェクトと結合すると, グリッド化することができる. すると, システムの拡張性を格段に改善することができる.

部品の開発

TRMIでは, スタンドアロンのアプリケーションロジックと組み合わせて使用することのできる部品をユーザが自由に開発できる. しかし, 完全に自由に開発していたのでは, 部品間の整合性が取ることも難しい. 特に, TRMIスタブやスケルトンとの整合性の確保が重要である. また, 多くの部品に共通な処理も存在するため, それらをいつも個別に開発していたのでは効率が悪い. そこで, TRMIでは, 標準の部品を自動生成し, そのサブクラスとして, ユーザが自分自身の部品を定義できるような方式を採用した.

trmic は, TRMIスタブとスケルトンに加えて, 標準のexception handler, schedulerおよびfactory を自動生成する. これらを, それぞれ, super exception handler, super schedulerおよびsuper factoryと呼ぶ. 例えば, 標準のschedulerでは, すべての代理メソッドは, サーバのメソッドを逐次呼び出しをするような形で実装されている. ユーザがこれを取りやめ, 自分自身でスレッドの同期制御を行いたい場合には, ユーザのschedulerの代理メソッド中で, サーバのメソッドを呼ぶ前後に必要なスレッドの同期制御の処理を行うことにより, これが実現できる.

また, 標準のexception handlerでは, リモートメソッド呼び出しに起因する例外を, クライアントがもともと処理可能な例外へと変換する. 例外の対応付けは, 標準のexception handlertrmicを用いて生成する際に, trmicのGUIを用いて行う. ユーザのexception handlerは, 例外を対応づけるだけではなく, exception handler内部で処理してしまって, クライアントへは知らせないなどの方式で, 実装することもできる.

さらに, これらの標準の部品は, 標準的な機能を持つばかりでなく, ユーザの部品で使用できるような機能を用意している. 例えば, 標準のfactoryでは, サーバを作成するメソッドや既存のインスタンスを削除するメソッド, 各サーバホストの負荷を計算するメソッドなどが用意されており, これらを用いることにより, ユーザが容易に自分のfactoryを定義できる.

また, trmicはユーザが自分で記述する部品の骨格となるコードを自動生成する処理も行う. 骨格となるコードには, 各部品が空の代理メソッドを持つ形で記述されている. これにより, ユーザが自分のexception handler, schedulerおよびfactoryを記述する際には, 白紙の状態から記述を始めるのではなく, trmicが生成するユーザ部品の骨格コードの代理メソッドに本体処理を追加記述するのみで, 自分の部品が作成できる.

trmicのカスタマイズ

trmic自身をカスタマイズして, 自動生成する部品を変更することも可能である. trmicは, 部品を生成する時に, テンプレートとなるファイルを読み込み, それを分散化処理の対象となっているクラスに応じて書き換える形で, 部品を自動生成する. 従って, このテンプレートファイルを交換することにより, 生成する部品を全く独自のものに変更することが可能となる.

サブクラスによるカスタマイズでは, サーバクラスごとの部品のカスタマイズが可能である. 一方, 通信プロトコルの変更などのように, すべてのクラスに共通な変更が発生する場合もあり, クラスごとに個別にサブクラスを定義していたのでは, 手間がかかる. そのような場合, trmicを変更して, 一括して生成する部品を変更することができる.