如果在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选项。
- 如何在本地模仿Travis CI?
- Docker for Windows – 容器域名无法parsing
- 用`docker run`覆盖文件
- 使用Dockerfile将UI容器中的'dist'文件夹挂载到NGINX容器
- docker exec命令的远程API
- docker工人MySQL没有输出
- AWS ECS和Docker:不能通过tcp:// <MY-ID> .dkr.ecr.us-east-1.amazonaws.com:2375 / <PROJECT>连接到Docker守护进程。
- 如何将Docker镜像推送到GoCD Pipeline中的AWS ECR
- 在Linux / Windows群集上部署服务时,Kubernetes“Failed create pod sandbox”错误