akihiro kamijo: BlazeDS Archives

March 10, 2008

BlazeDS のプッシュ機能(その3)

ちょっと間が空きましたが、BlazeDS を使ったサーバからのプッシュ 3 つ目の方法です。

3.Polling + Piggybacking (使用するチャネル: AMFChannel)

この方法は、昔ながらのポーリングをベースにしています。基本的には、サーバにデータの有無を確認するポーリングリクエストを定期的に繰り返し送信することでサーバから最新の情報を取得します。

それに加えて、ポーリング以外のタイミングでサーバへのリクエストを送信する際にも、そのリクエストにポーリングリクエストを付加して送信します。するとサーバは元々のリクエストに対するレスポンスに加えて、ポーリングへのレスポンスがあればそれも一緒に返します。(このように抱き合わせで送信することを指してピギーバックと呼んでいます)

さて、ポーリング+ピギーバッキングの設定例です。

<channel-definition id="polling-piggybacking-amf" class="mx.messaging.channels.AMFChannel">
<properties>
  <polling-enabled>true</polling-enabled>
  <polling-interval-millis>10000</polling-interval-millis>
  <piggybacking-enabled>true</piggybacking-enabled>
  ...
 

ロングポーリングのときと同様に polling-enabled を true にしてポーリング機能を有効にします。そして、polling-interval-millis には 10000 を設定しています。これは 10 秒間隔でポーリングリクエストを送信するようにという指定です。

polling-interval-millis の値を小さくするほどリアルタイム度が高くなります。(ロングポーリングでは 0 でした) が、その分余計なオーバヘッドが発生しますし、無駄なリクエストの数も増える可能性があります。この方法はせいぜい数秒に一度情報が更新されれば大丈夫といった使い方が向いていそうです。

ロングポーリングの例と違い、上のサンプルでは wait-interval-millis を明示的に指定していません。サーバ側はリクエストを受けたら直ぐに返信するという動きにしたいので、デフォルト値 (0) から変更する必要が無いためです。

あとは、piggybacking-enabled を true にしておくことで定期的なポーリング以外のタイミングでも情報を受け取れるようになります。効果の程は、どのくらいアクティブにクライアント側でのインタラクションが行われるかによりそうですね。

この方法は、前の 2 つの方法と違ってサーバのスレッドをブロックする必要がありません。そのため、スケーラビリティの面からは有利だと考えられます。とはいえ、サーバ一台辺りが処理できる数は数百のオーダーだと思われるので、よりスケーラビリティの必要な環境では BlazeDS の代わりに LCDS の利用も検討してみてください。

最後に、この方法に限らず、サーバからのプッシュと RPC に個別のチャネルを使用する必要はありません。効率的なリソース使用の観点からは一つの ChannelSet で RPC やサーバからのプッシュやデータ管理用コンポーネント全てをまかなうようにすることをお勧めします。

Posted by ackie at 09:57 AM | Comments (0)

March 04, 2008

BlazeDS のプッシュ機能(その2)

引き続き BlazeDS を使ったサーバからのプッシュ機能の設定のご紹介です。

2.ストリーミングチャネルの使用 (使用するチャネル: StreamingAMFChannel)

この方法では、クライアントが HTTP リクエストをサーバに送ってクライアント・サーバ間の接続を確立すると、サーバはその接続をデータプッシュ専用のチャネルとして張りっぱなしにします。サーバからのデータは HTTP 1.1 の Transfer-Encoding: chunked を使って送信されます。(そのため HTTP 1.0 クライアントはこの方法が使えません)

ロングポーリングではサーバがデータをプッシュする度にクライアントは新しいポーリングリクエストを送りなおす必要がありましたが、ストリーミングチャネルでは一度リクエストが送られると後はサーバからのプッシュのみ繰り返しになります。ポーリングによるオーバヘッドが無いことや、より遅延の少ないデータ配信が可能であることはこの方法の利点と考えられるでしょう。

下はストリーミングチャネルの設定例です。

<channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
<properties>
  <idle-timeout-minutes>0</idle-timeout-minutes>
  <max-streaming-clients>100</max-streaming-clients>
  <server-to-client-heartbeat-millis>5000</server-to-client-heartbeatmillis>
  ...
 

idle-timeout-minutes に 0 を指定するとチャネルがタイムアウトにより閉じられることがなくなります。これで、ずっとチャネルを開きっぱなしの状態が実現されます。

ストリーミングチャネルも接続されているクライアントの数だけサーバのスレッドを占有します。そのため max-streaming-clients を使ってストリーミング用に使用できるスレッドの最大数を指定するようにします。上の例では 100 が設定されています。

貴重なスレッドを不要なのにも関わらず使用していたら効率がよくありません。そのため、サーバからクライアントがちゃんと接続されているか確認信号を送ることができるようになっています。server-to-client-heartbeat-millis に正の値 (単位はミリ秒) を指定するとこの機能が利用できます。上の設定では 5 秒おきにハートビートが送信されます。

ところで、ストリーミングチャネルでは、一回のリクエストに対して複数回に渡りレスポンスを送るという構造になるため、サーバとクライアント間のネットワーク構成の影響を受ける可能性があります。例えば、間の HTTP プロキシがデータをバッファしてからクライアントに送るような環境では、リアルタイムのプッシュが実現できません。

