Optimized WebSocket broadcasting with Grizzly 2.3

One of the features introduced in Grizzly 2.3 is Broadcaster API for WebSockets.
There are two reasons for that:

  • Broadcasting is widely used with WebSockets (chat-like usecases) and it’s just good idea to have that API generalized.
  • Significant performance optimization

And here I’d like to stop on the 2nd bullet…
Normally when we use WebSockets API and want to broadcast some message (java.util.String) to a group of clients – we do something like:

String message = "somemessage";
for (WebSocket websocket : group) {
    try {
        websocket.send(message);
    } catch (WebSocketException e) {
}

it means each time we send a message to a particular client we do:

  1. Initialize UTF-8 CharsetEncoder;
  2. Convert java.util.String -> byte[] using UTF-8;
  3. Wrap the payload as WebSocket frame.

Depending on actual implementation steps 1 and 3 might be not that expensive (we can cache and reuse UTF-8 CharsetEncoders etc etc…), but step 2 is always expensive especially for large messages.
So why we should pass all 3 steps for each recipient instead of converting the message to a WebSocket frame just once and send the result to each recipient directly. Schematically it will look like:

String message = "somemessage";
byte[] rawFrame = prepareMessage(message);
for (WebSocket websocket : group) {
    try {
        websocket.sendRaw(rawFrame);
    } catch (WebSocketException e) {
}

This is how Grizzly’s OptimizedBroadcaster works.
Now, coming back to the Broadcaster API, the initial code will look like:

Broadcaster broadcaster = new OptimizedBroadcaster();
broadcaster.broadcast(group, message);

Please note, OptimizedBroadcaster is stateless and thread-safe – so you can use single instance in different threads to send messages to different groups.
Another way to use broadcast is:

websocket.broadcast(group, message);

If the later approach is used, it should be noted that, by default, Grizzly will use an unoptimized version of the Broadcaster (to maintain behavioral compatibility with previous releases). In order to leverage the optimized version, see the following example:

public static class BroadcastApplication
                 extends WebSocketApplication {
    private final Broadcaster broadcaster =
                new OptimizedBroadcaster();

    @Override
    public WebSocket createSocket(
                ProtocolHandler handler,
                HttpRequestPacket requestPacket, 
                WebSocketListener... listeners) {
        final DefaultWebSocket ws =
                (DefaultWebSocket) super.createSocket(
                handler, requestPacket, listeners);

        ws.setBroadcaster(broadcaster);
        return ws;
    }

    @Override
    public void onMessage(WebSocket socket, String data) {
        socket.broadcast(getWebSockets(), data);
    }
}

The complete Broadcast API sample might be found here.

Advertisements
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s