ZeroMQ: What You Need to Know Braindump

In a recent email conversation, I was asked about getting started with ZeroMQ by another Rubyist (the awesome Ilya Grigorik)

This was my caffeine addled response, which others may find useful as well:

I'm going to warn you, some things you hear when you first read about ZMQ sound crazy. If there's one thing to be said for ZeroMQ, it's this sentence, from the Mongrel2 book "[ZeroMQ is] sockets the way programmers think sockets work". 

The more time I spend with ZeroMQ, the less I can think of a reason I'd ever have to open up a raw TCP or UDP socket, except in extraordinary circumstances, again. I think of ZMQ as common IPC and network communication patterns abstracted into messages and sockets that don't require a broker infrastructure. The whole message queue aspect of it is great, but ZMQ is really designed for a whole range of situations you'd never use AMQP for, and IMHO, that's the truly interesting thing about it. You don't really run ZMQ brokers (mostly), you communicate socket to socket using queue semantics.

The mongrel2 book has the most concise rundown of ZMQ, and IMHO best frames how to use it properly. It's not very in depth, maybe 15 minutes of reading, but is probably the single best introduction to ZeroMQ.

http://mongrel2.org/doc/tip/docs/manual/book.wiki#x1-590005.2

After that, I'd read the rbzmq rdocs for ZMQ::Socket. It's actually a fantastic rdoc, and a better intro to ZMQ than a lot of the docs on the official ZMQ site. It's kind of sad that someone wrote that fantastic doc and it doesn't get any publicity.

Another good post on ZMQ is this blog post:

The mongrel2 project would probably be the best example of a project that really is aggressively using ZMQ in an interesting way. You could check out the m2r ruby adapter to get an idea about ZMQ use in an actual app: http://github.com/perplexes/m2r . You may notice a lot of people using ffi-rzmq rather than the zmq gem. They're almost completely compatible at the API level, except ffi-rzmq works on non MRI/YARV rubies. I'm personally using it exclusively. 

The project I'm working on, dripdrop. is just a simple serialization format and reactor api on top of ZMQ, to make building an app out of a lot of ZMQ building blocks easy, and as much of the tedium out possible. It initially started because I wanted a simple async interface to events on multiple servers running Rails, but I think it made me realize ZMQ needs a proper super-simple API, preferably one that integrates non-ZMQ exit points, like HTTP,  Websockets, XMPP, etc.

DripDrop is still definitely still at the playing around with different ideas stage, and isn't really stable yet. I'm happy with the serialization format though (which is pretty much just BERT with a header for PUB/SUB filtering at the ZMQ level, similar in approach to mongrel2's format, but using BERT). I already have plans to redo about most of it, and need to start adding in support for socket types other than pub/sub. I really do like pub/sub though, it may not have the right semantics as far as making sure messages get delivered, but it enables semi-aspect-oriented architectures where random other processes can hook into a message stream (am I abusing the term aspect-oriented?)

What I plan on working on is redoing it style-wise into a simple DSL like this (this is a simple forwarder that uppercases and copies everything to a websocket and a ZMQ pub socket as an example):


I like the conciseness of this, I can see integrating ZMQ, HTTP, Websockets and other protocols in an async fashion, using this style of API, as worthwhile. What do you think? Biting off too much?

Anyway, I've clearly had too much coffee :)

App monitoring/messaging with ZeroMQ + Ruby = dripdrop

I just this week had an idea for realtime app stats/messaging using ZeroMQ. I wanted to be able to view events from my app in real time, and be able to archive them or do any random thing with them. Hence, dripdrop was born. It's a pretty cool way of doing collecting stats or performing async tasks. There's a full description of it on the GitHub project page at: http://github.com/andrewvc/dripdrop.

I'm mostly leveraging the awesome libraries that are zmq, zmqmachine, bert, and em-websocket.

I've diagrammed my use case for it below:

ZeroMQ, It's a big deal

ZeroMQ's got some interesting ideas, but unfortunately hasn't quite gotten the press it deserves. I'm just starting to toy around with it, mostly due to Zed Shaw's use of it in Mongrel2. Regardless of Mongrel 2, ZeroMQ IS fascinating. Why? A few reasons. I'll get to some of them in a bit, but first I'll let this short block of text from the ZMQ::Socket class's Ruby docs explain why:

Generally speaking, conventional sockets present a synchronous interface to either connection-oriented reliable byte streams (SOCK_STREAM), or connection-less unreliable datagrams (SOCK_DGRAM). In comparison, 0MQ sockets present an abstraction of an asynchronous message queue, with the exact queueing semantics depending on the socket type in use. Where conventional sockets transfer streams of bytes or discrete datagrams, 0MQ sockets transfer discrete messages.

0MQ sockets being asynchronous means that the timings of the physical connection setup and teardown, reconnect and effective delivery are transparent to the user and organized by 0MQ itself. Further, messages may be queued in the event that a peer is unavailable to receive them.

Conventional sockets allow only strict one-to-one (two peers), many-to-one (many clients, one server), or in some cases one-to-many (multicast) relationships. With the exception of ZMQ::PAIR, 0MQ sockets may be connected to multiple endpoints using connect(), while simultaneously accepting incoming connections from multiple endpoints bound to the socket using bind(), thus allowing many-to-many relationships.

The full ZeroMQ Ruby docs are a good read, as are the papers on http://www.zeromq.org/.

So, why else go ZMQ? Well, it's got interchangeable transports. ZeroMQ supports ultra-fast inter-thread messaging, inter-processĀ  communication, TCP, and multicast, as supported transports.

These messages can be exchanged between any language that support ZMQ, at the moment, that's all your faves, from C/C++ to Java, to Ruby, to Python, and more.

Another good source for ZMQ info is this excellent post on Nicholas Piel's blog. Resplendent with diagrams and wonderful explanations.

At any rate, I'm just getting started with ZMQ, as my ZMQ exploration continues I'll update this blog.