|
|
Subscribe / Log in / New account

Development

0MQ: A new approach to messaging

January 20, 2010

This article was contributed by Martin Sustrik & Martin Lucina

BSD sockets have been used in thousands of applications over the years, but they suffer from some limitations. The low-level nature of the socket API leads developers to reimplementing the same functionality on top of sockets over and over again. Alternatives exist in the form of various "I/O frameworks" and "enterprise messaging systems" but both of these approaches have their own set of drawbacks. The former are generally bound to a certain programming languages or paradigms, while the latter tend to be bloated, proprietary solutions with resident daemons that hog system resources.

0MQ ("Zero-Em-Queue") is a messaging system that tackles these issues by taking a different approach. Instead of inventing new APIs and complex wire protocols, 0MQ extends the socket API, eliminating the learning curve and allowing a network programmer to master it in a couple of hours. The wire protocols are simplistic, even trivial. Performance matches and often exceeds that of raw sockets.

A client/server example

Let's have a look at a trivial example of 0MQ usage. Say we want to implement an SQL server. The networking part of the code-base is fairly complex; we have to manage multiple connections in a non-blocking fashion, a pool of worker threads is needed to send large result sets in the background allowing the SQL engine to process new requests in the meantime, and so on.

Here's how we can accomplish this using the 0MQ C language bindings:

    #include <zmq.h>

    int main () 
    {
        void *ctx, *s;
        zmq_msg_t query, resultset;

        /* Initialise 0MQ context, requesting a single application thread
           and a single I/O thread */
        ctx = zmq_init (1, 1, 0);

        /* Create a ZMQ_REP socket to receive requests and send replies */
        s = zmq_socket (ctx, ZMQ_REP);

        /* Bind to the TCP transport and port 5555 on the loopback interface */
        zmq_bind (s, "tcp://lo:5555");

        while (1) {
            /* Allocate an empty message to receive a query into */
            zmq_msg_init (&query);

            /* Receive a message, blocks until one is available */
            zmq_recv (s, &query, 0);

            /* Allocate a message for sending the resultset */
            zmg_msg_init (&resultset);

            /* TODO: Process the query here and fill in the resultset */
            
            /* Deallocate the query */
            zmq_msg_close (&query);

            /* Send back our canned response */
            zmq_send (s, &resultset, 0);
            zmq_msg_close (&resultset);
        }
    }

This example shows us several basic principles of 0MQ:

  • 0MQ transports data as messages, represented in this example by zmq_msg_t. 0MQ considers a message to be a discrete unit of transport, and message data as an opaque blob. This is considered a deliberate improvement compared to systems like CORBA with their 1000+ pages of core specification. Developers can always use a third-party library such as Google protocol buffers if they do not wish to write custom serialization code.

  • 0MQ supports different socket types which are specified at socket creation time and implement different messaging patterns. In this example we use ZMQ_REP which stands for the replier pattern, meaning that we wish to receive requests from many sources and send replies back to the original requester.

  • zmq_init() has two arguments related to threads. The first argument is the maximum number of application threads that will access the 0MQ API. The second argument specifies the size of the I/O thread pool 0MQ will create and use to retrieve and send messages in the background. For instance, when sending a large result set the send() function will return immediately and the actual work of pushing the data to the network will be offloaded to an I/O thread in the background.

  • For the sake of brevity, error handling has been omitted in this example. The 0MQ C binding uses standard POSIX conventions, so most functions return 0 on success and -1 on failure, with the actual error code being stored in errno. 0MQ also provides a zmq_strerror() function to handle it's specific error codes.

The client code is equally simple (C++):

    #include <string.h>
    #include <stdio.h>
    #include <zmq.hpp>

    int main ()
    {
        try {
            // Initialise 0MQ context with one application and one I/O thread
            zmq::context_t ctx (1, 1);

            // Create a ZMQ_REQ socket to send requests and receive replies
            zmq::socket_t s (ctx, ZMQ_REQ);

            // Connect it to port 5555 on localhost using the TCP transport
            s.connect ("tcp://localhost:5555");

            // Construct an example message containing our query
            const char *query_string = "SELECT * FROM mytable";
            zmq::message_t query (strlen (query_string) + 1);
            memcpy (query.data (), query_string, strlen (query_string) + 1);

            // Send the query
            s.send (query);

            // Receive the result
            zmq::message_t resultset;
            s.recv (&resultset);

            // TODO: Process the resultset here
        }
        catch (std::exception &e) {
            // 0MQ throws standard exceptions just like any other C++ API
            printf ("An error occurred: %s\n", e.what());
            return 1;
        }

        return 0;
    }

