Lightstreamer

Robust Network Code with window.setTimeout

by Michael CarterAugust 11th, 2008

In Orbited, we sometimes send multiple events in a single payload, particularly with the long-polling and polling transports. After we parse the data of each event, we call some event handler that a user has attached to the Orbited connection. Imagine code that looks something like this:

function rawOnReceive(rawData) {
    frames = parseFrames(rawData);
    for (var i = 0; i < frames.length; ++i) {
        self.onread(frames[i]);
    }
}

Unfortunately, sometimes user code can throw an exception. If this happens, we don’t want to stop sending the remainder of the frames, so we revised our original code to look more like this:

function rawOnReceive(rawData) {
    frames = parseFrames(rawData);
    for (var i = 0; i < frames.length; ++i) {
        try {
            self.onread(frames[i]);
        }
        catch(e) { }
    }
}

But now we have a problem — that is, if the user code fails, we hide the error, and then dispatch the next packet. This is a terrible solution because it will be next to impossible for users to track down bugs.

Consider window.setTimeout, a mechanism generally used to schedule calls after a set amount of time has expired. It has a side effect though; it moves code out of the callstack. So we use setTimeout with 0ms as the specified timeout in order to make the appropriate onread calls without worrying whether they throw exceptions or not:

function rawOnReceive(rawData) {
    frames = parseFrames(rawData);
    for (var i = 0; i < frames.length; ++i) {
        window.setTimeout(function() { self.onread(frames[i]) }, 0);
    }
}

This means that all of the onread callbacks will be scheduled to be executed, but none of them will actually execute until our code, the rawOnReceive function, finishes. Unfortunately, there is a second problem — the value of i used for each onread callback will be the final value of i. We need to hold on to each value separately for each callback. Consider this code:

function rawOnReceive(rawData) {
    frames = parseFrames(rawData);
    for (var i = 0; i < frames.length; ++i) {
        (function() {
            var j = i;
            window.setTimeout(function() { self.onread(frames[j]) }, 0);
        })();
    }
}

Note the extra function and the “var j = i” — Our solution is to create a closure that saves each value of i as locally scoped variable j. This code will allow us to make all the appropriate onread calls, whether or not one calls user code that causes an exception.

When I first tried this out, I thought it would fail due to the ordering of the messages — after all, we go through a lot of trouble in Orbited to guarantee message order. It would be truly tragic if we destroyed that ordering right at the last possible moment. But its actually not a problem whatsoever. Regardless of how the various browsers implement setTimeout, they have managed to do it in a way that preserves ordering if multiple consecutive calls have the same timeout value. Of course, I would feel more comfortable if this was documented somewhere!

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Thinking About Browser Protocols

by Michael CarterJuly 17th, 2008

In light of the recent discussion about sockets and protocols and Comet, I’ve been thinking about browser protocols:

XMPP:

  • Put IM on your website
  • Manage XMPP components from a browser

IMAP:

  • Write Gmail in 20 minutes ;-)

IRC:

  • Collaborate on Open (and otherwise) Software from a browser

STOMP:

  • Message Queue integration — Browsers can be first-class clients in MQ systems

We have already started the above choices with the Orbited project. But there are hundreds of additional protocol choices. What protocols do you want in the browser?

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Comet Presentation at MySpace

by Michael CarterJuly 10th, 2008

A few weeks ago MySpace invited me to give a presentation about using Orbited to create scalable Comet applications. While I can’t speak to any plans on the part of MySpace, I did get permission to post my speaking notes and slides. One point to keep in mind is that this presentation was made shortly before the naming of WebSocket was decided in the HTML5 spec, so the slides refer to the then-current name “TCPConnection”.

Slides

Speaking Notes


Slide: Orbited Logo + Michael Carter

-My name is Michael Carter
- Founder Lead developer of Orbited
- 2 years in development
- countless architectures tested
- now we’ve found the best
- javascript work

Slide: Comet

- Here to tell you about Comet
- Everything I’ve learned in two years of Comet work
- You probably already know what Comet is. But i’ll say it again just in case.

Slide: What is Comet

- Its about asynchronous updates in the browser (Pushing data)
- Not necessarily about a particular technology
- could be flash
- polling
- javascript hacks (streaming)
- Its about an interaction model — user is notified asap with new data
- Its about the applications that you can build with that interaction model
- Chat, clearly
- Financials
- Gaming
- Auctions
- Sports reporting
- Collaborative Editing
- Network monitor reporting / system administration
- Election Monitoring (Andrew Betts / London Paper)
- Air traffic control (no joke)
- To name a few
- In practice though, everyone wants Comet without the need for flash or bad performance of polling
- Just plain old js and html, low latency
- Which brings us to Transports

Slide: Transports
- These are the actual mechanisms for delivering data
- There are many

Slide: Iframe

- Originally we had script tag streaming
- but it made sense to put it in an iframe
- So we refer to it now as iframe streaming

Slide: Iframe Diagram

- Application page has a callback “receive”
- Finishes loading, creates and iframe
- Iframe causes an HTTP request to the server
- the server sends headers
- (transfer-encoding chunked for http 1.1)
- And then stops
- The key to this transport is incremental rendering
- Browser will try to display any open/close tag pair that it receives
- This includes displaying invisible elements, like script tags
- So the server can cause the browser to execute arbitrary javascript
-

Slide: Iframe Code
- Easy to implement
- Works in all browsers with the same code
- Suffers from..

Slide: Iframe Usability
- Loading Bars
- Hour glasses
- clicking noises?!

Slide: Iframe Unacceptable
- Modern applications can’t have clicking noises and hour glasses.
- The users would get too confused
- So Iframe streaming isn’t the most popular transport
- Instead, the most popular transport is…

Slide: XHR Long polling

- Long polling is what the cool kids do.
- (Meebo and Facebook, for instance)

Slide: XHR diagram

- Browser says, ‘Give me an event’
- Server says, ‘…’
- Server says, ‘event.’
- Browser says, ‘Give me an event’
- server says ‘…’
- Its cross-browser

Slide: Long polling code
- still easy to implement
- and no usability issues!
- seems like a big win
- but how does long polling performance compare to iframe streaming?
- Consider an island off the coast
- its surrounded by water

Slide: Island
- We want to send conveys to the island, so we build a bridge

Slide: Bridge
- Conveys can now go to the island as they please
- But maybe a big ugly bridge is not what we wanted… its too unsightly
- So instead we build a boat

