[Java] Optimized WebSocket broadcast

原文はこちら。
https://blogs.oracle.com/PavelBucek/entry/optimized_websocket_broadcast

ブロードキャストはWebSocketのサーバーサイドのコードで最もよく使われるユースケースの一つです。そのため、WebSocket API for Javaの現行バージョンのユーザビリティを評価し、改善すべき点などを提案しようと考えています。

ご注意頂きたいのは、このエントリはその目的から実験的なものだ、ということです。このエントリで述べるTyrusの機能を使うことはできますが、警告なしに変更される可能性があります。

ブロードキャストについて語るにあたって、その定義をしましょう。メッセージをブロードキャストするとは、メッセージを接続している全てのクライアントに対し送信することを意味します。おわかりですよね?よくあるWebSocketのサンプルアプリケーションはチャットです(Tyrusも例外ではなく、./samples/chatにあります)が、まさにそのように動作します。クライアントがメッセージをサーバーのエンドポイントに送信すると、メッセージを全てのクライアントに再送信するため、全てのクライアントがメッセージを見ることができる、というわけです。

認証・認可を無視した場合、サーバー側の実装は以下のように短くなります。
@OnMessage
public void onMessage(Session s, String m) throws IOException {
  for (Session session : s.getOpenSessions()) {
    session.getBasicRemote().sendText(m);
   }
}
これで十分動作しますし、期待通りの機能を提供します。基礎となるコードは接続された全てのクライアント向けのメッセージを処理する必要があります。そのため、送信対象のDataFrarmeをn回作成することになります(nは接続クライアントの個数を意味します)。現在のところ、全ては一つのデータフレームの作成に必要な処理時間に依存します。このオペレーションはそれほど高コストなものではありませんが、実際には多数回呼び出す必要があるにボトルネックになります。もう一つの重要な事実として、WebSocketの接続はステートレスゆえ、一度作成されたデータフレームを必要なだけ多くのクライアントに送信することができます。そのため、つまるところ、特にメッセージが全ての接続クライアントに対して同じである場合、データフレームを複数回作成する必要はないのです。

WebSocket APIではコンシューマがデータフレームレベルのメッセージにアクセスすることを許しておらず、既に構築されたデータフレームを送信する手段も提供していません。この内容は仕様の次バージョンに取り込まれるかもしれません…が、今はできないのでしょうか?

Tyrus (1.3以後)をお使いなら、同じユースケースの最適化版を試すことができます。
@OnMessage
public void onMessage(Session s, String m) {
  ((TyrusSession) s).broadcast(m);
}
org.glassfish.tyrus.core
Class TyrusSession
broadcast
https://tyrus.java.net/apidocs/1.3/org/glassfish/tyrus/core/TyrusSession.html#broadcast%28java.lang.String%29 
このようにすれば、データフレームを1回だけ作成してサーバー側のリソースを節約し、さらにクライアントはブロードキャストされたメッセージをより短期間に受信することでしょう。"broadcast"メソッドはMap<Session, Future<?>>を返します。この戻り値をどのメッセージがすでに送信されたか否かといった情報を取得するために使います。コールバック付きのバージョンはまだ利用できませんが、今後追加されるかもしれません(この機能が欲しいなら、users@tyrus.java.netにコメントを送って下さい)。

Tyrusのブロードキャストを使った際の性能向上を確認する正確な計測結果はありませんが、特に接続しているクライアント個数が多い場合には特に著しいものになると思われます。
(JDK8ユーザーへの注意:この最初のシナリオは、fork/joinフレームワークを使っても改善することができますが、現在のところ、TyrusはJava SE 7と使うことになっているので、このエントリでは意図して無視しています。)
ご質問があれば、是非users at tyrus.java.netへお寄せ下さい。

そしていつも通り、関連リンクを掲載しておきます。

0 件のコメント:

コメントを投稿