A somewhat generalized version of the ZeroMQ Majordomo pattern. The main motivation is to support clients or workers which run in threaded environments that will cause problems with non-thread-safe REQ or DEALER.
In which the generalization is described.
The Majordomo pattern or protocol (MDP) consists of a broker bringing clients together with workers via a “service” name in a reliable manner and which allows a high degree of scaling out.
There are a number of versions of MDP “in the wild”. Below is my understanding. Corrections of any inaccuracies are very welcome.
Version 1 (aka 0.1, aka MDPW01
for worker and MDPC01
for client
sub-protocol) of MDP is described in the ZeroMQ Guide and specified in
the stable ZeroMQ RFC 7/MDP. Copies of the Python examples from the
guide, updated for Python3, are in this repository under md/ for
reference (and PR’ed upstream).
Version 2 (aka 0.2, etc for sub-protocols) is specified in draft ZeroMQ RFC 18/MDP. This version extends 7/MDP to allow a worker to reply with a stream of messages. The majortomo (sic) package provides a Python implementation.
A version “0.3” can be found in the libmdp/ directory of zeromq/majordomo and some description of its changes w.r.t. 18/MDP can be found in majordomo#34. To my knowledge it is otherwise unspecified.
Finally, at some point in its git history, this version “0.3” was
changed from hand-coded implementation to one that is partially
generated by Zproto. As that uses the standard Zproto client/server
GSL templates, the packing of messages deviates from 18/MDP. In
particular, there is a leading two byte “signature” (0xAAA4
), the
initial fields described in 18/MDP are packed into a single frame and
zproto message IDs are included in addition to the IDs specified by
18/MDP.
The Generaldomo Package (GDP) generalizes version 1 aka 0.1 aka 7/MDP. GDP is a superset protocol which simplifies to 7/MDP when ROUTER is used for the broker. The extension only applies when the broker uses a SERVER socket. That is, a GDP broker configured to use ROUTER is a 7/MDP broker.
When speaking to a GDP broker using SERVER the worker or client must use the GDP-extended protocol. The differences are as summarized:
- All messages are single-part formed by encoding a 7/MDP multipart
message but omitting the initial “Frame 0: empty frame”. The
encoding is compatible with the CZMQ
zmsg_encode()
function. Specifically, the data of small messages less than 255 bytes are prefixed with a 1-byte size. Larger messages are prefixed by a single byte0xFF
followed by a 4-byte size value. - Worker messages are unchanged except that “Frame 3: Client address (envelope stack)” holds the 32 bit routing ID instead of a string holding the socket ID entity. The Worker should treat this field as opaque data in any case.
The implementation in this repository is heavily influenced by the
nice example code provided in the ZeroMQ guide. Externally it speaks
GDP as described above. Internally it generalizes and factors the
Zguide examples to facilitate using the generaldomo::Broker
class and
the generaldomo::Worker
and Client
API classes from a actor functions.
Examples using a cppzmq-based actor class are included.
The Generaldomo C++17 API requires libzmq
to have been built with
“draft” sockets. The easiest way to do this is by installing from
recent “master” branch of the official repository. ZeroMQ community
tends to keep “master” working well with each commit essentially being
a new release.
$ git clone https://github.com/zeromq/libzmq.git $ cd libzmq/ $ ./autogen.sh $ ./configure --prefix=$HOME/opt/zmq $ make -j$(nproc) $ make install
The cppzmq C++ interface to libzmq
is used by generaldomo C++ library. It essentially consists of two header files which are included directly an no installation is required.
The C++ API installs with waf
. Assuming libzmq
was installed as
above, Generaldomo C++ API may be installed as:
$ wget -O ~/bin/waf https://waf.io/waf-2.0.19 $ chmod ~/bin/waf $ export PKG_CONFIG_PATH=$HOME/opt/zmq/lib/pkgconfig $ waf configure --prefix=$HOME/opt/zmq
The Generaldomo C++ library API is still under development. For now, refer to the tests for working examples.
Generaldomo Python API requires Python 3 and is independent from the
C++ API and library. PyZMQ is required and must provide the “draft”
sockets. Assuming libzmq
was installed as above the following
commands will provide a suitable Python environment in which to
install and use Generaldomo Python API.
$ python3 -m venv /path/to/venv $ source /path/to/venv/bin/activate $ pip install --pre pyzmq \ --install-option=--enable-drafts \ --install-option=--zmq=/path/to/zmq $ pip install -r requirements.txt $ pip install [-e] .
All example programs are exposed through a common generaldomo
CLI.
The simple, self-contained “tripping” example with one or the other “serverish” socket type:
$ generaldomo tripping -n 1000 -f router -b router $ generaldomo tripping -n 1000 -f server -b server
To run the full Majordomo example, run each in three terminals:
$ generaldomo broker --verbose -s server $ generaldomo echo --verbose -s client $ generaldomo client --verbose -n 2 -s client echo hello world
Likewise this trio can be run with the ROUTER/DEALER socket types.
The broker
taking -s router
with echo
and client
taking -s dealer
.