Slide: A boat
- The convey arrives at the boat, and the boat takes it to the island
- no problem
- But what about the second convey that arrived just after the boat leaves?
- It waits for the boat to go to the island
- It waits for the boat to come back
- It gets on, and waits for the boat to go to the island
- 3x travel duration
- Well Iframe streaming is the bridge, and the boat is long polling
- Meaning, long polling suffers from a 3x latency performance hit
- But thats not all
Slide: Bandwidth comparison
- You also have to send headers all the time
- Your buddy says ‘hows it hanging’
- But the browser says ‘GET /some/url HTTP/1.1\r\nUser-Agent: …etc’
- And the server says ‘HTTP/1.1 200 ok\r\nContent-type….’
- your 15 byte message can easily incur 300 bytes of headers, or more!
- thats a 20x bandwidth increase in that case

Slide: Long polling unacceptable
- 3x latency is too much
- 20x bandwidth is too much

Slide: Strike 2, you’re out
- Strike 2, you’re out
- or so we thought

Slide: Htmlfile Object
- htmlfile object to the rescue

Slide: ActiveX!
- but safe for scripting
- hides usability issues

Slide: Garbage crossout
- leaks live connections on navigations
- But we can fix that by explicitly calling the garbage collector

Slide: Htmlfile works great
- Streaming
- But No side effects
Slide: Explorer only
- partial solution
Slide: Xhr Streaming
- transport for ff and safari
Slide: ready state 3
- don’t do one event per request/response cycle
- do a hundred. a thousand…
- ready state 3 saves the day
- callbacks for download progress from server
- responseText is just plain text without any inherent meaning

Slide: Manually parse
- So invent our own format
- parse it manually
- And we’re set for firefox and safari
- Without loading bars or anything
- and the same bandwidth and latency constraints of iframe streaming
- So we’ve got all the browsers
- Except opera

Slide: SSE

- Opera goes above and beyond the call of duty
- I don’t ask that browser’s make my life easy
- They can keep their nasty forest of terrible hacks
- All I ever asked from browsers is that they make it possible to do comet
- But Opera actually makes comet a first class citizen of the browser
- Create an event source, name a url, add a listener. The end.

Slide: Html5

- Then they went on to propose that the this be included in HTML5
- after discussions with other vendors, gained support, a new spec came up

Slide: deprecated

- so the new one isn’t implemented
- but thats okay
- we can use the deprecated one in opera 8+

Slide: Transport Conclusions 10.18.20
- Ten minutes to explain
- Years to discover

Slide: hacks
- And yes, its hacks, hacks hacks

Slide: aim carefully
- Developing these transports is like trying to throw darts at a board

Slide: moving target
- but the board moves after you’ve thrown the dart
- That is to say, just imagine the most frustrating game you can
- That game is twice as fun as building transports

Slide: sleek bridge
- We can avoid the boat transport (long polling)
- And provide great user experience
- get a nice looking bridge

Slide: sleek bridge image with orbited logo superimosed
- And orbited does just that

Slide: Scalability
- Once you have a way to do comet, you need to scale it
- where transports are frustrating, scaling is hard
- Step 1,

Slide: Vertical Scalability
- How do you put lots of users on one machine?
- Seems like such a hard problem, but really there’s a simple trick
- And once you know the trick, its possible
- Don’t use threads.
- People have tried this with servers like apache
- A reasonable thread count, of 20, will service 20 users
- A better user count is a 1000 though
- But a 1000 threads brings a system to its knees with context switches
- No comet, just thrashing

Slide: Comet + threads != scalable
- So use the little trick of omitting threads, and you’re golden
- Build event-based servers
- You don’t want your comet apps to be like nature preserves
- You don’t want your app to be a lonely desert with the occasional wanderer
- it should be a riot, with users tearing down the walls, sucking your resources dry, demanding more…

Slide: desert -> riot
- So use event based programming for your comet server
- And I guarantee, your app will be a riot, not a desert.

Slide: zzzz
This is the easy problem
The harder problem is the other “half” of scaling,

Slide: Horizontal Scalability
- If one server supports 1000 users, does 2 support 2000? and n, n-1000?
- This is a truly tough problem
- Really though, it depends on the application
- No one answer.
- But a few core rules are in order
- 1. Don’t share state between comet servers
- 2. Only do Comet in the Comet server. no Pub/sub, no jabber/game server, no load balancing, just comet
- 3. Treat comet as the last leg of the journey

Slide: Two Comet servers (sharded by user) doing pub sub (ajaxworld slide)
- For some reason, comet servers are all trying to provide a pub/sub api
- Developers like it, great.
- But it was already a hard problem before Browser’s existed
- And the people solving the problem, RabbitMQ/ActiveMQ, aren’t part of the comet community. (there have been minor inroads)
- Integrating streaming comet sith real publish/subscribe message queues would be great
- But, thats just a specific case of a larger issue
- The real issue with scaling comet applications is that
- Comet is difficult
- Comet imposes architectural constraints on web apploications that we aren’t used to (can’t do round robin balancing per http request)
- Its a moving part that has to be closely tied to the other pieces of the system
- But integrating comet with existing technologies would allow us to solve the horizontal scaling problem however these existing technologies already solve it.
- How could you scale a thick client deployment?
- We want that to be the only question to answer when scaling a comet application.
- So How do you integrate comet servers with X?

Slide: Offboard Comet integrated with Jabber
- This is an example of how a typical comet server is integrated with jabber.
- the browser maintains a connection with the comet server and the “bridge”
- The bridge is an http server (hopefully event based as well!)
- and also an xmpp client
- and also a “Comet client” (dispatch protocol)
- Message flow goes browser -> bridge -> jabber -> bridge -> comet -> browser

Slide: A lolcat tangled up
- This is a bit of a mess
- complex systems are hard to scale

Slide: previous slide (Offbard comet integrated with jabber)
- you can’t scale this with your typical web load balancer
- the mapping between comet servers, bridges, and xmpp servers are almost certainly not giong to be 1-1
- so you have the complex task of figuring out load balancing between each part
- and then you have to implement each client twice
- once for the bridge, once for the browser
- the bridge speaks xmpp to the jabber server, but json-chat (made up protocol) to the browser
- Clearly not the solution…

Slide: Victory march picture, maybe the planting of the american flag in some battle
- Standards save the day.
- HTML5 has specified a TCPConnection standard for the browser

Slide: TCPConnection (word)
- I’ve been working closely with whatwg/w3c to specify the protocol and api that solves all of our problems
- tcpconnection is just like a socket, but for javsacript in browsers
- It will
-traverse forward proxies
- speak ssl
- include cookies (auth integration)
- use a single socket for both directions
- revolutionize web applications
- Think about it — tcp connections revolutionized network programming in the 70s.
Slide: Iron Man screenshot during test sequence
- tcp/ip. Thats how dad did it, thats how america does it, and its worked out pretty well so far
- And we don’t even have to wait for browser vendors

