Fork me on GitHub

PubSubbin' with Redis, EventMachine, and WebSockets

I started looking at the capabilities of Redis and I came across an interesting feature released with v2.0: publish-subscribe. I was using Ruby to interact with Redis and it occurred to me that I could whip up a quick web based push system using WebSockets. So I hacked one up.

Dependencies

Redis

Redis is an advanced key value store. It supports a few key data structures: key-value with strings, hashes, sets, and lists to name a few. Redis is blazing fast, persistent, atomic, and asynchronous. Redis is a good supportive data store giving you a place to put those odds and ends of your application that aren’t really worthy of a table in a RDBMS. Not to say that it couldn’t be used as a full fledged data store (see: Redis Twitter clone example) but sometimes a relational data store is best. In Redis 2.0, the developers have implemented a publish/subscribe messaging paradigm. Redis allows you to subscribe to a specific channel or multiple channels. You can also specify a pattern or series of patterns that you can subscribe to.

EventMachine

EventMachine is an event-processing networking library. EventMachine lets you write clients and servers without the hassle of dealing with sockets. Plus, there is a WebSocket extension that lets you easily interface with WebSockets on the client side.

WebSockets

WebSockets is a long-polling and full-duplex, HTTP-based connection from the user’s web browser to the server. Keeping this connection open is what allows real-time push updates to the browser. Not all browsers support Websockets, but as it is a part of the HTML5 spec, it won’t be long before all browsers support it. For my purposes, this is acceptable because I’m using Chrome.

The App

Using the above technologies I was able to have a browser receive push updates in real-time. Here is how the code works: 1. The Redis channel is subscribed to. Upon receiving a message to this channel I send the message on all the clients that have connected. 2. The WebSocket connection is created. Upon connection, the socket is added to my array of open sockets to clients. 3. When a messsage is published in Redis to the ‘ws’ channel and then it is pushed to all members that are subscribed to that channel. 4. The message is then pushed out all the connected browsers via WebSockets.

It would be easy to substitute WebSockets for a Flash based solution that can receive push updates too so that it can degrade gracefully.

The Codez

Here is the basic HTML page:

Here is the code that runs on the back end:

I have enclosed the EM event loop and the Redis subscribe block in their own threads so that this can be loaded or required in an irb instance.

Presuming that you have redis-server running in the background using it’s default configuration (I just built it and ran it from the build directory) you should be able to open a websockets enabled browser and navigate to websocket.html. It’s going to be an ugly white page (this is just a proof of concept) so don’t expect anything fancy. Then in another irb instance you can type:

require 'redis'
@redis = Redis.new(:host => '127.0.0.1', :post => 6379)
@redis.publish 'ws', 'Something witty'

As soon as you press enter, the message is pushed directly to redis, picked up by our subscribe block and then pushed out to all the listening clients. All this in real-time without polling JavaScript.

Conclusion

The Publish-Subscribe in Redis is pretty solid and fast. I know there are other pub-sub techs (XMPP being the one that I’ve heard a lot about, but that’s for another blog post) out there but I started this out just looking at the capabilities of Redis as a whole, but it it evolved into a real-time web push experiment. That being said, the future of apps in the browser is very bright. With WebSockets and Web Workers, the capabilities of what can be done in a browser are becoming more and more competitive with their desktop equivalents. With technology like WebSockets being able to handle real time push, I feel that the browser is far from dead.

Update 2011-02-11: Changed redis local variable to an instance variable.

Comments

Post New Comment »

Loading....