EIP / Case Study Bond Pricing System


Case Study: Bond Pricing System

一言要約

ワイが実際に経験したEIP実例を紹介するで。

要約

膨大なパターンやパターン言語から遠ざかるのはたやすい。パターンは再利用な形でアイデアを抽象化する。多くの場合、パターンは包括的性質として便利にしてくれる一方理解するのが難しくなる。パターンを理解するのに最適なのは現実の世界の例である。起こりうる不自然なものでなく、実際に起こるか将来起こるシナリオである。

この章では発見プロセスを使って問題を解決するためにパターンを適用する。これから議論するシステムは、筆者が初期設計から本番まで2年間携わった債券取引システムである。これからシナリオと遭遇した問題、どのようにパターンを用いて解決するかを見てみる。これはパターン選択の決定プロセスを含み、システムのニーズにあわせてパターンを組み合わさて適合する方法も含む。そしてこれはビジネス要件やクライアントの決定、アーキテクチャや技術要件、レガシーシステムの統合など実際のシステムで遭遇したことも考慮に入れる。このアプローチの目的は実用的なアプリケーションを通じてパターン自身の明確な理解を提供することである。


システムの構築

ある大きなウォール街の投資銀行は、債券トレーディングデスクの業務フローを効率化するために債券価格決定システムを構築することを立案する。現在、債券トレーダーは様々な異なる取引市場でそれぞれ独自のインターフェースを持つ大量の債券を価格を送信する必要がある。システムの目的は、単一の隠蔽化されたユーザーインターフェースで債券市場に高度な分析機能を組み合わせた全ての債券価格の細部を最小限に抑えることである。これは様々な通信プロトコルを超えて様々なコンポーネント間の統合とやりとりを意味する。システムの高レベルのフローは以下のようになる。

BTHighLevelFlow.gif

まず、市場データがシステムに入ってくる。市場データは、自由市場において売買したい債券の価格やその他の情報に関するデータである。市場データは即座に分析エンジンに送信されデータを変更する。分析は金融アプリケーション用の数学関数を参照し、債券の価格や他情報を変更する。これらは関数結果を特定の債券に合わせるために入力変数を使う一般的な関数である。各トレーダーのデスクトップで動くクライアントアプリケーションは分析エンジンを各トレーダーごとに構成し、トレーダーが価格設定する各債券用に分析の詳細を制御する。分析が市場データに適用されると、変更されたデータは各取引市場に送り出され、他会社からのトレーダーは債券を売買できる。

パターンを用いたアーキテクチャ

このシステムの業務フロー概要では、設計プロセス中に発生するいくつかのアーキテクチャ問題に近づくことができる。これまでにしているものを見ていこう。トレーダーはWindows NTやSolarisワークステーションの両方で動くとても応答性が速いアプリケーションを求めている。よってプラットフォームに依存せずユーザ入力や市場データに迅速に応答できることからJavaシッククライアントとしてクライアントアプリケーションを実装することにした。サーバーサイドは我々のシステムで利用しているレガシーC++コンポーネントを継承する。市場データコンポーネントはTIBCO Information Bus(TIB)メッセージングインフラストラクチャと通信する。我々は以下のコンポーネントを継承している。

  • 市場データ価格フィードサーバ: 入ってくる市場データをTIBにpublishする
  • 分析エンジン: 入ってくる市場データを分析し、変更された市場データをTIBにブロードキャストする
  • コントリビューションサーバ: 取引市場と全ての通信を担う。取引市場は銀行にてコントロールされないサードパーティのコンポーネント。
BTLegacyMarketData.gif
BTLegacyContribution.gif

我々は別々のサブシステム(Javaシッククライアント、市場データ、コントリビューション)が通信する方法を決める必要がある。シッククライアントとレガシーサーバとを直接通信するが、クライアント上にあまりに多くのビジネスロジックが必要になる。代わりに、レガシーサーバと通信するJavaゲートウェイを構築する。マーケットデータ用のPricing Gatewayと取引市場に価格を送信するContribution Gateway。これはこれらの分野に関係するビジネスロジックの良いカプセル化を実現する。システムの現在のコンポーネントをいかに示す。"???"とマークされた接続はまだコンポーネントが通信する方法が分からないことを示している。

BTSystemAllComponents.gif

最初の通信に関する質問は、Javaシッククライアントと2つのJavaサーバコンポーネントとをデータ交換するために統合する方法である。この本で提案されている4つの統合スタイルを見ていこう。File TransferShared DatabaseRemote Procedure InvocationMessaging。我々はクライアントとデータベース間に抽象レイヤを作りたく、クライアントにデータベースアクセスコードを持ちたくないのでShared Databaseは除外できる。取引市場に送り出される現在価格を確認するために最小限のレイテンシの必要があり、File Transferも同様に除外される。残るはRemote Procedure InvocationMessaging

JavaはRemote Procedure InvocationMessaging両方のサポートを提供している。RPCスタイルの当方はRemote Method Invocation(RMI)、CORBA、Enterprise Java Beans(EJB)を使って行われる。Java Messaging Service(JMS)はメッセージングスタイル統合の共通APIである。よって両方の統合スタイルはJavaで実装しやすい。

ではRemote Procedure InvocationMessaging、どちらが今回のプロジェクトにとって良いか?システムに1つのPricing Gatewayインスタンスと1つのContribution Gatewayインスタンスがあるが、通常多くのシッククライアントがこれらのサービスに同時に接続する(各債券トレーダーは特定時間にログインする)。さらに銀行はこのシステムを他アプリケーションでも利用できるよう汎用的な価格システムにしたい。よって不定数のシッククライアントがある一方、価格をゲートウェイ外に送る他アプリケーションが不定数ある。