Slide: The future is now (sci-fi-ish picture + words?)
- Orbited provides a TCPConnection to all major browsers, today.

Slide: Browser < - > Comet Proxy < - > Jabber diagram
- Orbited speaks comet transports on the front
- and plain old tcp on the back
- So you put it in front of ANY tcp server
- and the browsers can interact as if they’d connected directly to the backend server over tcp.
- and the server doesn’t need to be altered whatsoever.
- No need for a bridge or dispatch protocol
- Much less complex means easier to scale
- Load Balancing?
- We can simplify this picture still

Slide: Browser < - > ( comet Proxy + Jabber Diagram single machine)
- Treat the comet proxy as part of the server
- One comet proxy per backend server
- Now you can all sigh in relief

Slide: Sigh of relief
- Because Comet isn’t going to get in the way
- Scaling Comet applications horizontally isn’t a twofold problem anymore
- If you know how to scale a network application, then you can scale a comet application.

Slide: Jabber server cloud with half Comet proxies, half normal
- And whats more, there’s no difference between the browser and the desktop

Slide: Auth + persistence (a pair of keys and some kind of storage)
- There are a couple of details: authentication and persistence

Slide: Jabber server with comet proxy on left, web app on the right, sql server behind both
- Just have the network server and the web app coordinate on the back end
- put the sql server behind both
- User creates an account over the web app
- but can log in to jabber
- jabber saves logs to the database
- and the user can see those logs via the web app
- And your problems are over.

Slide:Conclusion (Bullseye (with orbited logo somewhere))
- Transports are frustrating, but Orbited implements them (indeed, a number of projects take our implementation directly)
- Vertical Scalability and threads don’t mix. Orbited use event-based network IO.
- Horizontal scalability is tough because you have two problems.
- If you can solve integration, then you can get a handle on horizontal scalability by normal means
- TCPConnection is the perfect integration point. It works with all past, present, and future tcp/ip servers. Out of the box.
- Orbited provides that functionality today.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Independence Day: HTML5 WebSocket Liberates Comet From Hacks

by Michael CarterJuly 4th, 2008

A recent set of HTML5 discussions are changing the course of Comet. First, a recap of the last two years of Comet: With long-polling we set the bar to cross-browser push. With XHR streaming and ActiveXObject(’htmlfile’) we raised it to cross-browser streaming. With SSE we’ve been trying to raise the bar to native, cross-browser streaming. And there we’ve sat, hoping that browser vendors actually implement the latest SSE spec.

I say we’ve been selling ourselves short. All this time pushing for a native server->client streaming transport, but we still lack client->server streaming, and anything resembling a standard transport for bi-directional communication. The Holy Grail of Comet development has always been native browser support of a full-duplex, single-connection communication’s channel, otherwise known as a TCP socket. But we’ve been mired down in hacks so long that we’ve lost the vision.

No Longer. The HTML5 specification now offers WebSocket, a full-duplex communications channel that operates over a single socket. I have been listening closely, and in some cases contributing, to the process of ensuring that WebSocket will:

  • Seamlessly traverse firewalls and routers
  • Allow duly authorized cross-domain communication
  • Integrate well with cookie-based authentication
  • Integrate with existing HTTP load balancers
  • Be compatible with binary data

The API of WebSocket is very straightforward. You create a WebSocket and point it at a url:

var conn = new WebSocket("ws://www.example.com/livedemo")

Then you attach three callbacks:

conn.onopen = function(evt) { alert("Conn opened"); }
conn.onread = function(evt) { alert("Read: " + evt.data); }
conn.onclose = function(evt) { alert("Conn closed"); }

And finally, you can send upstream data with a simple function call:

conn.send("Hello World")

The browser will perform an HTTP handshake with the target web server to determine support, and then a direct stream will be exposed via the onread and send functions. The uri scheme “ws://” is used for WebSocket connections, and the “wss://” URI scheme is for secure WebSocket connections.

After the handshake, bi-directional framed communication ensues. Each frame can be either binary or text, thus allowing for swapping the encoding mid-stream. You can find more information about the protocol itself at the network section of the whatwg HTML5 draft page

While the HTML5 specification is not in a finalized stage, the first public draft was published by the W3C in January 2008, and browser vendors have already began targeting features in the specification. The idea of putting a duplex channel into the spec is not a new one; the TCPConnection API and protocol was initially drafted more than two years ago. Unfortunately there were many significant problems with TCPConnection that held back browser adoption. Ian Hickson, the editor of the HTML5 specification, tackled these problems head on and under his guidance the standard has evolved to a usable state with WebSocket. About this new feature, Mr. Hickson comments:

“I’m looking forward to seeing Web Socket implemented in browsers, as I think it’s going to enable all kinds of realtime applications like chatting, remote controls, and the like, without the ridiculous hacks authors have to use today.”

Comet

WebSocket in a browser is terrific because it drastically cuts down the complexity of the Comet server by an order of magnitude. What’s more though, it provides a straightforward, understandable API to JavaScript developers. The most important part of the specification is that developers can wrap their heads around the API in about five seconds. That’s because it looks so much like a socket.

If the future prospect of a native WebSocket isn’t enough good news, I am proud to announce that the Orbited project has implemented WebSocket for all major browsers, today. We do this by communicating over various Comet transports with the browsers, then performing the WebSocket handshake with the remote server, and proxying data in between. This means that today you can write a WebSocket server and application, start Orbited up, and be on your way. Tomorrow, you won’t need to change any of your server or client code whatsoever. Your application will fall forward to the native implementation of WebSocket for improved performance.

TCPSocket

The single most voiced criticism to this specification has been that a WebSocket isn’t quite the same as a raw TCP socket, because a WebSocket server needs to understand a specific handshake in order for browsers to connect directly, and as such a WebSocket can’t connect to existing servers. If we did allow raw TCP sockets in the browser, a malicious site could cause any visitors to open up a TCP connection to an SMTP server, for instance, turning a casual web visitor into a spambot. There are many variations on this scenario, but the general problem is that a raw socket connections in a browser will allow any sites that a user visits to access network services as if they were the user, in the same network security context as the user. We need to therefore make this an opt-in process or we’ll catch existing servers off-guard. Furthermore, very few protocols have any kind of cross-domain authorization or security mechanisms built in. If we were to allow raw TCP, then we would be opening all manner of cross-site security holes. We could fix these by limiting TCP connections to the origin domain and port, (meaning a direct sockets back to the webserver only) but that would limit any usefulness the TCP socket could provide.

I fully understand the criticism though; Earlier this week I discussed exactly why having a raw socket in the browser is so desirable. You could, for instance, quickly prototype a Gmail clone using a raw socket, an IMAP client, and an XMPP client in the browser.

