Introduction to ZeroMQ networking patterns

Page contents

What is ZeroMQ?

At its core, ZeroMQ (aka zmq) is a library of messaging components useful for transferring information between two or more applications. These can be anything, from two processes on the same machine to hundreds of servers communicating over the internet. ZeroMQ is built on top of traditional networking technologies like TCP sockets and automatically handles their limitations like splitting large messages into multiple TCP packets for transfer, but adding them back together before the other side processes them as a single message again. It also optionally allows authentication and encryption, although the verification of credentials needs to be implemented by the developer as well.

It aims to be minimal and only handles networking, without making any assumptions of the business logic implemented on top of it. This makes it powerful and flexible at the same time, giving all the freedom of choice to the developers who use it.

PAIR (bidirectional one-to-one)

The simplest form of networking offered by zeromq is the PAIR socket type, allowing communication in both directions between exactly two sockets. This is almost identical to plain TCP networking, but with some added benefits like automatic message chunking/merging for larger messages and support for encryption and authentication. Using PAIR sockets is typically used for tightly coupled pairs, like communicating processes or threads, but networked usage is also possible.

PUB/SUB (one-to-many broadcasting)

The publish / subscriber pattern is available in zeromq through the PUB (publisher) and SUB (subscriber) socket types. A PUB socket acts as a server, that one or more SUB sockets can connect to. The publisher can send messages to "topics" (any arbitrary string, think of it as custom categories), and subscribers can decide what "topics" they want to receive messages for. Subscribers receive all messages published in their subscribed topics, but only if they are connected in time - messages sent before connecting are not stored or repeated for them.

Pub/sub is a great pattern for situations where you need data from one point to be broadcast to many others, for example to broadcast notifications like weather warnings to many mobile devices of people living in the danger zone.

PUSH/PULL (one-to-many or many-to-one load-balancing)

The need to balance work across multiple workers is common to many networked applications, and zeromq offers a builtin solution in the form of PUSH and PULL sockets. The PUSH socket distributes messages evenly across all connected PULL sockets, in a round-robin fashion. A PULL socket simply receives messages and processes them. These two sockets can be combined in two ways: fan-out and fan-in.

Fan-out means a single PUSH socket acts as a load balancer to evenly process a set of tasks across multiple connected PULL sockets (one-to-many). Fan-in is the inverse of this, where many PUSH sockets all send messages to a single PULL socket (many-to-one), useful for collecting the results of previously load-balanced jobs or tasks like sending logs from many devices to a central logging server.

REQ/REP (synchronous many-to-one)

Patterns similar to that of web servers is possible through REQ and REP sockets. In this scenario, a REQ socket is a client making a request to a REP socket, blocking until it receives a response. This can be repeated any number of times, mirroring the common client/server model in use by many networking services today.

A REP socket can be used by multiple REQ sockets, but will only process one at a time (synchronous), blocking all the others in the meantime. For services with little computational overhead per request or low traffic this is fine, but starts to become problematic with growing connection counts or increased latency, for example if a single response takes some time to complete.

ROUTER/DEALER (many-to-many custom communication)

For anything not covered by the previously discussed message transfer patterns, zeromq provides a last resort, namely the ROUTER and DEALER sockets. These sockets are intentionally less opinionated about the direction and circumstances of communications. They work by first defining a ROUTER socket, which acts as a central proxy for messages from or to DEALER sockets. The difference to all other forms of sockets is, zeromq doesn not bring business logic to dictate how.

Want to use a ROUTER as a load balancer from many publishers to many workers? Or only send data from the DEALERS to the ROUTER? Perhaps even set a unique ID for each DEALER and add that to every message, so the ROUTER can proxy messages between DEALER sockets directly? These socket can do it all.

The ROUTER and DEALER sockets are highly customizable and enable developers with more specific needs to build their own communication platform on top of the quality of life tooling of zeromq. You could even build your own message queuing server if you want to!

More articles

Finding common bugs with valgrind

From memory leaks to race conditions

How attackers hide backdoors in web servers

Understand and detect post-exploitation changes

Production-ready wordpress hosting on docker

Complete with SSL certificates, backups and upgrades