【问题标题】:How to have multiple publishers and subscribers in ZMQ/0MQ?如何在 ZMQ/0MQ 中拥有多个发布者和订阅者?
【发布时间】:2021-05-06 04:34:01
【问题描述】:

如何创建一个允许多个发布者和这些发布者的多个订阅者的网络?

还是绝对有必要使用消息代理?

import time
import zmq
from multiprocessing import Process

def bind_pub(sleep_seconds, max_messages, pub_id):
    context = zmq.Context()
    socket = context.socket(zmq.PUB)
    socket.bind("tcp://*:5556")

    message = 0
    while True:
        socket.send_string("1 sending_func=bind_pub message_number=%s pub_id=%s" % (message, pub_id))
        message += 1
        if message >= max_messages:
            break
        time.sleep(sleep_seconds)

def bind_sub(sleep_seconds, max_messages, sub_id):
    context = zmq.Context()
    socket = context.socket(zmq.SUB)
    socket.bind("tcp://*:5556")
    socket.setsockopt_string(zmq.SUBSCRIBE, '1')

    message_n = 0
    while True:
        message = socket.recv_string()
        print(message + " receiving_func=bind_sub sub_id=%s" % sub_id)
        message_n += 1
        if message_n >= max_messages - 1:
            break
        time.sleep(sleep_seconds)

def conect_pub(sleep_seconds, max_messages, pub_id):
    context = zmq.Context()
    socket = context.socket(zmq.PUB)
    socket.connect("tcp://localhost:5556")

    message = 0
    while True:
        socket.send_string("1 sending_func=conect_pub message_number=%s pub_id=%s" % (message, pub_id))
        message += 1
        if message >= max_messages:
            break
        time.sleep(sleep_seconds)

def connect_sub(sleep_seconds, max_messages, sub_id):
    context = zmq.Context()
    socket = context.socket(zmq.SUB)
    socket.connect("tcp://localhost:5556")
    socket.setsockopt_string(zmq.SUBSCRIBE, '1')

    message_n = 0
    while True:
        message = socket.recv_string()
        print(message + " receiving_func=connect_sub sub_id=%s" % sub_id)
        message_n += 1
        if message_n >= max_messages - 1:
            break
        time.sleep(sleep_seconds)

尝试使用 bind_pub、connect_pub、connect_sub、connect_sub 网络架构时:

# bind_pub, connect_pub, connect_sub, connect_sub
n_messages = 4
p1 = Process(target=bind_pub, args=(1,n_messages,1))
p2 = Process(target=conect_pub, args=(1,n_messages,2))
p3 = Process(target=connect_sub, args=(0.1,n_messages,1))
p4 = Process(target=connect_sub, args=(0.1,n_messages,2))
p1.start()
p2.start()
p3.start()
p4.start()
p1.join()
p2.join()
p3.join()
p4.join()

导致pub_id=2 消息丢失:

1 sending_func=bind_pub message_number=1 pub_id=1 receiving_func=connect_sub sub_id=2
1 sending_func=bind_pub message_number=1 pub_id=1 receiving_func=connect_sub sub_id=1
1 sending_func=bind_pub message_number=2 pub_id=1 receiving_func=connect_sub sub_id=2
1 sending_func=bind_pub message_number=2 pub_id=1 receiving_func=connect_sub sub_id=1
1 sending_func=bind_pub message_number=3 pub_id=1 receiving_func=connect_sub sub_id=1
1 sending_func=bind_pub message_number=3 pub_id=1 receiving_func=connect_sub sub_id=2

类似地运行一个 connect_pub、connect_pub、connect_sub、bind_sub 架构:

# connect_pub, connect_pub, connect_sub, bind_sub
n_messages = 4
p1 = Process(target=conect_pub, args=(1,n_messages,1))
p2 = Process(target=conect_pub, args=(1,n_messages,2))
p3 = Process(target=bind_sub, args=(0.1,n_messages,1))
p4 = Process(target=connect_sub, args=(0.1,n_messages,2))
p1.start()
p2.start()
p3.start()
p4.start()
p1.join()
p2.join()
p3.join()
p4.join()

导致sub_id=2 没有收到任何消息:

1 sending_func=conect_pub message_number=1 pub_id=1 receiving_func=bind_sub sub_id=1
1 sending_func=conect_pub message_number=1 pub_id=2 receiving_func=bind_sub sub_id=1
1 sending_func=conect_pub message_number=2 pub_id=1 receiving_func=bind_sub sub_id=1

【问题讨论】:

  • 所以.. 我没有得到公认的答案.. 阅读它就像吃碎玻璃.. obv 这家伙的智商为 3233.. 他只是在平行宇宙中.. 我有 subscriber插座。如何将其连接到多个发布者?

标签: zeromq distributed-system


【解决方案1】:

嗯,
公平地说,ZeroMQ 主要是一个无代理框架,

这意味着第二个问题是先验解决的 - 不,它不仅 不是 绝对必要,而且原则上也是不可能的(如果一个人不实施 Broker-(半)持久性作为 Zen-of-Zero 标准 ZeroMQ 工具基于层的额外附加组件)。


接下来,
ZeroMQ 工具远不是你所知道的“socket”-s:

这是一个经常被重新表述的误解,所以让我用粗体重复一遍。

当心:
ZeroMQ Socket()-instance 不是 tcp-socket-as-you-know-it。最好阅读 ZeroMQ hierarchy in less than a five seconds 或此处的其他帖子和讨论中的主要概念差异。


然而,
更重要的是,
似乎没有未涵盖的明确需求:

ZeroMQ 可以服务于所有的:

many-PUB-s : many-SUB-s           -or-  
 one-PUB   : many-SUB-s           -or- even  
many-PUB-s :  one-SUB

那些“许多”的全部或部分仍然可以得到 .connect()-ed 到单个或多个接入点,因此生成的拓扑可能确实很疯狂(有关详细信息,请查看上面提供的link to a "five seconds" read)所以,自己的想象力似乎是这样做的唯一上限。

有关性能和延迟范围,请随时seek and read more in other posts.

【讨论】:

  • 您能否详细说明many-PUB-s : many-SUB-s 架构是如何制作的?即 PUB/SUB 端使用什么类型的连接{ PUB/SUB | PUSH/PULL | PAIR/PAIR | XPUB/XSUB | ... | REQ/REP } 以及connectbind 方法如何适应它?
  • 如果只有一个发布者或消费者能够绑定,如何实现many-PUB-s : many-SUB-s
  • 想象一下,只要可行且可在整个一组已经.bind( ... )-RTO'd PUB-s。因此,many-PUB-s : many-SUB-s 拓扑也可以工作,仍然在需要时使用本机 PUB/SUBXPUB/XSUB 原型。
  • 我提供了一个many pub many sub架构的代码示例以及结果。这似乎是不可能的。
  • 你在开玩笑吧?我无法对你的回应做出足够的反应。在我最初的问题中,我询问了如何做以及是否需要使用消息代理。你说这是可能的。我继续向您展示了代码,这些代码是唯一有机会工作而不使用消息代理的组合,现在您告诉我使用文档中的模式。开个玩笑,我不知道你是怎么获得这么高的声誉的。我已经标记了你的答案。这真是个笑话。
【解决方案2】:

当然没有必要使用代理来实现多对多网络,但是代理确实简化了配置,因为每个节点只需要知道代理的地址,而不是所有节点。

另一种可能性是混合方法——使用代理在对等点之间交换地址信息,以便它们可以直接相互连接。你可以在这里找到一个例子:https://github.com/nyfix/OZ/blob/master/doc/Naming-Service.md

【讨论】:

  • 完全同意这一点,我研究过一个非常相似的混合解决方案。最好的部分是发送方和接收方之间的数据连接是单跳和低延迟,而发现服务节点/代理可以在负载均衡器后面复制。最近,我在 aws 上部署了系统,并将发现部分放入带有负载均衡器的规模集中,这使得系统非常可靠。
猜你喜欢
  • 2016-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多