We have a clear problem then: Direct access to existing network servers could greatly simplify application architecture, but due to security restrictions it’s a non-starter; we absolutely must retrofit each network server with the new WebSocket protocol first. I hope that happens, but we can’t count on it, at least not right away. What we really need is a way to allow the server to opt-in without putting it in the protocol, a way to seamlessly layer access control in front of the back-end server. It turns out that this problem has already been solved for traditional networks. That is, if we have two end-points communicating over TCP, and we need transparent access control in between, then we can use a well known device: A firewall. The beauty of a firewall is that server behind it requires no re-programming, or even re-configuration, yet gains all of the access control/security benefits. What we really need in the browser case, is a custom firewall that can listen for WebSocket connections from the browser, enforce access control, and relay TCP to a back-end server.

That is why Orbited provides this feature under the API name TCPSocket. Orbited is the firewall that sits between the back-end server and the browser. It understands WebSocket protocol for browser communication, and uses whitelist security to accept or reject requests to proxy TCP data to and from a back-end server. That’s right, you can fire up a stock XMPP server, and Orbited, and write the XMPP client entirely in JavaScript. This works cross-browser today. We also offer a binary mode that uses an intermediate encoding to allow the browser to read raw bytes (in the form of JavaScript integer arrays) from a remote server. Here is a diagram of the architecture:

Orbited is a Web Firewall

The Future

Now its up to the browser developers to implement Websocket. I expect some will be very quick on the uptake, while it may take years for others. I expect to see a common pattern emerge where application servers listen to the WebSocket protocol directly from new browsers, but fallback to Orbited’s emulation layer for legacy browsers. The key here is that we don’t have to wait on the browser vendors to get started. We can all develop these WebSocket applications now, and when browsers have native support, we’ll all get a performance boost.

We will probably never get a native (raw) TCP socket in the browser, for the security reasons I outlined. It’s okay though — we can use the firewall pattern I outlined. For more information about installing and configuring Orbited, check out the documentation and the getting started section.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Sockets in the Browser

by Michael CarterJuly 1st, 2008

I am pleased to announce, with the Orbited 0.5.x series, we provide a TCP socket for the browser.

When I used tell people about Comet, I’d have to ask if they’ve heard about Reverse Ajax, or HTTP Push. Or a number of other arbitrary phrases for the same technology. “You know, where you have data on the server, and you need to get it to the browser without the browser needing to ask for it.” Now I don’t have to deal with that, because very, very few people have heard of Reverse Ajax and not also heard of Comet. But still, when I walk into an arbitrary user group meeting, I ask who has heard of Comet, only about 25% of the audience raises their hands.

Now I have a new tactic. I ask, “How many of you have heard of Comet? Keep your hands up…” and a quarter have their hands up. “If you’ve heard of a socket — yes, a TCP socket — then also put your hand up.” And at this point, the entire audience has their hands raised. With the Orbited project we’ve found our explanation of purpose: We provide a socket API to the browser using the best methods available, which in most cases are Comet-based. This week I can make it official because for all intents and purposes, the Orbited project provides a TCP socket in the browser.

The name of the API is TCPSocket and you can use it like this:

var conn = new TCPSocket(hostname, port)
 
conn.onopen = function() { alert('connection opened!') }
conn.onread = function(data) { alert('RECEIVE: ' + data) }
conn.onclose = function(data) { alert('connection closed!') }
 
conn.send('Hello World');

The above code code is all you need to know. It will open a TCP connection to hostname:port, and will send the data “Hello World”. Any data the server sends back will be alerted with the onread handler.

The exact mechanism behind this innovation is pretty straightforward: Orbited is a router and firewall for incoming TCPSocket connections from the browser. It uses Comet techniques to establish bi-directional communication with the browser, then forwards all data over a raw TCP socket to the end point. Configuration allows access control enforcement so that the TCPSocket can only be connected to pre-approved end-points, so that the Orbited server isn’t an open relay.

While this presents a paradigm shift in the way developers are tackling real-time, web-based applications today, it’s actually a return to the original method of writing network applications. Instead of writing applications based on web frameworks and throwing a Comet server in the mix, you can simply use the client-server architecture where the browser is the client, and the server is an arbitrary TCP server. Let’s take Gmail as a brief case study.

The Gmail application features a nice gui that clearly took some time to build. The real trouble with building Gmail is figuring out a way to bridge email notification to the browser. You could create a server that uses IMAP to discover the new messages, then use a Comet transport to push those messages to the browser. You also need to write a similar adapter for XMPP. That means you’ll need a server that acts as an XMPP client for each user and transcodes the XMPP protocol to something JSON-based for easy access in the browser. You’ll need to then integrate these and find some way of doing load balancing. While this isn’t rocket science, its damn hard.

On the other hand, assume that your base tools include a pure-JavaScript IMAP and XMPP client in the browser. On page load the browser can ask the IMAP server directly for the 20 most recent emails, including their send times, read status, and subject. Next, the browser can issue an IDLE command which will cause the IMAP server to send immediate notification of any new mail. The browser also can connect to the XMPP server and send/receive presence information to/from the user’s buddy list. Message dialogs and typing notifications are all handled by callbacks attached the XMPP client, and sending messages to buddies is a trivial one-liner. There’s not a whole lot else to do besides make a great user interface, which can take as much time as you can give.

I’m not trying to cast a shadow on the engineering behind Gmail — its a brilliantly engineered product. We’ve been stuck with web application servers (read, jumped up HTTP servers) for so long though, that we take complicated architecture for granted. I’m just pointing out that you don’t need to be a brilliant engineer to create Gmail if you have the right tools. The right tools aren’t web application servers, they’re sockets and clients, and with those tools we could put together a tutorial titled “How to write your own Real-time Email/Chat application in 20 minutes.”

The Future

Once you have a TCP socket in the browser, no web application architecture is impossible, or even that hard. Only now it is apparent how far JavaScript lags behind all other programming languages for networking support. We need to start developing every major protocol in JavaScript. For now, Orbited ships with STOMP (ActiveMQ and RabbitMQ), IRC, and XMPP implementations, but we plan on soon shipping a Daemon that serves implementations of all major communication protocols.

These developments will transform the way we think about the web. Many thick-client systems no longer need to be re-engineered for the web — its just a matter of writing a user interface. It is conceivable to write a fully featured browser application with no web application server whatsoever. All the applications that use complicated architectures to bridge various protocols to the browser over HTTP can now be simplified many times over. JavaScript developers no longer have to live in a ghetto; we can use a socket just like in all other programming languages.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Comet at the iPhone BarCamp

by Michael CarterJune 27th, 2008