シッククライアント(または価格データを使う他アプリケーション)は価格データを取得するためにゲートウェイを呼び出し処理を起動するために極めて簡単にPRCを使うことができる。しかしながら、価格データは常に公開され、特定クライアントは特定データのみ興味があるので、タイムリーに関連データを適切なクライアントに届けるのは難しい。クライアントがゲートウェイをポーリングすることもできるがオーバーヘッドが大きい。ゲートウェイは、クライアントができるだけすぐにデータを得られるようにするのが良い。しかし、クライアントが現在アクティブであるかや、どの特定データが欲しいのかを追跡するために各ゲートウェイを必要とする。新しいデータが利用可能になる(1秒間に何回も起きる)と、ゲートウェイは関心のあるクライアントにデータを渡すためにRPCを作成する必要がある。理想的には全クライアントに同時に通知されるべきなので、PRCは自身の並行スレッドで行う必要がある。これで上手く行くが、とても複雑になる(心の声:very fastって何?)。

Messagingはこの問題を非常にシンプルにする。Messagingでは、価格データの種類ごとに別々のチャネルを定義できる。ゲートウェイが新しいデータ片を得ると、そのデータ種類用のPublish-Subscribe Channelに、そのデータを含むメッセージを追加する。一方、特定のデータ種類に関心がある全クライアントはその種類のチャネルをlistenする。このように、ゲートウェイはどれだけのリスナーアプリケーションがあるか、そのアプリケーションが何なのかは知る必要がなく、関心のあるならだれでも新しいデータを簡単に送り出すことができる。

クライアントはまだゲートウェイ内で振る舞いを呼び出すことができるようにする必要がある。メソッドが同期的に呼び出される間クライアントは遮断でき、これらのクライアント-ゲートウェイ間の呼び出しはRPCを使ってかなり簡単に実装できる。しかし、ゲートウェイ-クライアント間の通信にメッセージを既に使っていると、メッセージはおそらく、同様にクライアント-ゲートウェイ間通信を実装する良い方法になる。

よって、ゲートウェイとクライアント間の全通信はメッセージを介して達成される。全コンポーネントはJavaで書かれているので、JMSはメッセージングシステムとして簡単な選択肢を提示する。これによりMessage Busまたは将来のシステムが現在のシステムとメッセージングインフラストラクチャへの変更無し或いは少しの変更で統合できるようなアーキテクチャを効率的に作成できる。このように、アプリケーションのビジネス機能を銀行が開発する他アプリケーションによって簡単に使うことができる。

BTJMSJavaComponents.gif

JMSは単に仕様であり、JMS準拠のメッセージングシステムを決める必要がある。我々はIBM MQSeries JMSを使うことに決定した。なぜならその銀行がWebSphere?アプリケーションサーバや多くのIBM製品を使っている「IBMショップ」だからだ。結果として、適所にサポートインフラがあり、製品のサイトライセンスも持ってるためMQSeriesを利用する。

次の質問はどうやってMQSeriesメッセージングシステムをスタンドアロンのC++ コントリビューションサーバやTIBCOベースの市場データと分析エンジンサーバとを接続するかである。MQSeriesコンシューマがTIBメッセージにアクセスする方法が必要である。でもどうやって?おそらくMessage Translatorパターンを使ってTIBメッセージをMQSeriesメッセージに変換することができる。しかしMQSeriesのC++クライアントがMessage Translatorとして動くと、JMSサーバの独立性が犠牲となる。また、TIBCOはJava APIを持っているものの、顧客アーキテクトやマネージャはそれを拒否している(心の声:なんでや!)。その結果、Message Translatorのアプローチは放棄せざるを得ない。

TIBサーバからMQSeriesサーバへのブリッジはC++とJava間の通信を必要とする。我々はCORBAを使えたが、その後のメッセージングについてはどうする?Message Translatorパターンを良く見ると通信プロトコルが利用するChannel Adapterに関係していることが分かる。Channel Adapterの肝は非メッセージングシステムをメッセージングシステムに接続することである。2つのメッセージングシステムを接続するチャネルアダプタのペアはいわゆるMessaging Bridgeである。

Messaging Bridgeの目的はあるメッセージングシステムから別のメッセージングシステムにメッセージを転送することである。これはまさにJavaからC++へのイントラ言語間通信の複雑さを追加しようとしていることである。我々はChannel AdapterとCORBAの組み合わせを利用して言語間Messaging Bridgeを実装できる。2つの軽量Channel Adapterサーバを構築する。1つはTIBとの通信を管理するC++、もう一つはJMSとの通信を管理するJava。これらそれぞれ自身のMessage Endpointsである2つのChannel Adapterは、CORBAを介して互いに通信を行う。我々が選択したMQSeriesでは、それが会社の標準であることからJNIでなくCORBAを利用するだろう。メッセージングブリッジは、一見互換性のないメッセージングシステムや異なる言語間の効率的なメッセージ変換を実装する。

BTChannelAdapterMessageTranslator.gif

次の図はゲートウェイと他コンポーネントを含む現在のシステム設計を示している。これはパターンアプリケーションの良い例である。Message Translatorパターンを実装するために非メッセージングプロトコルを持った2つのChannel Adapterを組み合わせ、1つのパターンを効率的に使って別のパターンを実装した。さらに、Channel Adapterのコンテキストを、メッセージングシステムから非メッセージングシステムに接続するのではなく非メッセージングの言語間変換プロトコルを用いて2つのメッセージングシステムにリンクするよう変更した。

BTChannelAdapterCurrentSystem.gif

担当者のつぶやき

みんなの突っ込み