如果在Docker中运行,ZeroMQ REQ .recv()挂起的消息大于〜1kB

我正在使用REQ / ROUTER套接字来开发一个相对简单的基于Python / ZeroMQ的工作分配系统。 该系统是分布式的,工作人员节点分布在不同的大陆上。

ROUTER负责分配工作, .bind() ROUTER套接字。 通过使用REQ套接字的TCP工作者.connect()

在build立一个新的工作节点的过程中,我注意到虽然较小的消息(高达1kB)没有问题,但是由ROUTER发送的〜2kB以上的回复永远不会被工作人员接收进入他们的REQ -socket – 当我调用recv() ,套接字只是挂起。

工作者代码在Docker容器内部运行,当我运行同样的镜像时,我能够解决这个问题--net=host – 如果Docker使用主机networking,似乎不会发生这种情况。

我想知道这是否是在主机或Docker的networking堆栈configuration中的东西,或者是可以防止在我的代码中的东西?

这里是我的代码的简化版本,再现了这个问题:

工人

 import sys import zmq import logging import time READY = 'R' def worker(connect_to): ctx = zmq.Context() socket = ctx.socket(zmq.REQ) socket.connect(connect_to) log = logging.getLogger(__name__) while True: socket.send_string(READY) log.debug("Send READY message, waiting for reply") message = socket.recv() log.debug("Got reply of %d bytes", len(message)) time.sleep(5) if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) worker(sys.argv[1]) 

路由器

 import sys import zmq import logging REPLY_SIZE = 1024 * 8 def router(bind_to): ctx = zmq.Context() socket = ctx.socket(zmq.ROUTER) socket.bind(bind_to) poller = zmq.Poller() poller.register(socket, zmq.POLLIN) log = logging.getLogger(__name__) while True: socks = dict(poller.poll(5000)) if socks.get(socket) == zmq.POLLIN: message = socket.recv_multipart() log.debug("Received message of %d parts", len(message)) identity, _ = message[:2] res = handle_message(message[2:]) log.debug("Sending %d bytes back in response on socket", len(res)) socket.send_multipart([identity, '', res]) def handle_message(parts): log = logging.getLogger(__name__) log.debug("Got message: %s", parts) return 'A' * REPLY_SIZE if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) router(sys.argv[1]) 

FWIW我能够在Ubuntu 16.04(包括路由器和工作者)上使用Docker 17.09.0-ce ,libzmq 4.1.5和PyZMQ 15.4.0重现这15.4.0

不,先生,sockets根本不挂:

为什么?

问题是,你已经指示Socket() .recv()一旦调用.recv()方法,而不指定zmq.NOBLOCK标志(ZeroMQ原始API中的ZMQ_DONTWAIT标志.recv() ,就进入无限阻塞状态。

这是其原因,在昨天报告的其他情况下,将代码移动到无限的阻塞状态,因为似乎还有其他问题阻止Docker-container将任何第一条消息正确传递给Worker的Docker-embedded-ZeroMQ- Context() I / O引擎和REQ访问点的手中。 由于REQ -archetype使用严格的两步有限状态自动机 – 严格跨步( .send() – > .recv() – > .send() – > ... ad infimum)

这种原因 – >效果颠倒是错误的和误导 –
套接字挂起 ”的问题
无法决定的
从一个问题Docker不提供一个单一的消息 (以允许.recv()返回)


下一步:

可以在REQ端使用.poll()来嗅探工作人员已经到达的任何消息。

一旦没有这种情况, 关注Docker首先 +下一个可能会受益于ZeroMQ Context() -I / O引擎性能和链接级别调整configuration选项。