I will be giving a talk this Saturday titled “Impact of the Reverse AJAX (Comet), TCP Connection and HTML5 to the architecture of the Web” at the iPhone BarCamp this Saturday in Palo Alto, CA.

There are under ten slots still available for this event (registration cap is 100) so if you’re interested, you can still register. This talk will cover a range of Comet-related topics, including what Comet is and how it works, how it will impact the architecture of your application, and the formalization of Comet with regards to the HTML5 specification. Additional information can be found at the BarCamp Wiki. I hope to see you there, but if not, I’ll post my slides and speaking notes for later review.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

My Future with Kaazing

by Michael CarterJune 11th, 2008

I’ve recently started a new job at Kaazing, a company focused on re-engineering the Web for real-time. Kaazing’s vision for the future of Comet closely parallels my own vision, allowing this architectural position to be mutually beneficial both for Kaazing’s Enterprise customers and the Orbited project. To those ends, Kaazing has generously allotted a substantial portion of my hours towards committing improvements directly to the Orbited codebase. Many of those improvements will be soon made available with the upcoming 0.5 release of Orbited. Furthermore, Kaazing is encouraging my direct involvement with the HTML5 specification as a forum for driving Comet standards. These exciting developments are great news for me, Orbited, Kaazing, and the entire Comet community.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Colliding Comets: Battle of the Bayeux Part 7

by Michael CarterMarch 27th, 2008

Michael Carter says that his concerns about the Bayeux protocol have gone unanswered, and that Greg Wilkins’ and Alex Russell’s arguments for Bayeux have focused on peripheral issues.

Part 1: Greg Wilkins explains the need for Bayeux
Part 2: Michael Carter criticizes the current state of Bayeux
Part 3: Greg Wilkins responds to Michael Carter
Andrew Betts’ thoughts (from a related article)
Part 4: Michael Carter responds to Greg Wilkins
Part 5: Kris Zyp’s thoughts
Part 6: Alex Russell responds to Michael Carter
Part 7: Michael Carter responds to Alex Russell

I’ve already made clear, technical arguments about Bayeux’s flaws, but those issues still haven’t been addressed. In his original article, Greg brought up multi-frame connection sharing as one of Bayeux’s core features, and in an effort to keep the dialogue centered on facts I pointed out that Bayeux actually doesn’t solve the problem whatsoever. Alex, on the other hand, has a different opinion on the matter. But while Greg is claiming that Bayeux’s strength is that it supports connection sharing, and Alex is proclaiming that actually it’s the lack of that support that is the real strength, let me say that I honestly couldn’t care less about multi-frame anything; a proposal to solve this was in the works long before I even entered the realm of Comet development. There are so many more important issues.

Bayeux is a bad foundation for Comet communication. It implies the wrong API, and by not specifying an actual API, an application can’t swap one Bayeux client out for another. It lacks any message reliability or ordering guarantees. There is no standard way of integrating new transports—that’s completely unspecified. The worst part is that these flaws are, according to Alex, not errors of omission; rather, they are by design. The Bayeux authors don’t care about client interoperability or transport interoperability, which are the only two parts of Comet that are even possible to standardize. Instead they’ve chosen a communication protocol (note my previous musing that lacks many necessary features, demands the use of publish/subscribe messaging, and will almost certainly be obsolete within the year, when long-polling, the “critical core” of Bayeux, goes out of style.

On the other hand, the API for bi-directional communication has been known for more than forty years. It’s a socket, and it supports open, close, send, and receive. Long polling happens to be one way to implement the receive method, and as Alex suggests, it’s far from the best. We already know we want nothing to do with the current methods of communication a few years down the line, so let’s stop trying to standardize a communication protocol and instead choose a good API. Why on earth would we have to hem and haw on the ideal standard Comet API when it’s so clearly a TCP Socket, and in fact already defined in HTML5? I say, declare the TCPConnection as the base for Bayeux’s communication and be done with it. When all the browsers support bi-directional communication, preferably via the actual TCPConnection specification, then we can throw out all the hacks and get on with our life. And in the meantime, the rest of us aren’t saddled with the publish/subscribe layer that’s a useless burden to many applications.

It makes the most sense to say that a standards-compliant Comet server is something that serves some JavaScript that exposes the TCPConnection API. How the JavaScript actually implements that is something that we can “compete about”, as the Bayeux authors like to put it, but higher level functionality like publish/subscribe or application-specific protocols can be implemented on top of the TCP socket. Developers just want a socket. It’s unrealistic to foist a messaging protocol API on everyone and say “live with it.” Not all developers want it. Those who want a messaging API (ala Bayeux) can use go use one, and it won’t hurt the rest of us.

Of course, Bayeux also tries to allow interoperability between an arbitrary client and server. I detailed previously exactly why I think that this is absolutely the wrong target for public standardization, because the important interface is between applications developers and a Comet implementation, not between Comet servers and clients. That said, we would do well to have our own APIs and even protocols that allow us to share client side code. In particular, we need a Comet transport API that defines a simple interface for connecting to a remote server, identifying the connection to that server, and receiving data. It also makes sense to allow an implementation of this API to specify an upstream communication mechanism. A Comet client would really just be an implementation of a TCP socket built on top of the Comet transports. If Orbited defined a fast new Comet transport, anyone’s Comet TCP implementation could use the code without modification.

The story I’m outlining for interoperability is that your browser-side application includes a comet.js from the Comet server, which exposes the TCPConnection API. If you want a new Comet server, just start it up and link to that new server’s comet.js file. In the end, the interface is always the same. If developers want publish/subscribe, then they can use Bayeux, which would be built on the TCPConnection interface. This is the ideal world for application developers, and even for the Bayeux authors who want to push a particular mode of interaction for Comet. They can worry about publish/subscribe but have a reasonable communication layer. This would work out well for server developers too, as we would probably end up sharing much of the comet.js code that implements the transports and protocol necessary to expose the proper interface, but we wouldn’t muddy the waters for the general public—they’d just have a single interface to worry about. In the end, we’ll get some kind of native TCP connection in a browser, and suddenly Comet is irrelevant, and our applications continue to work, but even more efficiently.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Synchronous Web Frameworks and Comet

by Michael CarterFebruary 26th, 2008

Simple integration with current technologies is a very real problem standing in the way of widespread Comet adoption. Developers are trained to use a language or framework like PHP, Django, or Rails, where all state information is pushed into the database. There is generally no state beyond what’s needed for the duration of the request. But real-time applications need to keep track of more information and access it more often. Even some very trivial functionality is difficult to integrate with these frameworks.

Consider a Comet application where the application broadcasts a single piece of information every thirty seconds. An administrator can change that piece of information by logging into the application via a web-based GUI. Given a framework like Django, the GUI would be obviously simple to make. But what about the timer? This involves creating a separate thread for the timer itself, and could potentially be complicated depending on kind of server Django happened to be running on top of. This simple app turns out to be very hard to implement in practice due to the nature of synchronous web frameworks.

The timer may seem trivial, but what if your app needs to keep track of connection state? The application could send a PING command out to all of the clients every 30 seconds. If the application doesn’t get a reply (via an XHR requests, let’s say) before the next ping is broadcast, then that browser would be considered disconnected. There is a very real need for this type of feature in many Comet applications, but it is particularly hard to implement with synchronous frameworks.

This could be solved with two steps:

  1. 1) Having the Comet server handle connection state, including pings and ping responses.
  2. 2) Having the Comet server make HTTP callbacks to the application when timeouts occur.

