Sunday, 16 February 2014

Comet and Web Socket

JavaEE 6 introduce many improvement on Ajax processing. The new API allow server to serve long AJAX request without wasting HTTP thread pool. This major improvement make the waiting in Ajax request become less expensive for server resource and make server push/comet become more feasible.

In this article, I would like to revisit the strategies of implementing server push using HTTP and compare them with latest Java Socket API 3.0

BACKGROUND
HTTP is created with the goal to be protocol for simple, 1-way communication. The request must be initiated from web client and server provide the response to this request. This work well for earlier day where the main goal for website is to provide content. However, with the web evolving to Web 2.0 with lots of interaction, developers soon find the need to initiating request from server to web client. The name of this feature is server push, reverse Ajax or Comet

Generally, there are two strategies to solve this problem, hacking HTTP to implement Comet or step back further and introducing another protocol that is full-duplex. The new protocol is named Web Socket, which is fully supported by Java from Java EE 6 (Java Socket API 1.0).

SERVER PUSH METHODS

Regular Polling

In regular polling, the client regularly send request to server to ask for any new message to digest. This method is better fit to status check/health check purpose but still can be used for server push.

The main benefit is simple implementation and providing early alert of server failure. However, the drawback of this method is the over-head of  creating multiple HTTP requests and wasting of resource when there is no message. Another problem is the delay of messages because it is only can delivered when there is a polling request from client.

Service Streaming

In Service Streaming, the client send a request to server and server send back a long response, piece by piece whenever there is a message available. It can be implemented using Chunk Transfer Encoding of HTTP 1.1. Basically, the response last forever until the channel is closed.

As this method send multiple messages in the same response, it is client responsibility to handle the streaming and decode the message. The best javascript I can find that support streaming is jQueryStream (https://code.google.com/p/jquery-stream/wiki/API)

This method assure no delay of message delivery but implementation is more difficult. Moreover, as the response is hanging on server, likely one thread is occupied handling the response stream. Fortunately, from Servlet API 3.0, the thread that handling the response is not necessarily to be HTTP Thread. Hence, there is less impact to server scalability.

One more concern is the dedicated usage of one HTTP request. As browser enforce the maximum concurrent requests to one domain, wasting one request for service streaming may cause serious performance issue on old browser (IE 6 and 7 only allow 2 concurrent connections)

Long Polling

Long Polling is based on Bayeux protocol, which uses a topic-based publish-subscribe scheme. Let skip the part of topic subcribe and channel as this is not our main concern. The long polling is pretty similar to service streaming as the client need to initiate a request for server to send back response and server hold on the response until a message available. The main difference is the server end the response when delivering the message. Upon receiving the message, client immediately send another request and waiting for the response again. In case there is no message, the server return a empty response and client will submit another request.

This method sharing most of the advantage and disadvantage with service streaming but implementation is much easier for both server and client. I personally feel this method is hybrid of regular polling and service streaming. It still consume network when there is no message but the over-head of making http request is minimized.

Passive Piggyback

In passive piggyback, the server wait for the next request from client to include the message in the response. In real life scenario, it is used to update session cookie of stateless session. It is easy to see that this method is less reliable comparing to the above methods but also consume less resource.

I suggest this method to be used only when by nature of your application, regular requests were sent back to server. Clean implementation for this method is quite challenging. There are 3 problems that you need to solve here.

The first thing you need to consider is how to conveniently attach your message to any response without interfering with the original response. One option is to use cookie for storing message but with this option, you always need to check value of cookie for every callback handler in javascript.

The second problem is to intercept any response to attach message in server. This can be achieved easily nowadays with filter or AOP. However, thing is more difficult on client side. There is nothing like AOP for javascript. Therefore, you need to make consistent use of a javascript framework to handle every Ajax request in your system. Otherwise, you may miss the message.

Web Socket

All of the above method is quite hacky. They attempt to implement 2-way communication over a one-way protocol. The alternative solution is to implement another protocol as replacement for HTTP which is full-duplex. This protocol is web socket.

This is one example from Wiki how client and server establish web socket connection

Client request:
GET /mychat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 12
Origin: http://example.com
Server response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat


Lucky enough, Java have Java API for Web Socket 1.0 has been included to JavaEE from version 7. Tomcat also support WebSocket from version 7. If you want to know in detail how to implement Java Socket, can take a look at the example I found in this website

http://hmkcode.com/first-time-java-api-for-websocket/

At this moment, I would suggest you to carefully considering if you really need to use Web Socket. It is effective, easy to implement and secure but the main concern that it is stateful. Web Socket is basically server to client channel, its require all the message to be delivered to and from the same server.

The server need to maintain the state of its connection and if you want to install Load Balancer, the load balancer need to know how to forward the request to the same server. Until today, stickiness session is difficult to achieve with a non-http protocol. The best strategy is to use a L3 Load Balancer that calculate the server to redirect to by client IP hashing. Client IP is the information of TCP protocol (L2). Hence, it is applicable for both HTTP and Web Socket (both L3).


(image of 7 layer of communication from http://www.digikey.com/en-US/articles/techzone/2012/apr/communication-in-industrial-networks)


Even AWS Load Balancer cannot support stickiness for L3 load balancer. That why I believe it is better to wait until web socket become more widely adopted before start using it.