This example uses the ZMQ_REQ socket type, which specifies the requester messaging pattern, meaning that we wish to send requests, which may be possibly load-balanced to all peers listening for such requests, and we wish to receive replies to our requests. The example also nicely shows how the 0MQ C++ language bindings map to the native language features and allow us to use exceptions for error handling.

One socket, many endpoints: A publish/subscribe example

Now, let's have a look at another common pattern used in messaging, where one application (the publisher) publishes a stream of messages while other interested applications (subscribers) receive and process the messages.

The publisher application (Java):

    import org.zmq.*;

    class publisherApp
    {
        public static void main (String [] args)
        {
            // Initialise 0MQ with a single application and I/O thread
            org.zmq.Context ctx = new org.zmq.Context (1, 1, 0);

            // Create a PUB socket for port 5555 on the eth0 interface
            org.zmq.Socket s = new org.zmq.Socket (ctx, org.zmq.Socket.PUB);
            s.bind ("tcp://eth0:5555");

            for (;;) {
                // Create a new, empty, 10 byte message
                byte msg [] = new byte [10];

                // TODO: Fill in the message here

                // Publish our message   
                s.send (msg, 0);
            }
        }
    }

The subscriber application (Python):

    import libpyzmq

    def main ():
        
        # Initialise 0MQ with a single application and I/O thread
        ctx = libpyzmq.Context (1, 1)

        # Create a SUB socket ...
        s = libpyzmq.Socket (ctx, libpyzmq.SUB)

        # ... ask to subscribe to all messages ...
        s.setsockopt (libpyzmq.SUBSCRIBE , "")

        # ... request the tcp transport with the endpoint myserver.lan:5555
        s.connect ("tcp://myserver.lan:5555")

        while True:
            # Receive one message
            msg = s.recv ()

            # TODO: Process the message here
     
    if __name__ == "__main__":
        main ()

As with our previous examples, we have deliberately omitted error handling and processing code for the sake of brevity. Error handling in both the Java and Python bindings is implemented using native exceptions.

These examples demonstrate the following:

  • Message subscriptions using the setsockopt() call. Using this call the subscriber indicates that it is only interested in the subset of messages sent by the publisher starting with the specified string. For example, to subscribe to only those messages beginning with ABC we would use the call:

        s.setsockopt (libpyzmq.SUBSCRIBE , "ABC")
    
  • To boost performance 0MQ subscriptions are simple plain strings rather than regular expressions, however, you can use them for simple prefix-style matching where a subscription to animals. would match messages such as animals.dogs and animals.cats.

Now, let's look at a more complex scenario such as one that is often encountered in the stock trading business. We want to send a high volume message feed of stock prices to multiple applications, some of which are located on our local LAN and others which are located at branch offices connected via slow and expensive WAN links. The message load is so high that sending the feed to each receiver on our LAN, individually using TCP, would exhaust our LAN bandwidth.

For the subscribers located on our local LAN, the ideal solution would be to use a multicast transport. 0MQ supports a reliable multicast protocol known as Pragmatic General Multicast (PGM) which suits this purpose ideally. Many LWN readers may not have heard of PGM — without going into too much detail here we can say that it's an industry standard protocol specified in RFC 3208 and implemented mostly by proprietary messaging and operating system vendors such as Tibco, IBM, and Microsoft. Luckily, the excellent Open Source OpenPGM implementation exists and is used by 0MQ.

Back to our stock trading example: While using a PGM transport is fine on our local LAN, multicast won't work too well for our overseas offices, so we really want to be able to talk to those using plain old TCP. In terms of code, we want something like this to bind our sending socket to both a TCP port as well as a multicast group:

    s.bind ("tcp://eth0:5555");
    s.bind ("pgm://eth0;224.0.0.1:5555");

