ZeroMQ XPUB/XSUB Serious Flaw?
Asked Answered
C

2

9

It seems as though the XPUB/XSUB socket types have a serious flaw that is difficult to work around:

XPUBSUB

This is my implementation of that center node:

#include <zmq.hpp>

int main()
{
    zmq::context_t context(1);

    //Incoming publications come here
    zmq::socket_t sub(context, ZMQ_XSUB);
    sub.bind("ipc://subscriber.ipc");

    //Outgoing publications go out through here.
    zmq::socket_t pub(context, ZMQ_XPUB);
    pub.bind("ipc://publisher.ipc");

    zmq::proxy(sub, pub, nullptr);

    return 0;
}

The problem is, of course, slow joiner syndrome. If I connect a new publisher to XSUB and publish some messages, they disappear into the void:

#include "zhelpers.hpp"

int main () {
    //  Prepare our context and publisher
    zmq::context_t context(1);
    zmq::socket_t publisher(context, ZMQ_PUB);
    publisher.connect("ipc://subscriber.ipc");

    s_sendmore (publisher, "B");
    s_send (publisher, "Disappears into the void!!");

    return 0;
}

However, if I sleep(1) after connecting to XSUB, it magically works:

#include "zhelpers.hpp"

int main () {
    //  Prepare our context and publisher
    zmq::context_t context(1);
    zmq::socket_t publisher(context, ZMQ_PUB);
    publisher.connect("ipc://subscriber.ipc");

    sleep(1);
    s_sendmore (publisher, "B");
    s_send (publisher, "Magically works!!");

    return 0;
}

The Guide claims there is a simple solution to this "slow joiners" syndrome, but then never delivers a working synchronized XSUB/XPUB implementation. After much searching it looks like most people are just sleeping, which is really bad.

Why hasn't this ever been fixed? Are there any known workarounds? All my google queries just point me back to the guide...

Cuspidor answered 30/3, 2017 at 22:58 Comment(4)
Would you also have your subscriber code ? One other solution that I could find in the guide was to synchronise the subscribers with the publishers like here : zguide.zeromq.org/c:clonesrv2 The details in this (zguide.zeromq.org/…) chapter in the guide were useful to me as well. What eventually worked for me was to avoid processing the response message immediately by adding it to a list and doing the processing later.Streaky
Have you also checked this github.com/booksbyus/zguide/blob/master/examples/C%2B%2B/… ?Streaky
Downvote because the guide offers a solution to this problem: last-value-caching, right below the espresso pattern : zguide.zeromq.org/page:all#toc116 :)Teasel
Last-value caching helps subscribers who start up after messages are published, but it doesn't help with OP's original concern about publishers' messages getting lost before they can make it to the cache.Pampas
C
7

I found one workaround here, and that is to use PUSH/PULL on the publisher side, and PUB/SUB on the subscriber side. The new topology looks like this:

pullpub

This is the code you need for the center node:

#include <zmq.hpp>

int main()
{
    zmq::context_t context(1);

    //Incoming publications come here
    zmq::socket_t sub(context, ZMQ_PULL);
    sub.bind("ipc://subscriber.ipc");

    //Outgoing publications go out through here.
    zmq::socket_t pub(context, ZMQ_PUB);
    pub.bind("ipc://publisher.ipc");

    zmq::proxy(sub, pub, nullptr);

    return 0;
}

And then for publishers:

#include "zhelpers.hpp"

int main () {
    //  Prepare our context and publisher
    zmq::context_t context(1);
    zmq::socket_t publisher(context, ZMQ_PUSH);
    publisher.connect("ipc://subscriber.ipc");

    s_sendmore (publisher, "B");
    s_send (publisher, "No sleep!");

    return 0;
}

This solution seems to work fairly well, and I hope people chime in if they see any downsides to it. If I come across a better answer, I'll post here.

Cuspidor answered 31/3, 2017 at 14:14 Comment(0)
S
1

The downside is your publishers are always publishing. In the XSUB/XPUB case, subscriptions are forwarded to your publishers so that they can restrict what they are sending to the proxy. That results in less network traffic and less work for the proxy. In the PULL/PUB case, the publishers never see the subscription information. A worst case scenario would be a subscriber's subscription means they only want data from one publisher. All publishers would still be sending their data to the proxy and the proxy would filter out everything but the one publisher's messages.

Stereoisomerism answered 12/10, 2018 at 11:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.