EventSource Broker

Today I'm releasing a new open-source EventSource Broker. A fast and scalable bridge between the HTML5 EventSource API and an AMQP fanout exchange.

It's written in Haskell and based on the Snap Framework.

While it's still mostly an experiment, I'm looking into replacing Pusherapp with EventSource for Webpop.

WebSockets received a lot of attention after the new protocol first made its appearance in modern browsers, only to mostly fizzle out for a while, when some security concerns intermediary proxies and gateways.

WebSockets, however, is not the only new kid on the block when it comes to client-server communication in the HTML5 spec. By now all modern browsers (no, I still won't count IE amongst them) have implemented the Server-sent Events API.

EventSource is an alternative to WebSockets in the case where full bi-directional communication channel is not needed.

Its biggest difference from WebSockets is that EventSource uses the HTTP protocol and plays well with intermediaries, firewalls, cache proxies and HTTP aware load balancers. This makes EventSource endpoints a lot easier to fit into a normal web architechture. It also makes fallover solutions for older browsers much simpler, since they can simply fall back to long polling.

The EventSource API

Working with EventSource in javascript is incredibly easy. Simply create an EventSource object and set up bindings to your server-sent events.

The Backend - Handling Concurrency

While EventSource is easy and pleasant to work within the browser and plays nice with load balancers and intermediaries, the story is a bit different when it comes to serving up an EventSource endpoint with the typical web stacks.

The typical web framework is written to handle short requests and will crumble under the weight of thousands of long lasting concurrent connections.

This is where Haskell comes in. The Snap Framework takes advantage of Haskell's excellent concurrency constructs and makes it straight forward to write superfast services that can use a mixture of threads and eventloops to handle loads of connections without breaking a sweat. All without the nested callback soup and fragile error handling of something like node.js.

EventSource Broker is a Snap based service that will serve up an EventSource endpoint. It also connects to an AMQP fanout exchange (so far only tested with RabbitMQ).

When a client connects to the /eventsource endpoint it specifies a "channel" it wants to subscribe to and the EventSource broker will pass on all events received from the AMQP exchange with a matching channel.

With this infrastructure in place it's now extremely easy to stream anything from your normal web infrastructure and to your user's browser. Just maintain a connection to RabbitMQ and dump any message you want a user to receive to a queue.

Performance and Scaling

I haven't done any exhaustive benchmarking of the Haskell EventSource. Benchmarking EventSource is not straight forward with the typical HTTP benchmarking tools. Both ab and siege use way more resources per connection when benchmarking than Snap does while responding to the benchmarks. So with a single machine the benchmarking tool becomes the bottleneck way before Snap starts even noticing the load.

A single snap server should easily be able to handle 60.000 connections and memory usage is very low (around 8-10MB for the EventSource Broker with ab hitting it with 100 concurrent connections).

Would love to see suggestions on good tools to benchmark something like this.

The use of a fanout exchange makes the service easy to scale by simply adding more EventSource Brokers and putting them behind a load balancer.

comments powered by Disqus