Ideally we'd be able to compose 99designs.com out of several top-level web applications. There are many challenges with this, for instance:
- How do we manage routing and route generation, cross-application?
- How do we manage sessions without shared db access?
- How do we handle shared UI like alert bars and unified headers?
On the whole, these problems are solvable. For routing we could just use Varnish, with some custom code to read routemaps from the apps, or we could use something like Mongrel2. Alternately, a Go-lang HTTP/SPDY terminator would be pretty damn quick and flexible.
The one thing I will say about Mongrel2 is that it appears to be dead and has utterly failed to get traction. Still not sure why, but probably worth not ignoring the writing on the wall.
The other side of the coin is backend service composition. It should be trivial to write and deploy a monitored, robust, stand-alone service for something like exchange rates, private messaging, etc.
For me, the requirements around this are:
Synchronous and asynchronous semantics (request/response, or request with a callback) Streaming support (e.g. request a large binary file as a stream) Minimal code required to expose useful, robust services
Things that we might care about are:
Versioning, or ways to elegantly change the exposed services incrementally without breaking calls "in-flight" Developer friendly (easy to test, no code generation, good language support)
This is the piece I've spent the most time researching, and the options that appeal to me the most are the light-weight RPC mechanisms built over interesting transports (in order of interest):
- https://github.com/blog/531-introducing-bert-and-bert-rpc (this becomes even sexier when you look at Elixer as a language for extending services)
- http://zerorpc.dotcloud.com/
- https://github.com/nathanmarz/storm/wiki/Distributed-RPC
It's worth noting that most of these systems don't seem to have great answers for versioning, but I'm not sure I care.
I've spent a lot of time trying to like Protobuf (et al) and Thrift, but I just can't get past the bulky formats and painful code generation. It makes testing hard and it's ugly.
The other option is to build some sort of central message bus and use that as the basis for RPC/Service communications. In the above, Bert is similar to this in that it's based on Erlang OTP, and Storm is basically a distributed message processing system.
Airbnb wrote an awesome post about this: http://nerds.airbnb.com/smartstack-service-discovery-cloud/
They use HAProxy, combined with Zookeeper (or something similar), such that basically every service is exposed as a port number of the local machine. This makes wiring apps easy.
I'd be tempted to basically use this approach, it's elegant. It would work nicely for RESTful services, I'm not sure how it would work with the above RPC layers, will require some thought.
- http://www.slideshare.net/MaxAlexejev/modern-distributed-messaging-and-rpc
- http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html
- https://blog.twitter.com/2013/braindump
- https://github.com/dotcloud/hipache
- https://engineering.groupon.com/2013/misc/i-tier-dismantling-the-monoliths/
- http://blog.programmableweb.com/2013/02/20/linkedin-opens-rest-li-a-restful-service-architecture-framework/
Extra reading
I think a Go fronted (like gov.uk did) would work pretty well - it could then do some awesome custom stuff like process auth cookies/speak to the auth service and add relevant session info into http headers passed down to the respective systems. could also selectively route unauthed requests through to a varnish cache for perf/authed ones into the real services. Or leave caching down to the individual bits.
Other random thoughts I'm having
And yup, just write mongrel2 off.
I've pulled rest in action off the shelf - I haven't thought super seriously about this stuff for quite a while so don't want to be super prescriptive at all