SOA(サービス指向アーキテクチャ)の概念が普及するにつれ,前提となる技術的基盤であるWebサービスのインタフェースを持つシステムが増えてきた。一般的には「在庫を照会する」「入金処理を行う」などの単位で一つのサービスにすることが多い。Webサービスは,既に提供されているサービスを組み合わせてアプリケーションを構築できるという手軽さがあるが,作り方を間違えると性能や信頼性の低いシステムが出来上がってしまう。その典型の一つがこれだ。「同一サーバー内のWebサービス呼び出しをしてはいけない」。

 説明を簡単にするために,図1に示す単純なアーキテクチャで稼働するシステムを想定しよう。なお,記載している製品名はあくまで例であり,各分野におけるリファレンス実装もしくはデファクト・スタンダードなものだ。読者の得意な製品に置き換えて読み進めてほしい。

図1●想定するシステムのアーキテクチャ
図1●想定するシステムのアーキテクチャ
  • アプリケーションはServletとして実装する
  • ServletエンジンとしてApache Tomcatを利用する
  • SOAPエンジンとしてApache Axisを利用する
  • WebサーバーとしてApacheを利用する。ApacheとTomcatの間はmod_jkによるajp13(Apache JServプロトコル バージョン1.3)で接続する
  • DBMSはDBサーバー上で稼働し,O/Rマッピング・ツールを利用してDBサーバーと接続する

 この構成の上で,在庫管理システムが稼働しており,在庫管理システム上で以下の2つのサービスが存在することとする。

サービスA:商品名を検索条件とし,商品コード一覧を取得する
サービスB:商品コードを入力とし,商品の在庫を照会する

 ここで,他システムからの要件により,以下の機能を持つサービスを新規開発することになった。

サービスX:商品名を検索条件に,商品の在庫一覧を取得する

 アプリケーション開発者は,違和感なく以下のような設計をしてしまうかもしれない(図2)。

図2●サービスXの実装方法の例
図2●サービスXの実装方法の例

(1)入力された商品名を基に,サービスAの呼び出しを行う
(2)サービスAからの応答を基に,サービスBの呼び出しを行う
(3)サービスBの応答をクライアントに返す

 これでサービスXは問題なく動くように,一見,見える。しかし,このような実装をしてしまうと,在庫管理サーバーの性能設計が格段に難しくなってしまうのである。

多重度設計の切り口で考える

 性能設計における重要な要素の一つに,多重度設計(流量設計とも呼ぶ)がある。突発的に大量の処理要求が来てもシステム全体が輻輳しないように,実行多重度を制限するような設計である。データ・アクセス層の処理(DBへの検索,更新処理など)はトランスポート層(HTTP処理などのシステムの外側)での処理に比べてCPU負荷が高いため,一般的にはシステムの外側(トランスポート層)から内側(データアクセス層)に行くにしたがって多重度を小さくする(図3)。

図3●多重度設計の例
図3●多重度設計の例

 こうすることで,各層間でキューイングの効果が得られ,突発的な高負荷時にビジーでエラー応答することを防ぐ効果が期待できる。図3の例では,Servletスレッド数とDBコネクションプール数は「同一」,Apacheスレッド数は「Servletスレッド数+5」というルールを設けている。

 本来,外側から内側に行くに従って小さくしていくのが,多重度設計である。サービスがそれぞれ独立している限りそのセオリーに従って設計すればよいのだが,サーバー内部からのサービス呼び出しを許すと,多重度設計は一気に難しくなる。

 サービスXが外部から呼び出されると,サービスAとサービスBをシーケンシャルに呼び出す。サービスXが10多重で呼び出された場合,内部呼出用に10多重(A)を保証しなければならない。サーバー全体として外部に保証すべき多重度が10(B)だとした場合,A+Bで合計20多重でServletスレッドの上限を設計する必要がある。Apacheのスレッド数は余裕を持たせるためにさらに増やして,25多重とする。

 ここでやっかいな問題が起こる。外部提供用に10スレッド,内部呼出用に10スレッドを別々に確保できなければ正常に動作しないのだが,Apacheではサービスごとに異なる多重度を設定することができない。外部から25の接続を来た分だけ受け付けてしまう。結果として,内部呼び出し分のスレッドまで使い果たし,処理が輻輳する可能性が出てきてしまうのである。

 技術的な対策として,以下のような例が考えられる。

1.サーバー外部で流量制御する
外部からの流量制御をするために別のハードウエアを導入する。
例)在庫管理サーバーの前にロード・バランサを導入して外部からのコネクション数を制限する。

2.サーバー内に内部呼び出し専用の入り口を設ける
例1)Apacheを別ポートでもう一つ起動し,内部呼び出し用に利用する。
例2)TomcatのHTTPポートを内部呼び出し用に利用する。

 いったん内部呼び出しを許可してしまうと,アプリケーションの実装によってどういう呼び出し方(内部呼び出しの回数,サービスごとのトランザクションミックス)をされるか分からない。事実上,多重度設計は困難を極める。その結果,あるサービスが多く呼ばれたときは他サービスが使えないという事象に陥りやすくなる。

 たかがサービスを一つ追加するだけにもかかわらず,コスト面,性能設計面で,いきなりハードルは高くなることが分かるだろう。このようにコストをかけたり,面倒な設定をしなければならなくなるため,内部呼び出しは基本的にはやるべきではない。そもそもサービスXは在庫管理システム側で提供すべきサービスなのかというところから考え直さなければならないのである。


武田則幸
野村総合研究所
基盤サービス事業本部 システム基盤統括二部
 ベンダー系SIerで通信業者向けシステム開発に従事した後,98年にNRI入社。情報セキュリティ事業に携わった後,2002年より証券系基幹業務システムの基盤方式設計を担当。2005年社内ITアーキテクトに認定