This example shows off two major features of 0MQ. First, the ability to bind or connect a socket to multiple endpoints by simply calling bind() and/or connect() more than once. Second, the use of different underlying transports for a socket. 0MQ supports several transports, of which the most important are tcp, pgm, and inproc (optimized for sending messages between threads within the same application). Using the same API for in-process and remote communication allows us to easily move computations from local worker threads to remote hosts and vice versa.

While the example above works, it results in each overseas receiver creating a separate TCP connection to the publisher in our main office which may result in messages being transferred multiple times over the WAN link. What we would like instead is a proxy application that would run at each branch office (ideally directly on it's edge router to minimize the number of network hops, thus reducing latency to a minimum) connecting to the publisher and re-distributing the messages on the branch office LAN via reliable multicast.

For the scenario described above we can use zmq_forwarder which is part of the 0MQ distribution. Running zmq_forwarder with a simple XML configuration file that describes the inbound and outbound connections is all that is needed.

Performance

Of course, none of this is any good if your code runs slowly. Assuming recent and well-tuned hardware, the end to end latency for transferring a small message (64 bytes or less) on a 1GbE LAN using 0MQ is approximately 30-40 microseconds. As for throughput, when transferring a single stream of one byte messages 0MQ achieves rates of up to 3-4 million messages per second.

Observant readers will note that achieving these throughput figures with raw BSD sockets is impossible. The 0MQ approach is to use "message batching" (i.e. sending messages in batches rather than one by one) thus avoiding frantic up-and-down traversal of the networking stack. Thanks to smart batching algorithms, message batching has almost no impact on latency.

The memory footprint of 0MQ will be particularly interesting to embedded developers, as it is much smaller that of conventional messaging systems. For instance on Linux/x86, the core code occupies only a couple of pages in resident memory.

Conclusion

While 0MQ is still a young project which is evolving rapidly, it is an interesting and powerful alternative for those who prefer a messaging system which emphasizes simplicity, efficiency, and low footprint over the complex bells and whistles of most current enterprise messaging systems. Particularly noteworthy is 0MQ's extension of the well known socket APIs and it's ambition to be "just a transport" which gets out of the way rather than yet another bloated messaging or RPC framework.

0MQ is licensed under the LGPL and you can download it on the project website. API documentation is provided in the form of traditional UNIX man pages and help can be found on the community mailing list or IRC channel. The project also has a GIT repository and is accepting contributions from the wider community.

As of this writing, 0MQ runs on Linux, Windows, Solaris, and many other POSIX platforms. Language bindings available include C, C++, Common Lisp, Java, Python, Ruby, and more. Unfortunately, packaging is lagging behind, so community contributions in this area would be very helpful. Due to the closed nature of stock trading systems it's hard to get a handle on actual adoption of 0MQ in the wild, but there is one case study available.

Comments (21 posted)

System Applications

Audio Projects

New Music Player Daemon releases

The Music Player Daemon project has announced the release of mpd 0.15.8 and ncmpc 0.16.1, both components include bug fixes.

Comments (none posted)

Database Software

MySQL 5.5.1-m2 released

Version 5.5.1-m2 of MySQL has been announced. "The new features in this release are of beta quality. As with any other pre-production release, caution should be taken when installing on production level systems or systems with critical data."

Full Story (comments: none)

PostgreSQL Weekly News

The January 17, 2010 edition of the PostgreSQL Weekly News is online with the latest PostgreSQL DBMS articles and resources.

Full Story (comments: none)

Embedded Systems

Android, Linux & Real-time Development for Embedded Systems (Embedded.com)

Embedded.com has an overview of Android development. The article looks at Android capabilities, particularly for non-phone applications, as well as what is needed to port it to non-ARM architectures. The information about "real-time" is essentially a suggestion to run Android and Linux along with an RTOS. "However, it would be better to think of Android as being a software platform for the construction of smart phones, as it is freely available and highly configurable. To be more precise, it is a software platform for building connected devices. [...] Android is an application framework on top of Linux. We will look at the details of the layers of the framework, shortly. It is supplied as open source code, but does not bind the user with the constraints of the GPL — there is no requirement for developers to make public any code developed using Android."

Comments (1 posted)

Interoperability

Samba 3.4.5 and 3.3.10 released

Two new releases of Samba are available. Samba 3.4.5: "This is the latest stable release of the Samba 3.4 series." Samba 3.3.10: "This is the latest stable release of the Samba 3.3 series."

Comments (none posted)

Web Site Development

moin 1.9.1 released

Version 1.9.1 of moin, a wiki system, has been announced, it includes important security and bug fixes. "See http://moinmo.in/MoinMoinDownload for the release archive and the change log."

Full Story (comments: none)

Tinyproxy 1.8.0 released

Version 1.8.0 of Tinyproxy has been announced. "Tinyproxy is a light-weight HTTP proxy daemon for POSIX operating systems. It is distributed using the GNU GPL license version 2 or above. Designed from the ground up to be fast and yet small, it is an ideal solution for use cases such as embedded deployments where a full featured HTTP proxy is required, but the system resources for a larger proxy are unavailable."

Full Story (comments: none)

Miscellaneous

Announcing CoffeeSaint, a Nagios status viewer

Folkert van Heusden has announced the CoffeeSaint project. "CoffeeSaint is a fully customizable Nagios status viewer. It grabs the status from a Nagios server and displays it in a fullscreen GUI. It is written in Java so it should run on all platforms (tested on Linux, AIX 6.1 and windows xp) capable of running Java 5. Also works with OpenJDK."

Comments (none posted)

SystemTap 1.1 released

Version 1.1 of SystemTap, an infrastructure for gathering information about a running Linux system, has been announced. Changes include: "better support for gcc 4.5 richer DWARF debuginfo, new preprocessor conditional for kernel 'CONFIG_*' testing, improved (experimental) unprivileged user support, new tapsets, better local-vs-global variable warnings, better return codes, bug fixes, and more..."

Full Story (comments: none)

Desktop Applications

Audio Applications

Audacity 1.3.11 released

Version 1.3.11 of the Audacity audio editor has been announced. "This release fixes a number of bugs reported to us in 1.3.10. Thank you to everyone who sent us feedback."

Comments (none posted)

Calendar Software

Lightning 1.0 beta1 now available

Version 1.0 beta1 of Mozilla Lightning has been announced. "The Calendar Project is proud to report, that (finally) the 1.0 beta1 release of Lightning has been completed and is now available via AMO[1]. Nearly 16 months after the 0.9, this release is more than overdue and we're more than happy to get the nearly 500 bugfixes and improvements into the hands of our users."

Full Story (comments: none)

Data Visualization

DISLIN 10.0 released

Version 10.0 of DISLIN has been announced, the software is only free for non-commercial use. "DISLIN is a high-level and easy to use plotting library for displaying data as curves, bar graphs, pie charts, 3D-colour plots, surfaces, contours and maps. Several output formats are supported such as X11, VGA, PostScript, PDF, CGM, WMF, HPGL, TIFF, GIF, PNG, BMP and SVG."

Full Story (comments: 1)

Desktop Environments

GNOME 2.29.5 released

Version 2.29.5 of GNOME has been announced. "Here is the first GNOME release for year 2010 and fifth development release towards our 2.30 release that will happen in March 2010. Your mission is easy: Go download it. Go compile it. Go test it. And go hack on it, document it, translate it, fix it."

Full Story (comments: none)

GNOME Software Announcements

The following new GNOME software has been announced this week: You can find more new GNOME software releases at gnomefiles.org.

Comments (none posted)

Day one at Camp KDE 2010 (KDE.News)

KDE.News has a report from the first day of Camp KDE. "Saturday, the first day of Camp KDE 2010 in San Diego, started with a short introduction by Jeff Mitchell. Jeff, who was the principal organizer of the conference, introduced us to a bit of history about Camp KDE and then went into some statistics about the KDE community. The conclusion was that if we maintain our current rate of growth we'll have about 6 billion developers by 2050. Continuing with this theme, he spoke about current topics in KDE such as the migration to Git and the upcoming release of KDE SC 4.4. Jeff then introduced the talks to follow, including the work on KDE-on-Windows, KOffice and KDE technology on mobile devices."

Comments (5 posted)

KDE Software Announcements

The following new KDE software has been announced this week: You can find more new KDE software releases at kde-apps.org.

Comments (none posted)

Xorg Software Announcements

The following new Xorg software has been announced this week: More information can be found on the X.Org Foundation wiki.

Comments (none posted)

Financial Applications

SQL-Ledger 2.8.28 released

Version 2.8.28 of SQL-Ledger, a web-based accounting system, has been announced. Changes include: "1. Version 2.8.28 2. fixed missing cc, bcc when converting sales order to invoice 3. added default value for exchangerate on reports 4. added additional fields for customer/vendor search".

Comments (none posted)

Mail Clients

Sylpheed 3.0beta6 (development) released

Development version 3.0beta6 of the Sylpheed mail client has been announced. Changes include: "* The bug that IMAP caches get wrongly deleted was fixed. * The copyright year was updated."

Comments (none posted)

Thunderbird 3.0.1 is now available for download

Thunderbird 3.0.1 has been released. It evidently contains security fixes, but the list of fixes does not clearly indicate which. Nevertheless: "We strongly recommend that all Thunderbird users upgrade to this release."

Full Story (comments: 2)

Music Applications

arpage 0.2 alpha released

Version 0.2 alpha of arpage, a JACK Synchronizedd Arpeggiator, has been announced. "The UI is still dead-boring GTK, but I've read back over the LAD threads regarding audio-oriented UI libraries and I'm thinking of investigating libproaudio with the next release."

Full Story (comments: none)

fishnpitch - a realtime JACK MIDI tuner

The first alpha release of fishnpitch is available. "It's a small command line tool that creates JACK MIDI ports and allows tuning to arbitrary scales (via .scl files) with any MIDI capable synthesizers. Incoming note messages are translated via pitch bend and distributed among several midi channels."

Full Story (comments: none)

MusE 1.0.1 released

Version 1.0.1 of MusE, a multi-track virtual studio, has been announced. "Right on the heels of big One-O we've decided to release a minor update with some corrections, main features being some package improvements and a midi timing issue when running under very high priority."

Full Story (comments: none)

Qtractor 0.4.4 released

Version 0.4.4 of Qtractor, an Audio/MIDI multi-track sequencer, has been announced. "Release highlights: * LV2 plug-in support (NEW) * MIDI event list view (NEW) * Expedite audio/MIDI clip import (NEW) * DSSI plug-in output control ports feedback/update (NEW) * JACK transport, MMC, SPP control options (NEW) * Self-bounce/recording (FIX) * Audio/MIDI drift correction (FIX) * Anti-glitch audio micro-fade-in/out ramp smoothing (FIX)"

Full Story (comments: none)

Web Browsers

Firefox 3.6 Release Candidate 2 is available

Version 3.6 rc2 of Firefox has been announced. "An update to the Firefox 3.6 Release Candidate is now available. This second release candidate is available for free download at http://www.mozilla.com/firefox/all-rc.html and has been issued as an automatic update to all Firefox 3.6 Beta and Release Candidate users."

Full Story (comments: none)

Firefox 3.6 privacy policy review

Firefox 3.6 is undergoing a privacy policy review. "Firefox 3.6 has some new features, like Personas being part of the browser itself. As such, we have taken this opportunity to review and update our privacy policy. Privacy and data protection are important issues to the people of Mozilla. So we are looking at all the terms of this policy and thinking about how to best use our privacy policy to benefit users. This means you should expect more significant changes in the future. For example, we are considering ways to significantly shorten and simplify this policy."

Full Story (comments: none)

Mozilla dumps Firefox 3.7 from schedule, changes dev process (ComputerWorld)

ComputerWorld reports on an interview with Mozilla's Mike Beltzner about changes in how Mozilla plans to deliver new features in Firefox. "Rather than add features to Firefox only in once- or twice-a-year upgrades, Mozilla will quietly insert some functionality via its regular security updates, which appear every four to six weeks, said Mike Beltzner, director of Firefox, in an interview Thursday. [...] That means Firefox 3.7, which was slated for a second quarter release, has been dropped from the development schedule, said Beltzner. The next version of the open-source browser after the almost-ready Firefox 3.6 will be an as-yet-unnamed update at the end of this year or in early 2011."

Comments (67 posted)

Miscellaneous

XYZCommander 0.0.3 released

Version 0.3 of XYZCommander, a pure console visual file manager, has been announced. "New features: * Python2.4 support * Permanents filters * Custom sorting * High-color mode support with urwid >= 0.9.9 * New command line options: -c colors and -s skin * XYZCommander's system prefix can be set using XYZCMD_PREFIX environment variable in case of custom installation, by default it is equal to sys.prefix."

Full Story (comments: none)

Languages and Tools

Caml

Caml Weekly News

The January 19, 2010 edition of the Caml Weekly News is out with new articles about the Caml language.

Full Story (comments: none)

Perl

Perl 5.11.4 is available

Version 5.11.4 of Perl has been announced. "Perl 5.11.4 is the first release of Perl 5.11.x since the code freeze for Perl 5.12.0. It and subsequent releases in the 5.11 series include very limited code changes, almost entirely related to regressions from previous released versions of Perl or which resolve issues we believe would make a stable release of Perl 5.12.0 inadvisable."

Full Story (comments: none)

Python

execnet 1.0.3 released

Version 1.0.3 of execnet has been announced. "execnet is a small and stable pure-python library for working with local or remote clusters of Python interpreters, with ease. It supports seamless instantiation of remote interpreters through the 'ssh' command line binary. The 1.0.3 release is a minor backward compatible release..."

Full Story (comments: none)

py.test 1.2.0 released

Version 1.2.0 of py.test has been announced. "py.test is an advanced automated testing tool working with Python2, Python3 and Jython versions on all major operating systems. It has a simple plugin architecture and can run many existing common Python test suites without modification. It offers some unique features not found in other testing tools. See http://pytest.org for more info. py.test 1.2.0 brings many bug fixes and interesting new abilities".

Full Story (comments: none)

Python 2.5.5 Release Candidate 1 released

Version 2.5.5 Release Candidate 1 of Python has been announced. "This is a source-only release that only includes security fixes. The last full bug-fix release of Python 2.5 was Python 2.5.4. Users are encouraged to upgrade to the latest release of Python 2.6 (which is 2.6.4 at this point). This releases fixes issues with the logging and tarfile modules, and with thread-local variables."

Full Story (comments: none)

Shed Skin 0.3 released

Version 0.3 of Shed Skin has been announced. "I have just released Shed Skin 0.3, an experimental (restricted) Python-to-C++ compiler. Please see my blog for more details about the release: http://shed-skin.blogspot.com/".

Full Story (comments: none)

stream 0.8 released

Version 0.8 of stream has been announced. "Stream is a module that lets one express a list-processing task as a pipeline and provide ways to easily parallelize it."

Full Story (comments: none)

IDEs

Pydev 1.5.4 released

Version 1.5.4 of Pydev has been announced, click below for the release details. "Pydev is a plugin that enables users to use Eclipse for Python, Jython and IronPython development -- making Eclipse a first class Python IDE -- It comes with many goodies such as code completion, syntax highlighting, syntax analysis, refactor, debug and many others.".

Full Story (comments: none)

Test Suites

Linux Desktop Testing Project 2.0.1 released

Version 2.0.1 of the Linux Desktop Testing Project has been announced. "LDTPv2 a complete rewrite of LDTPv1 in Python. This release is dedicated to Eitan Isaacson. Eitan wrote the LDTPv2 framework and important API's in LDTPv2 !"

Full Story (comments: none)

Version Control

monotone 0.46 released

Version 0.46 of the monotone version control system has been announced. "The highlights in this release are bisection support - thanks to Derek Scherger! - and the possibility to call the automation interface over the network - thanks to Timothy Brownawell! Please note that stdio interface has been changed in an backwards-incompatible way."

Full Story (comments: none)

Page editor: Forrest Cook
Next page: Announcements>>


Copyright © 2010, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds