如何将队列连接到ZeroMQ PUB / SUB

时间:2016-03-10 21:28:25

标签: zeromq jeromq

请考虑以下事项:

  • 一组3个逻辑服务:S1S2S3
  • 每个服务的两个实例正在运行,因此我们有以下流程:S1P1S1P2S2P1S2P2S3P1,{{ 1}}
  • S3P2代理在单个进程中运行,并且可由所有服务进程访问

逻辑服务,让我们说ZeroMQ,发布逻辑服务S1M1感兴趣的消息S2。每个逻辑服务只有一个进程必须收到S3,因此请说M1S2P1

我尝试了以下内容,但没有成功:

  • 经纪商线程1正在运行 S3P2 代理
  • 代理线程2正在运行 XSUB/XPUB 代理,ROUTER/DEALER连接到ROUTER套接字并订阅了所有内容(逻辑XPUB
  • 代理线程3正在运行S1代理,ROUTER/DEALER连接到ROUTER套接字并订阅了所有内容(对于逻辑XPUB
  • 代理线程4正在运行S2代理,ROUTER/DEALER连接到XPUB套接字并订阅了所有内容(对于逻辑ROUTER
  • 每个逻辑服务进程正在运行连接到代理S3套接字的REP套接字线程

我认为DEALER代理会给我发布/订阅语义,并且XSUB/XPUB代理会在ROUTER/DEALER套接字之间引入REP发送的消息之间的竞争代理。

如何合并XSUB/XPUB套接字来完成此操作?

UPDATE1

我知道"没有成功"我没有帮助,我尝试了不同的配置并得到了不同的错误。我尝试的最新配置如下:

ZeroMQ

copyLoop是这样的:

(XSUB proxy=> XPUB) => (SUB copyLoop=> REQ) => (ROUTER proxy=> DEALER) => REP

我得到的例外情况如下:

public void start() {
    context = ZMQ.context(1);

    subSocket = context.socket(ZMQ.SUB);
    subSocket.connect(subSocketUrl);
    subSocket.subscribe("".getBytes());

    reqSocket = context.socket(ZMQ.REQ);
    reqSocket.connect(reqSocketUrl);

    while (!Thread.currentThread().isInterrupted()) {
        final Message msg = receiveNextMessage();
        resendMessage(msg);
    }
}

private Message receiveNextMessage() {
    final String header = subSocket.recvStr();
    final String entity = subSocket.recvStr();

    return new Message(header, entity);
}

private void resendMessage(Message msg) {
    reqSocket.sendMore(msg.getKey());
    reqSocket.send(msg.getData(), 0);
}

我正在运行JeroMQ 0.3.4,Oracle Java 8 JVM和Windows 7.

2 个答案:

答案 0 :(得分:3)

您似乎通过ROUTER连接添加了一些复杂性 - 您应该能够直接与发布商建立联系。

您当前遇到的错误是REQ套接字具有严格的消息排序模式 - 您不能连续两次send(),您必须发送/接收/发送/接收/ etc(同样,REP套接字必须接收/发送/接收/发送/等)。从它的外观来看,你只是在REQ套接字上进行发送/发送/发送/等,而没有收到响应。如果您不关心同行的回复,则必须接收并弃置回复,或使用DEALER(或ROUTER,但DEALER在您当前的图表中更有意义。

我已经创建了一个如何使用基本流程结构完成此体系结构的图表。

Broker T1         Broker T2                Broker T3                Broker T4
(PUB*)------>(*SUB)[--](DEALER*)   -->(*SUB)[--](DEALER*)   -->(*SUB)[--](DEALER*)
       |_____________________||____|                  ||    |                  ||
       |_____________________||_______________________||____|                  ||
                             ||                       ||                       ||
     ========================||     ==================||            ===========||=
   ||             ||              ||              ||              ||              ||
   ||             ||              ||              ||              ||              ||
   ||             ||              ||              ||              ||              ||
(REP*)         (REP*)          (REP*)          (REP*)          (REP*)          (REP*)
 S1P1           S1P2            S2P1            S2P2            S3P1            S3P2

所以,主要区别在于我放弃了你的(SUB copyLoop=> REQ)步骤。您选择XPUB/XSUB vs PUB/SUB取决于您,但除非您目前想要使用XPUB/XSUB的额外功能,否则我会更容易开始。

显然,这个图表没有涉及信息如何进入您的经纪人,当前您显示的是XSUB套接字 - 这超出了您迄今为止提供的信息的范围,可能是您能够收到的信息已成功发送到您的经纪商,所以我不会处理。

我认为专用于每项服务的代理线程是否可以明智地选择是否将消息发送到他们的服务?如果是这样,那么您选择让他们订阅一切应该可以正常工作,否则可能需要更智能的订阅设置。

如果您在服务进程上使用REP套接字,那么服务进程必须接收该消息并异步处理它,从不将有关该消息的任何详细信息传达给经纪人。然后它必须通过确认(如“RECEIVED”)响应每条消息,以便它遵循REP套接字的严格接收/发送/接收/发送模式。

如果您想要关于服务如何处理发送回代理的消息的任何其他类型的通信,REP不再是服务进程的适当套接字类型,DEALER可能不再是您的经纪人的正确套接字类型。如果您需要某种形式的负载平衡以便发送到下一个打开的服务进程,则需要使用ROUTER/REQ并让每个服务指示其可用性并让代理保持该消息直到下一个服务进程说通过发回结果可以获得它。如果你想要一些其他类型的消息处理,你必须指出它是什么,这样才能提出合适的架构。

答案 1 :(得分:1)

显然,我混淆了一些元素:

  • 套接字具有相同的API,无论您是将其用作客户端套接字(.front_back{ transform: rotateY( 180deg ); backface-visibility: hidden; background-color:red; } )还是服务器端套接字(Socket.connect
  • 套接字具有相同的API,无论类型如何(例如,Socket.bind套接字不应调用Socket.subscribe
  • 某些套接字类型需要发送/接收响应循环(例如PUSH
  • 沟通模式的一些细微差别(REQ/REP vs PUSH/PULL
  • 调试ZeroMQ设置的难度(不可能性?)

非常感谢Jason的非常详细的答案(以及令人敬畏的图表!),它指出了我正确的方向。

我最终得到了以下设计:

  • 经纪人主题1正在ROUTER/DEALERXSUB/XPUB
  • 上运行扇出bind(localhost:6000)代理
  • 代理商线程2正在bind(localhost:6001)SUB/PUSH上运行排队connect(localhost:6001)代理;代理线程3和4使用具有不同绑定端口号的类似设计
  • 消息生产者使用bind(localhost:6002)
  • 上的PUB套接字连接到代理
  • 消息使用者使用connect(localhost:6000)上的PULL套接字连接到代理排队代理

除了这种特定于服务的排队机制之外,我还能够简单地添加一个类似于服务的扇出机制:

  • 代理线程在connect(localhost:6002)SUB/PUB
  • 上运行connect(localhost:6001)代理
  • 消息生产者仍使用bind(localhost:6003)
  • 上的PUB套接字连接到代理
  • 消息使用者使用connect(localhost:6000)上的SUB套接字连接到代理扇出代理

这是一次有趣的旅程。