BlogBack

Exploring WebSockets and Evergreen

I gave a brief presentation on websockets at the mid-term developers meeting last September in Atlanta. Since that time, I’ve given the topic a lot of thought and I’ve done a fair amount of coding and experimentation.  I’d like to present my thoughts and findings here in a 3-part blog series.  Part 1 will be an introduction to Websockets, where I’ll describe what they are and how they work.  Part 2 will delve into their effects on network speed and latency.  Finally, in part 3 I’ll discuss some code, which I created as a websockets proof-of-concept opensrf client and gateway.

Part 1: An Introduction to Websockets

Websockets are a member of the HTML5 family of web standards.  It’s a client/server communication protocol, similar in many ways to XMLHTTPRequest.  It provides a way for clients to connect to a server, issue requests, and receive responses.  It offers a number of improvements, though, over the standard HTTP call-and-response style of communication used by XMLHTTPRequests.  Quoth the oracle:

The WebSocket protocol makes possible more interaction between a browser and a web site, facilitating live content and the creation of real-time games. This is made possible by providing a standardized way for the server to send content to the browser without being solicited by the client, and allowing for messages to be passed back and forth while keeping the connection open.  (http://en.wikipedia.org/wiki/WebSocket)

Since Evergreen relies heavily on XMLHTTPRequest, particularly in the form of the OpenSRF HTTP Translator, much of the discussion to follow will be based on comparisons of the two.

Let’s start with a simple Websocket vs. XMLHTTPRequest code sample.  Here is some Javascript one might use to send a message to a server and have the server echo the response:

var socket = new WebSocket('ws://echo.websocket.org/');socket.onopen = function() {socket.send('hello echo');socket.send(‘hello echo 2’);}// onmessage will be called twice in this example,// since two echo requests were sent to the server.socket.onmessage = function(evt) {// alerts the echo response textalert(evt.data);// If we want to disconnect..// socket.close()}

You can see this code run at http://jsfiddle.net/berick/vnPbV/3/

A similar, though slightly different, XMLHTTPRequest might look like this:

var client = new XMLHttpRequest();client.onreadystatechange = function() {if (this.readyState == this.DONE) {if (this.status == 200) {alert(this.responseText);}}}client.open("GET", "/echo?message=hello%20echo", true);client.send();

The most obvious difference, besides the code style, is that the Websocket client can send more than one request over the Websocket connection.  (Note the two calls to socket.send(…)).  On the other hand, an XMLHTTPRequest is designed to handle exactly one request.

Less obvious from the code, but equally important, is that a Websocket client can receive more than one response on the same connection.  XMLHTTPRequests, however, are designed to receive exactly one response.  (There is a partial exception to this XMLHTTPRequest limitation, which I discuss below).

This wide open (bi-directional, full-duplex) channel of communication is the primary difference and benefit of Websockets over XMLHTTPRequests.  It creates an environment where clients connect to a server, send large batches of requests and receive large, intermingled batches of replies, all on the same connection.  I’d like to explore this aspect of Websockets more fully in part 2 of this series.  For now, what are some other benefits that may not be obvious in this code sample?

Standards Compliant

Both Websockets and XMLHTTPRequest are web standards.  However, Evergreen makes heavy use of the OpenSRF HTTP Translator, which takes advantage of a non-standards compliant technique for streaming responses to clients via XMLHTTPRequest.  The streaming component of the HTTP Translator only works for Mozilla (staff client, Firefox) clients.  Because of this, the full benefit of the Translator can only be used by a limited pool of clients.  Alternatively, Websockets allows servers to stream responses to any compliant browser / architecture.

[List of supported browsers http://en.wikipedia.org/wiki/WebSocket#Browser_support]

This is very important should we decide to create a web-based staff client, move away from Mozilla for the staff client architecture, or desire streaming responses for non-staff interfaces.

Message broadcast / Async notifications

In theory, a websocket gateway could broadcast messages to all connected clients.  For example, an administrator could send a “System Going Down For Maintenance at X o’clock”  message to all active staff clients.  Similarly, unsolicited messages could be sent to a single client (or set of clients), based on some criteria.

For the Translator, all responses received from the server must the direct result of a request.

Cross-origin support

With this, it’s possible to serve API-derived content from a different domain than the base web application.  This could be useful, for example, for segregating web traffic to better manage resources.  It also means you can serve SSL API content even when retrieving non-SSL web content (HTML, JS, etc.), which could provide a nice balance between speed and security.  Finally, it would be possible to connect to more than one server (Evergreen or otherwise) at once.  It sounds kind of insane, but imagine retrieving data (reports, serials predictions, etc.) from a peer Evergreen server.

Using the Translator means that API content and web content are required to be served from the same domain.

Session caching and migration is no longer necessary

One of the complications that came with the OpenSRF HTTP translator was the necessity of tracking opensrf sessions in memcache.  Since the Apache keepalive means clients may get routed to a different Apache server in the middle of a conversation, steps were taken to allow the conversation to continue from a different location once the client re-connected.  With always-on connections provided by websockets, this is no longer an issue.

Mozilla mulipart-mixed streaming bug

There is an outstanding bug we have been unable to squash related to the HTTP translator and Mozilla’s multipart mixed/replace MIME type handling. See LP 1004019, but note that even though the fix in the LP entry is committed, the problem still occurs sometimes.  More research is needed.  Use of Websockets would theoretically allow us to side-step this problem.

Each of these, particularly the first 3, could have far-reaching implications.  Join me for part II of this series, where I explore the implications of always-on connections and their effects on network congestion and latency.