ヘッダーをスキップ
Oracle® WebLogic Server SIP Container開発者ガイド
11g リリース1(11.1.1)
B61430-01
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

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

この章では、Oracle WebLogic Server SIP Containerにデプロイするアプリケーションを開発するための要件とベスト・プラクティスについて説明します。内容は次のとおりです。

4.1 分散型アプリケーションの開発の概要

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

旧バージョンのOracle WebLogic Server SIP Containerのアプリケーションを移植しようとしている場合、次に説明する規約や制約の多くは馴染みのないものかもしれません。というのも、以前のWebLogic Server実装ではクラスタリングをサポートしていなかったからです。アプリケーションを移植したら徹底的なテストとプロファイリングを行って問題を洗い出し、新しい環境で満足な結果が得られるようにしてください。

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

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

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

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

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

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

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

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

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

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メソッドを使ってセッションの内部でオブジェクトを変更した場合、Oracle WebLogic Server SIP Containerはその変更をレプリケートできません。

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

  Foo foo = new Foo(..);
  appSession.setAttribute("name", foo); // This persists the call state.
  foo.modifyState(); // This change is not persisted.

そのかわりに、次のように呼出し状態属性の値を変更してから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の手順が実行されると、Oracle WebLogic Server SIP Containerコンテナは、すでに呼出し状態をロックしていることに注意してください。アプリケーション・コードがメソッド内からの現在の呼出し状態にアクセスしようとすると、(たとえば、データ構造や属性に保存されているセッションへのアクセス)、ロックの発注結果はデッドロックになります。

例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()メソッドを呼び出す場合は、Oracle WebLogic Server SIP Containerコンテナによってすべてのsend()呼出しがバッファされ、SIPリクエスト・メソッドの復帰にそれらが順に転送されるという点に注意してください。send()呼出しが即座に転送されることを前提にアプリケーションを設計しないでください。


警告:

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

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

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

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

4.9 SipApplicationSessionActivationListenerを慎重に使用する

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

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

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

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

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

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

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