ヘッダをスキップ
Oracle® WebLogic Communication Services 開発者ガイド
11g リリース 1 (11.1.1)
B55506-01
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

4 SIP アプリケーションの要件とベスト プラクティス

この章では、OWLCS にデプロイするアプリケーションを開発するための要件とベスト プラクティスについて説明します。以下の節で構成されています。

4.1 Oracle Communications Converged Application Server の分散型アプリケーションの開発の概要

典型的なプロダクション環境では、SIP アプリケーションはエンジン層クラスタを形成する OWLCS インスタンスのクラスタにデプロイされます。SIP データ層内のサーバのクラスタは、アクティブな呼び出しについての呼状態のレプリケートされたインメモリ データベースを提供します。この環境でアプリケーションを確実に機能させるには、以下の節に書かれているプログラミングの作法と慣行に従い、デプロイ後のアプリケーションの複数のコピーがクラスタ環境で期待どおりに動作するようにしてください。

旧バージョンの OWLCS のアプリケーションから移植しようとしている場合、以下で述べる規約や制約の多くは馴染みがない可能性があります。その理由は、2.0 および 2.1 のバージョンの WebLogic SIP Server 実装ではクラスタ化をサポートしていなかったからです。アプリケーションを移植したら徹底的なテストとプロファイリングを行って問題を洗い出し、新しい環境で満足な結果が得られるようにしてください。

4.2 アプリケーションではスレッドを作成しない

OWLCS はマルチスレッド アプリケーション サーバであり、ホストしているモジュールについてリソースの割り当て、同時実行性、およびスレッドの同期化を慎重に管理します。OWLCS アーキテクチャを最大限に生かすには、SIP サーブレット および Java EE API の仕様に従ってアプリケーションのモジュールを構築してください。

SIP サーブレットなどのサーバサイド モジュール内に新たなスレッドを作成するようなアプリケーション設計は避けてください。

4.3 サーブレットは非ブロッキングでなければならない

SIP および HTTP サーブレットは、メソッドが呼び出されるとき呼状態がロックされた状態になるので、SIP メソッドの本体でスレッドをブロックしないようにする必要があります。たとえば、サーブレット メソッドが SIP サーブレット コンテナに制御を返す前にデータの取得や書き込みを積極的に待機するような設計は避けてください。

4.4 すべてのアプリケーション データをセッションに格納する

アプリケーションを複数のエンジン層サーバ (レプリケートされた OWLCS コンフィグレーション内) にデプロイする場合は、すべてのアプリケーション データをセッション属性としてセッションに格納する必要があります。レプリケートされたコンフィグレーションでは、エンジン層サーバはキャッシュされた情報を保持しないので、すべてのアプリケーションを SIP データ層サーバにあるセッション属性からデシリアライズする必要があります。

4.5 すべてのセッション データがシリアライズ可能でなければならない

SIP アプリケーション呼状態のインメモリ レプリケーションをサポートするためには、SIP サーブレット セッションに格納されるオブジェクトをすべてシリアライズ可能にする必要があります。オブジェクトがシリアライズ可能とみなされるには、オブジェクトのすべてのフィールドがシリアライズ可能か一時的なフィールドである必要があります。サーブレットでシリアライズ可能なオブジェクトとシリアライズ不可能なオブジェクトを組み合わせて使用した場合、OWLCS はシリアライズ不可能なオブジェクトのセッション ステートをレプリケートすることができません。

4.6 setAttribute() を使って「No-Call」Scope のセッション データを変更する

SIP サーブレット コンテナは、SIP サーブレットの doxxx メソッドを呼び出す時、関連する呼び出し状態が自動的にロックされます。しかし、アプリケーションは、「No-Call」 Scope のセッション データを変更する場合もあります。No-call scope は、通常の doxxx メソッドの範囲外で呼び出し状態データが変更されたコンテキストを参照します。たとえば、HTTP サーブレットが SIP セッション データを変更しようとする場合、またはサーブレットを呼び出す前にコンテナがロックした呼状態以外の呼状態を SIP サーブレットが変更しようとする場合、データは no-call scope に変更されます。

アプリケーションは常に、SIP セッションの setAttribute メソッドを使用して no-call scope の属性を変更する必要があります。同様に、セッション オブジェクトから属性を削除するには、removeAttribute を使用してください。セッションデータを更新するために setAttribute/removeAttribute が使用されるたびに、SIP サーブレット コンテナは関連する呼状態のロックを取得および解除します。(メソッドは、更新するオブジェクトを待ち行列化させ、直ちに制御を 返します。)これにより、1 回に 1 つのアプリケーションだけがデータを変更し、クラスタの SIP データ層ノード間で変更がレプリケートされることが確実になります。

その他の set メソッドを使ってセッションの内部でオブジェクトを変更した場合、OWLCS はその変更をレプリケートできません。

OWLCS コンテナは、setAttribute を呼び出した後に加えられた変更を呼状態に維持しません。たとえば、次のコード サンプルでは、setAttribute を呼び出すと呼状態が直ちに変更されますが、続いて modifyState() を呼び出すと、呼状態が変更されません。

  Foo foo = new Foo(..);
  appSession.setAttribute("name", foo); // これは呼状態を保持します。  foo.modifyState(); // この変更は保持されません。

その代わりに、次のように呼状態属性の値を変更してからsetAttribute を呼び出すようにしてください。

  Foo foo = new Foo(..);
  foo.modifyState();
  appSession.setAttribute("name", foo);

また、SIP サーブレット コンテナには、それぞれの setAttribute の呼び出しに対して呼状態がロックされるという点にも留意してください。たとえば、HTTP サーブレットで次のコードを実行する時、SIP サーブレット コンテナは呼状態のロックを 2 回ずつ取得して解除します。

appSess.setAttribute("foo1", "bar2");
appSess.setAttribute("foo2", "bar2");

このようにロックすると、1 つのスレッドだけが常に呼状態を変更することが確実になります。しかし、他のプロセスは順次更新の間に呼状態を変更することができます。次のコードは、no-call 状態を行なった場合、スレッド セーフと見なされません。

Integer oldValue = appSession.getAttribute("counter");
Integer newValue = incrementCounter(oldValue);
appSession.setAttribute("counter", newValue);

上記のコードをスレッドセーフ にするには、wlssAppSession.doAction メソッドを使用して囲む必要があります。これにより、呼状態へのすべての変更が、次のように単一のトランザクション ロック内で行われます。

wlssAppSession.doAction(new WlssAction() {
       public Object run() throws Exception {
         Integer oldValue = appSession.getAttribute("counter");
         Integer newValue = incrementCounter(oldValue);
         appSession.setAttribute("counter", newValue);
         return null;
       }
     });

最後に、呼び出しの呼び出し状態は doInvite() などの「doSipMethod」で呼をロックした場合、デッドロック状況を回避するようにしてください。doSipMethod の手順が実行されると、OWLCS コンテナは、すでに呼び出し状態をロックしていることに注意してください。アプリケーション コードがメッソド内からの現在の呼状態にアクセスしようとすると、(たとえば、データ構造や属性に保存されているセッションへのアクセス)、ロックの発注結果はデッドロックになります。

例 4-1 は、デッドロックとなる例を示しています。コンテナによって callAppSession に関連付けられた呼のコードが実行されると、ロックの順が逆転して getApplicationSession(callId) とのセッションを取得しようとするとデッドロックの原因になります。

例 4-1 デッドロックを引き起こすセッション アクセス

WlssSipApplicationSession confAppSession = (WlssSipApplicationSession) appSession;
confAppSession.doAction(new WlssAction() {  
  // confAppSession is locked
  public Object run() throws Exception {
    String callIds = confAppSession.getAttribute("callIds");
    for (each callId in callIds) {
      callAppSess = Session.getApplicationSession(callId); 
      // callAppSession is locked
      attributeStr += callAppSess.getAttribute("someattrib");
    }
    confAppSession.setAttribute("attrib", attributeStr);
  }
}

com.bea.wcp.sip.WlssAction インタフェースの使用については、節 6.3.1「SipApplicationSession の変更」を参照してください。

4.7 send() 呼び出しがバッファされる

SIP サーブレットが doInvite()doAck()doNotify() などの SIP リクエスト メソッド内で send() メソッドを呼び出す場合は、OWLCS コンテナによってすべての send() 呼び出しがバッファされ、SIP リクエスト メソッドの復帰後にそれらが順に転送されるという点に注意してください。send() 呼び出しが即座に転送されることを前提にアプリケーションを設計しないでください。


警告 :

リクエストや応答は制御が SIP サーブレット コンテナに返るまで送信されないので、send() を呼び出した後でアプリケーションが待機したりスリープしたりしないようにする必要があります。

4.8 SIP サーブレットを配布可能としてマークする

SIP サーブレットをクラスタ環境にデプロイすることを前提として設計およびプログラムした場合は、アプリケーションをエンジン層サーバのクラスタにデプロイするときに、サーブレットのデプロイメント記述子に distributable (配布可能) マーカー要素を入れる必要があります。distributable 要素を省略すると、OWLCS はそのサーブレットをエンジン層サーバのクラスタにデプロイしません。sip.xml で distributable をマークした場合は、WAR ファイルの web.xml でも同様にマークする必要があります。

distributable 要素は必須ではなく、単一の組み合わせ層 (レプリケートされない) OWLCS インスタンスにデプロイする場合は無視されます。

4.9 SipApplicationSessionActivationListener を慎重に使用する

SIP サーブレット 1.1 仕様は、SIP セッションがアクティブ化されるかパッシベーションされる場合アプリケーションにコールバックを提供する SipApplicationSessionActivationListener について説明します。レプリケートされた OWLCS デプロイメントのみにコールバックが発生することに注意してください。単一サーバ デプロイメントは SIP データ層を使用しません。そのため SIP セッションはパッシベーションされません。

レプリケートされたデプロイメント OWLCS は、セッションに対して SIP メッセージが処理される前後に SIP Session を何度もアクティブ化し、パッシベーションします。(RDBMS ベースの永続性がコンフィグレーションされない場合でも、通常、どのレプリケートされたデプロイメントにおいてもこれは発生します。)アクティブ化およびパッシベーションのこの定数サイクルは、頻繁なコールバックになるため、アプリケーションで SipApplicationSessionActivationListener の使用を控えます。

4.10 セッションの有効期限のベスト プラクティス

JSR289 アプリケーションでは、コンテナでのセッションの削除がより「インテリジェント」に行われます。たとえば、セッションまたは sipappsession に対し、invalidate() を明示的に呼び出す必要はありません。

ただし、セッションで setExpirs() が使用され、アプリケーションが JRS289 型である場合は、セッションで setInvalidateWhenReat(false) を呼び出さない限り、この呼び出しの効果はありません。

4.11 Java EE アプリケーションのベスト プラクティスに従う

他の Java EE API を使用したアプリケーションをデプロイする場合は、それらの API の基本的なクラスタ化ガイドラインに従ってください。たとえば EJB をデプロイする場合は、すべてのメソッドを多重呼び出し不変として設計し、デプロイメント記述子の中で EJB ホームをクラスタ対応として指定してください。詳細については、「Clustering Best Practices」を参照してください。