そのため、idle-timeout-minutes には 0 でなく 2 や 3 (単位は分) を指定して、「データは送られているがクライアントには届いていない状況」を判別できるようにしたほうが安全だと考えることができます。その場合は、クライアント側では「届いていないと判断されてチャネルが閉じられてしまった場合」に備えて、ChannelSet に 2 次利用できるチャネル (ポーリング AMF チャネル等) を指定しておく必要がありそうです。

このようにストリーミングチャネルは動きに少し癖があります。最初にご紹介したロングポーリングの方が一般的には使いやすいかもしれませんね。

3 つめの方法は、また次回。

Posted by ackie at 07:55 PM | Comments (0)

March 03, 2008

BlazeDS のプッシュ機能

Flex 3 と一緒に BlazeDS がオープンソースプロジェクトとしてリリースされました。BlazeDS は RPC とサーバからのプッシュを実現するためのサーバ側のテクノロジーです。クライアント側は Flex 3 のライブラリを使用します。

BlazeDS のプロジェクトサイト(http://opensource.adobe.com/wiki/display/blazeds/BlazeDS) には GNU LGPL 下で turnkey (Tomcat 付き構成済みバイナリ)、バイナリ、ソースの 3 種類のリリースバージョンが公開されています。

また、Adobe のバグ管理サイトにも BlazeDS 用のバグデータベースが追加されました。(http://bugs.adobe.com/blazeds/) 例によって、日本語表示を選択することが可能です。

BlazeDS と Flex (もしくは AIR) アプリケーションの接続にはチャネルの指定が必要です。RPC の利用には LCDS でもおなじみの AMFChannel または HTTPChannel 等を使用しますが、サーバからのプッシュにはこれらに加えて StreamingAMFChannel やStreamingHTTPChannel 等が使用できます。

(チャネル名に含まれる AMF と HTTP による違いは送信するデータフォーマットがバイナリ形式かどうかだけなので、この記事では AMF のみ取り扱います)

さて、BlazeDS でのサーバからのプッシュの実現は、3 種類の方法から選択することができます。以下、それぞれの特徴について簡単に説明します。

1.Long Polling (使用するチャネル: AMFChannel)

この方法では、クライアントは通常の HTTP リクエストとしてポーリングをサーバに行います。サーバ側ではクライアントへ送るデータが無かった場合は、そのまま新しく送信するデータが利用可能になるまでレスポンスを保留します。(これがロングポーリングと呼んでいる理由です) クライアントはデータを受信すると次の受信に備えるため、直ちに新しいポーリングのリクエストをサーバに送信します。

クライアントが毎回リクエストを送る手間を除けばほぼリアルタイムのプッシュが実現できます。この方法の利点の一つは、一般的な HTTP のリクエスト・レスポンスのパターンを利用するため、ネットワーク環境について特別に心配する必要がないことです。

下はロングポーリング用チャネルの設定例です。

<channel-definition id="long-polling-amf" class="mx.messaging.channels.AMFChannel">
<properties>
  <polling-enabled>true</polling-enabled>
  <polling-interval-millis>0</polling-interval-millis>
  <wait-interval-millis>-1</wait-interval-millis>
  <max-waiting-poll-requests>300</max-waiting-poll-requests>
  ...
 

まず polling-enabled を true にしてポーリング機能を有効にしています。次の行では polling-interval-millis に 0 を指定することでクライアントがデータを受信したら直ぐ (待ち時間が 0) 次のポーリングを行うよう設定しています。

サーバ側は、wait-interval-millis を -1 にすることで、ポーリングに対するデータが利用可能になるまでずっとレスポンスの送信を保留するようになります。ここまでがロングポーリングの基本設定です。

ロングポーリングで注意が必要なのは、返事を保留しているリクエストの数だけサーバのスレッドがブロックされてしまうという点です。無制限にポーリングリクエストを受け付けたりすると、全てのスレッドが保留状態になってサーバが新規リクエストを一切受け付けられなくなってしまうかもしれません。

そこで、上の例では max-waiting-poll-requests を使い、受け付けられるポーリングリクエストの最大値を 300 に指定しています。実際には、この数値はアプリケーションサーバのスレッドの最大数と、スレッドの使われ方を基準に決定することになることと思われます。

あとは、不要に長時間スレッドを占有する状態を避けるため、wait-interval-millis に例えば 60,000 (1 分) 程度の値を設定して、一旦サーバ側のリソースを開放するという方法も効果があるかもしれません。

なお、同じ HTTP セッションを使って複数のポーリングリクエストを行うことはできません。(サーバ側で制限しています) 例えば、複数の Flash Player インスタンスを同一ブラウザ内で起動する場合、一時点では、どちらか片方のみがロングポーリングを利用できます。

この方法では、サーバがデータをプッシュする度に、クライアントがポーリングリクエストを送るという「余分な」負荷がかかります。沢山のクライアントに頻繁にデータを送るケースではあまり向かない(効率が悪くなる)可能性もあるということですね。

ちょっと長くなったので、続きはまた次回。

Posted by ackie at 06:15 PM | Comments (0)

February 04, 2008

Adobe BlazeDS release candidate 公開

BlazeDS のリリースキャンディデート (重要なバグフィックス以外はほぼそのままリリースされる予定のバージョン) が公開されました。(BlazeDS@Labs) Flash 用のクライアントライブラリが提供されないようなのがちょっと残念ですが、Flex 3 と Ajax からは直ぐに使えるようになっています。コード、サンプル、およびドキュメントのダウンロードはこちらから。(Adobe ID が必要です)

Posted by ackie at 06:28 PM | Comments (0)