Now the application need only implement a timeout callback as a particular URL, like any other function of the web application; it’s just an HTTP request with some form parameters. The application can make a note of that disconnect in the database, or inform the other clients as needed. It could even store undelivered messages (from the body of the callback request) in the database for future delivery. The best part is that no timers or any other complicated mechanisms are needed.

In Orbited 0.4 we are including some pre-defined callbacks to make development with synchronous frameworks much easier. These callbacks include message delivery success/failure, signon, and signoff/timeout. We have future plans to include publish/subscribe-specific callbacks so that the web application need only implement a single URL as the publish callback if it needs to react to published information. We also are including callbacks for authentication, which will make it trivial to tie publish/subscribe security to the application’s pre-existing authentication framework.

I believe that the future of widespread Comet adoption is to provide a scalable server that can be easily integrated with existing methods and technologies. No one wants to completely re-learn web development, but they may be willing to learn a couple simple steps towards achieving Comet integration. Providing a simple mechanism to integrate real-time functionality with PHP, Rails, or Django will be a huge win for the Comet community.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Colliding Comets: Battle of the Bayeux Part 4

by Michael CarterFebruary 15th, 2008

In part 4 of this series on Bayeux, Michael responds to Greg’s rebuttal from part 3.

Part 1: Greg Wilkins explains the need for Bayeux
Part 2: Michael Carter criticizes the current state of Bayeux
Part 3: Greg Wilkins responds to Michael Carter
Andrew Betts’ thoughts (from a related article)
Part 4: Michael Carter responds to Greg Wilkins
Part 5: Kris Zyp’s thoughts
Part 6: Alex Russell responds to Michael Carter
Part 7: Michael Carter responds to Alex Russell

Introduction

I approached this dialogue initially by imagining an ideal Comet protocol, and then I pointed out how Bayeux differs from that protocol. Greg believes that Bayeux’s only flaw is a lack of documentation, and that if I fully understood Bayeux, I wouldn’t have any problems. While I certainly don’t pretend to possess the same knowledge as the authors of Bayeux, I think that this line of reasoning doesn’t adequately address my concerns, and so I will explain how and why. My first article was somewhat theoretical, as this one will be. But I will also take a look at specific statements from the Bayeux specification and explain how they relate to this discussion.

Framework or Specification

My main point in the section “Cost Without Benefit” in my previous article is that supporting the Bayeux specification costs developer resources, but most of the features of Bayeux are unnecessary for a Broadcast application. Greg replies, “But broadcast does need a very important feature of Bayeux: transport negotiation!” I concur, transport negotiation is very important, and our final standard should contain it. But pointing out one feature of Bayeux that broadcast applications would need isn’t sufficient to justify using the protocol when it is chock full of unnecessary features.

This point on its own might not be enough reason to rework Bayeux, but it represents an alarming trend in the rhetoric coming from Bayeux supporters. I’ve heard many times, as Greg put it, “Bayeux is not a framework, it is a specification.” And it makes good strategic sense to try to write a specification for a standard as opposed to a framework, as frameworks tend to fracture a community whereas standards can do the opposite.

But when defining a protocol, the designers must be exceptionally cautious of feature bloat. Every required piece of functionality is another hurdle to actually implementing the protocol. The first priority of a specification is to explain to developers how it should be implemented, whereas a framework’s first priority is to provide a slew of features in an easily understandable API. Frameworks are for developers-as-users whereas standards are for developers-as-developers. But while the Bayeux supporters want to call it a specification, many end-developers have gotten the impression that they should treat it like a framework.

In a previous musing I said that “The point of any standardization is to allow interoperation between moving parts in a system…[Bayeux] defines the separation between moving parts to occur at the network edges.” Bayeux’s domain, therefore, is those developers who are implementing the communication layer between the browser and the server. As a Comet server developer, I am the implicit target of Bayeux. Application developers on the other hand don’t care about the communication protocol. They only care about a framework—a convenient API with every feature they could want. This is very similar to the way in which web application developers want a framework like Django or Ruby on Rails, but don’t care about specifics of the HTTP communication protocol.

So which is Bayeux, a specification or a framework? As Greg said, they “don’t expect that many developers will implement Bayeux, unless they have some new idea, language, transport etc.” Besides the fact that we wouldn’t want them to re-implement Bayeux just because they thought of a new transport, I doubt a developer could even have some new idea without first fully understanding the specification, probably because they’d implemented either the server or client side previously. The long and short of it is that if a developer, like me, has a problem with Bayeux, the response is that it’s not really meant for a developer like me to implement. This is a dangerous precedent as it limits Bayeux’s developer base basically to the people who designed it, or developers with identical priorities and an identical set of most-likely use-cases.

The Bayeux authors are trying to skip the middle man and cater directly to end-users. Even though Bayeux’s implicit domain has nothing to do with application developers, the designers have gone out of their way to include feature unnecessary for basic HTTP push. These are framework features, and there has been a general understanding that these features mean that Bayeux is some kind of standard for the masses.

I don’t think this is necessarily an isolated phenomenon. In Greg’s article he seems to imply that we should actually treat Bayeux as a framework when he asks, “And how many of us really use all the features of the frameworks that we have at hand?” The answer is that we often don’t use all the features of a framework. But how about this for a contrasting question: And how many of us really use all the features of Internet Protocol? I certainly use each and every feature of Internet Protocol whenever I do anything on the internet, as do you, the reader, just by reading this article. That is because the designers of IP guarded very carefully against feature bloat, promising nothing but the bare essentials necessary for application/protocol designers to efficiently implement any functionality they required on top of IP. So instead of redefining a network stack from the ground up, the HTTP protocol just bases its communication on TCP and IP.

