【1】処理スレッドの解放7.0.34までの実装では、WebSocketハンドシェイク後にクライアント側から何かしらデータを送信しない限り処理スレッドが解放されないという問題がありました。このため、Tomcat側のコネタク設定で、“最大接続数(maxConnections)”が“最大処理スレッド数(maxThreads)”より多い場合でも、クライアント側からデータを送信しなければ、maxThreads数以上の接続ができませんでした。7.0.35では、この問題は解消しています。chunked」を返していました。このため、Jetty-WebSocketクライアントがChunkedメッセージと勘違いして誤動作を起こしていました。7.0.33で、この問題は修正されています。【3】ヒープメモリの大量使用TomcatのWebSocketモジュールでは、送信時のテキストデータ/バイナリデータの内部保持用に、java.nio.CharBuffer/java.nio.ByteBufferを使用しています。デフォルトの状態では、1接続につき、それぞれ8Kbytes確保しています。これらのバッファは、クライアントから接続している間ヒープメモリを圧迫し続けるため注意が必要です。不要であれば、バッファサイズを小さくすることも考えた方が良いでしょう。バッファサイズは、MessageInbound#setOutboundByteBufferSize()/setOutboundCharBufferSize()を使って変更することが可能です。内部保持用のバッファは、以下の場合に使われます。writeTextMessage():CharBuffer、ByteBufferともに利用writeTextData():CharBuffer、ByteBufferともに利用writeBinaryData():ByteBufferを利用ただし、writeBinaryMessage()を使用する場合は、この内部保持用バッファは使用しませんので、送信するデータがバイナリで良い場合(もしくは、クライアント側でバイナリからテキストに変換できる場合)は、このメソッドを使用すると効率が良くなります。setOutboundByteBufferSize()/setOutboundCharBufferSize()のそれぞれに1を渡すことで、ヒープ利用量を目いっぱい下げることができます。【1】無通信タイムアウトデフォルトでは接続後に何も送信しないと、およそ5分(30万ミリ秒)でサーバ側からコネクションを切断します。WebSocketServletの初期化パラメータ、もしくは、プログラム中でWebSocket.Connection#setMaxIdleTime()を用いてタイムアウト値を変更することで対処します。「0」を設定すると、無限待ちとなります。8ではデフォルト通信バッファサイズが8Kbytesです。このため、大量にデータを送信する場合は、バッファサイズを拡張した方が性能が出る場合があります。web.xmlで初期化パラメータbufferSizeを設定することで、チューニングが可能です。【3】Jetty-WebSocketクライアントJettyが提供しているWebSocketクライアントは、作成したWebSocketServletのテストを行う場合に便利な機能です。1つのコネクションに対してスレッドを大量に確保しようとするため、今回の検証のように1プロセスで大量のコネクション用スレッドを起動すると、プロセス数の上限にすぐに達してしまうため、注意が必要です。このような使い方をする方が間違っているのかもしれませんが......。Node.js/Socket.IOでのWebSocketアプリケーション実装上の注意点Socket.IOはバイナリデータの送信に対応していません。Socket.IOを使ってバイナリデータをやりとりする場合は、データをBase64でエンコードする必要があります。3つのテストパターンで試す今回は、3パターンのテストパターンを考えてみました。した場合の性能差や、サーバから送信するデータ量によって性能差が見えるかを確認しています。テストケース【1】同時受信パターン10000クライアント接続完了後にサーバからメッセージを送信して、クライアント側での受信時間を計測します。クライアントアプリケーション1万クライアント分のスレッドを作成して、各スレッドがWebSocketでサーバに接続します。全てのクライアントが接続を完了した後、最後に接続したクライアントからメッセージを送信します。サーバアプリケーション(Tomcat/Jetty用)クライアントからの接続を受け付けると、コネクションをArrayListに格納します。クライアントからメッセージを受け取ると、ArrayListに格納されたコネクションを取り出して、メッセージを送信します。Tomcat/Jettyともに、ブロードキャストする仕組みを持っていませんので、上記のような作りになっています。・サーバアプリケーション(Node.js用)クライアントからの接続を受け付けても、特に処理は行いません。クライアントからメッセージを受け取ると、送信したクライアントおよび接続中のクライアントに対してメッセージをブロードキャストします。テストケース【2】同時送信パターン1万クライアント接続完了後にクライアントからメッセージを送信して、サーバ側での受信時間を計測します。クライアントアプリケーション1万クライアント分のスレッドを作成して、各スレッドがWebSocketでサーバに接続します。全てのクライアントが接続を完了した後、すべてのクライアントスレッドがサーバに対して一斉にメッセージを送信します。全クライアントがメッセージの送信を完了した後、サーバに対してログ出力依頼のメッセージを送信します。サーバアプリケーションクライアントからメッセージを受け取ると、Tomcat/Jetty用サーブレットではArrayListに、Node.js用ではArrayにメッセージを溜め込みます。クライアントからログ出力依頼のメッセージを受け取ると、溜め込んだメッセージをログファイルに出力します。テストケース【3】大量データ受信パターン1つのクライアントに対して、サーバから大量データを送信して、クライアント側で全データ受信にかかった時間を計測します。データサイズは、1〜10Mbytes(1Mbytes刻み)の10パターンで行います。クライアントアプリケーション1クライアントのみWebSocket接続します。接続後に、要求するデータサイズを送信します。サーバアプリケーションクライアントから要求データサイズの入ったメッセージを受け取ると、Tomcat/Jetty用はバイナリデータを、Node.js用はテキストメッセージをクライアントに対して送信します。次ページでは、テスト結果を見ていきます。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。