Bayeux is very clearly trying to play the role of a framework even though it is technically a specification. The result is that it’s a bad communication protocol and a bad framework. A good framework, after all, would have long ago published a standard API and worked out a method for third-party, client-side transport discovery. And a good communication protocol wouldn’t utilize publish and subscribe messages as communication primitives while forgetting to include basic reliability and message ordering guarantees. My entire previous article shows in depth exactly why Bayeux is a bad communication protocol, and I have yet to see any evidence to the contrary. It seems that the general mindset when defining Bayeux functionality has tended towards showing that a feature might be desirable in some situation. This is alarmingly similar to process we’d want when designing a framework, but hardly resembles the cold and rigorous approach of cutting down features when designing a communication protocol. If anything my critique is that Bayeux bites off far more than a single communication protocol could chew.

Performance

In the section “Cost and More Cost” I outlined a situation where the communication primitives established by Bayeux are actually a burden to support. My argument is that Bayeux lacks a simple peer messaging system, and building one on top of the publish/subscribe infrastructure will be a big performance hit. Greg clearly agrees with me, but offers the /service/* channels as a way around the problem. Unfortunately, there is a misunderstanding in what the server is, potentially because I say “server” where I mean “application server”.

A bit of history is of import: when I first approached Comet-style communication and began work on the Orbited project, I spent some time in the #cometd IRC channel where the authors of Bayeux coordinate their efforts. The major reason I avoided implementing Bayeux at that time was that there is no good provision for application <--> Bayeux server communication, aside from treating the application as a Bayeux client itself. The only other provision was to treat a Bayeux server like a framework and write the application as a hook into the Bayeux server. This required a complete Bayeux server implementation in the language of the developer’s choice, and precluded the use of modern frameworks like TurboGears, Rails, Django, and others. This wasn’t a problem for the designers of Bayeux though, because they were the ones who implemented the original Bayeux servers, and so they were able to hook any functionality they wanted directly into the server.

But for those of us treating Bayeux as a specification for a communication protocol and not a server framework, the only alternative was to have the application connect to the Bayeux server as a client itself. And this is exactly why I didn’t bring up the /service/* channel in my previous article: it only allows messaging between the Bayeux client and the Bayeux Server, not peer messaging between Bayeux clients, such as the application server and the browser. It doesn’t mitigate the problem in the slightest as there is still no way to efficiently send messages from the browser to the application over Bayeux except to implement peer messaging on top of the publish subscribe mechanism offered by Bayeux.

Greg does point out that I “correctly [identified] that there is unacceptable cost in having user specific channels for user specific messages.” But Bayeux’s solution with /service/* only half solves the problem, as there is absolutely no way for an application implemented outside of the Bayeux process to send a message directly to a client. So as-is, Bayeux imposes unacceptable performance costs. Until we have a better tool to solve this problem, applications should be implemented within the Bayeux process, as if the Bayeux server was a framework. I have noticed that Bayeux supporters seem to rarely assume that the application server is separate from the Bayeux server, such as Greg’s suggestion to just use the /service/* channels, because that’s probably just not how they think about the problem. Once again we have the protocol/framework dichotomy where the demands of each impact the other.

Greg isn’t really thinking about performance in the same way I am though. His proof that Bayeux performs well is that even if you don’t use Bayeux’s features, aside from its ability to push data, it only costs a request (or, as Kris points out in comments, several requests) to setup those unused features.

As much as I am interested in counting the pennies and saving some real money on bandwidth over the years, I’m more interested in being able to scale my solution to many concurrent users. My point is that Bayeux offers a publish/subscribe framework that has many challenges to scaling. I believe there are some good approaches to scaling a publish subscribe network, but the constraints in such a system are at least an order of magnitude greater than those in peer-messaging. By implementing peer-messaging on top of Bayeux we need to first accept the constraints of publish/subscribe. This is, simply put, backwards. It would be like implementing a one-time search algorithm in a language that required all arrays to be stored in sorted order. Instead of incurring an O(n) cost for the search, we incur an O(nlogn) cost for the sort and the search, when we didn’t even need a sorted list at all.

An Unrealistic Agenda

One advantage of my proposed layered approach to Comet is that the lower tiers make no provision for browser -> server communication. There are many ways to accomplish this, and existing application developers already use them without problems. I was very clear on this point in my previous article: “The worst thing we can do is use the promise of Comet as a carrot, and the Bayeux standard as a stick, and try to force developers to adopt our way of communication with the HTTP server.”

But still Greg states that “if Bayeux is successful in weaning developers off XHR (and wrappers), of getting them thinking of messaging (instead of request/response)… then Bayeux will have done its job.”

I need to be emphatic here that this is not Bayeux’s job. And if it is Bayeux’s job, then adopting Bayeux is a strategic catastrophe for the Comet community. As I previously said, it puts us directly at odds with “millions of libraries and billions of lines of code geared towards supporting query-string encoded client -> server communication as either a form submission or an XHR request.” In fact, I’d go as far as to say that it puts us at odds with the HTTP specification and all of those who support that standard.

The lack of real-time applications is due to developers not knowing how to push data from the server to the browser. Comet versus request/response is not a dichotomy we want to create, because we’ll lose. A layered approach to Comet would allow some basic push capabilities at a lower level, thus allowing developers to choose whichever upstream communication model they want. But it still would provide a good platform to reform the current messaging paradigm at a higher level. Bayeux could very well use the publish/subscribe model, provided there was a lower-level option for developers who simply were not interested.

In short, it makes strategic sense for the Comet standard to closely resemble and interoperate with current standards. We want to be saying, “But Comet is basically HTTP, not some new, strange standard.” Then we’ll have a much easier time gaining widespread adoption.

Multi-frame

The extent of Greg Wilkins’ arguments in his first article is that specifications can solve many problems, and Bayeux is a specification, so therefore Bayeux can solve many problems. He puts a lot of stock in the idea that Bayeux is ideal because it solves the problem of multi-frame Comet operation, also known as the 2 connection limit problem. But the reality is that Bayeux has at best the most minimal support for overcoming this problem. Section 8 of the Bayeux specification describes “Multi frame operation”. All it says is that the Bayeux server or client should set a cookie as a marker that a particular client already has a connection open to a particular server. Then, if a second connection is necessary, one of the two should fall back to polling. Here is the exact content that describes how a client should handle multi-frame operation:

8.2 Client Multi frame handling

It is RECOMMENDED that Bayeux client implementations use client side persistence or cookies to detect multiple instances of Bayeux clients running within the same HTTP client. Once detected, the user MAY be offered the option to disconnect all but one of the clients. It MAY be possible for client implementations to use client side persistence to share a Bayeux client instance.

It’s very possible that the Bayeux authors have some great ideas about this, but those ideas haven’t yet made it into the publicly published standard where I can read it. As-is, the whole section is mostly a big hand-wave. There is no explanation on how to detect connections across domains. What if I’m connected to ten different Comet servers? I can’t think of any “client side persistence” mechanism that would allow clients served from different domains to all store and read data from the same place, much less work in all major browsers. Furthermore, without the exact description of what data should be stored, all of those Bayeux connections would necessarily need to be the same version of the same client. What’s the point of the standard if we all have to use the same client?

I understand this is a hard problem, and even Greg admits at the end of his first article that “the solutions for multi-tab are still very rudimentary”. But his entire first article does seem to be directed towards solving the two connection limit, when in reality he only briefly alludes to how Bayeux solves the problem: he suggests that publish/subscribe and transport negotiation may be helpful. I flatly disagree with the suggestion that publish/subscribe has any bearing on the problem. On the other hand, transport negotiation is a good idea that will allow connections to degrade to polling. This is a definite strength of Bayeux, and I think our final standard should have transport negotiation.

Transports

That brings us to the issue of defining transports, or rather the lack of specification in that area. Greg shares with us that

[Bayeux] recognizes that we are not all going to agree on long polling or streaming, or on stopping innovation on new transports. So transport is negotiable in Bayeux.

Upon close inspection, the current Bayeux standard specifies how a few transports should work, but provides no provision for integrating new transports with the specification. Transport negotiation just defines a method by which the client and server agree on a transport, but says nothing about the API a transport should support. Indeed, I can invent a telepathic transport, but I have to then guess as to how it fits into the Bayeux client. If we ask the Bayeux authors about it, we’ll get the response that “These are concerns that framework and server developers can innovate, differentiate and compete about.” But its not acceptable for the Bayeux authors to be even slightly vague with this crucial section of the specification. We need to know exactly what JavaScript API a transport should have, and how that transport can identify itself to the JavaScript Bayeux client. Without this information, we are left to a free-for-all of inventing “competing” methods of identifying new transports in our frameworks. We could all just assume the Dojo implementation as a model for Bayeux, but then we might as well also throw the written specification out and just agree that Bayeux is Dojo.

To JavaScript (or not to JavaScript)

Bayeux recognizes that we are not all going to agree on the same language on the server or the client.

Indeed, the purpose of standards are for platform and language interoperability. But, Bayeux actually makes a pretty big mistake in not standardizing JavaScript as the client language. Whether Bayeux should be a communication protocol or not, it should at the very least be for JavaScript clients, and we should also define a standard API. As it stands, if I write my application for Dojo’s Bayeux, but then someone else creates a new Bayeux client, I couldn’t just switch over to the new client because they would likely not be interoperable. By standardizing the wire protocol and not bothering to standardize the API we make it easy for clients to interoperate with servers, but not for clients to interoperate with applications. The Bayeux standard makes it unfortunately clear, though, that such an API is outside of its realm, as it is a wire protocol intended for browsers and non-browsers alike:

While HTTP is the predominant transport protocol used on the internet, it is not intended that it will be the only transport for Bayeux. Other transports that support a request/response paradigm may be used. However this document assumes HTTP for reasons of clarity.

and

The majority of Bayeux clients will be implemented in JavaScript…

Of course, Bayeux does provide an Unconnected Operation for message dispatch:

OPTIONALLY, messages can be sent without a prior handshake… This pattern is often useful when implementing non-browser clients for Bayeux servers. These clients often simply wish to address messages to other clients which the Bayeux server may be servicing, but do not wish to listen for events themselves.

This provision is a false hope though, as it only allows synchronous message dispatch from external servers because it relies on HTTP. A much saner protocol would allow us to dump as many message requests as we wanted without receiving any of the responses. We’d simply put an ID on each request and the server would respond as it was able. Without this provision, throughput would be severely limited. If you opened 10 connections to the Bayeux server from your app, and each one had a round-trip latency of 200ms, the most messages you could dispatch would be 50/second. You can easily perform this calculation once you realize that the round-trip latency directly affects throughput. The number of messages you can deliver each second is just one second divided by the round-trip latency. So with 200 ms latency you can deliver only 5 messages a second.

At the very least I think we should stop pretending that Bayeux is anything more than a collection of browser-based JavaScript methods of push.

Data format

Bayeux recognizes that not everybody is a JSON fan, and while the content of the Bayeux messages is specified in JSON, there is no requirement that they are sent as JSON, and implementation of XML (e.g. BOSH), binary, or telepathic transports would be welcome.

This statement is very misleading—the extent of what it says is that any data format can be encoded in any other data format. We can invent telepathic transports, but we still have to encode some part of the communication in the JSON format. Yes, the application can encode the payload as an XML document, but it’s still re-encoded in JSON for transport. See section 1.4.2 of the Bayeux standard:

conforming Bayeux servers and clients MUST still conform to the semantics of the JSON messages outlined in this document.

Conclusion

I’ve outlined many reasons in these two articles as to why Bayeux isn’t ready. Standardization is of the utmost importance, and I think the people behind Bayeux have made great strides towards creating something useful. But the supposed goal of Bayeux seems in reality to be that of a framework, not a protocol. If this is the case, then the Bayeux authors would do well to rework their standard into an API proposal. This would provide many more benefits in line with their goals. If, on the other hand, they really do want Bayeux to be a communication protocol, then they should get serious and drop any efforts to target application developers.

Overall though, there has clearly been a lack of perspective in the design process of Bayeux. It is very easy to start optimizing towards a particular use case, and for many projects that is the right and obvious approach. For a standardized protocol though, the designers must be extraordinarily careful that they create a technology that is robust enough to withstand the test of time. If they do not, then a whole new set of de-facto standards will evolve, ultimately displacing the original standard. If we tackle this problem now then we can avoid multiple years of setback.

The only reasonable approach to this problem is layering the protocol. This is not something that can happen on top of or underneath the Bayeux protocol as is. Layering doesn’t mean you adopt a monolithic standard for Jabber over HTTP (see BOSH), and then put another monolithic standard on top of it. This is one idea Greg puts forth, and indeed it is layering, but what’s the point? You get none of the advantages of having flexible, discrete layers as I outlined in my previous post.

Every single concern I’ve brought up can be solved by simply defining multiple standards with different domains. Bayeux is a perfectly reasonable high-level protocol or framework API, provided we jettison all the specific communication mechanisms it defines. After all, splitting the framework-like features of Bayeux away from the communication protocol features is the only way that Bayeux could possibly satisfy Comet server developers (like me) and application developers who want to use Comet. The crux of the issue is actually pretty simple, as I discuss in Should Bayeux be a Communication protocol?. Pay close attention though, because I don’t actually believe we should have only a protocol, or only an API standard. Rather, Bayeux is trying to look like both, but it should make a choice and leave room for the other. Given Bayeux’s feature set and the general philosophy of its creators, I suspect its place is that of an API standard.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]