ZeroMQ工作人员

时间:2017-07-05 04:29:25

标签: php zeromq distributed-computing pyzmq jzmq

ZeroMQ相当新。我有一个简单的REQ / REP队列,如下所示。我正在使用PHP,但这并不重要,因为任何语言绑定对我来说都没问题。 这是请求任务的客户端

$ctx = new ZMQContext();
$req = new ZMQSocket($ctx, ZMQ::SOCKET_REQ);
$req->connect('tcp://localhost:5454');
$req->send("Export Data as Zip");
echo $i . ":" . $req->recv().PHP_EOL;

这是一个真正执行任务的工人。

$ctx = new ZMQContext();
$srvr = new ZMQSocket($ctx, ZMQ::SOCKET_REP);
$srvr->bind("tcp://*:5454");
echo "Server is started at port $port" . PHP_EOL;
while(true)
{
    $msg = $srvr->recv();
    echo "Message = " . $msg . PHP_EOL;
    // Do the work here, takes 10 min, knows the count of lines added and remaining
    $srvr->send($msg . " is exported as zip file" . date('H:i:s'));
}

由于导出数据的任务大约需要10分钟,我想从不同的客户端连接到服务器,并获得完成任务的进度/百分比。 我想知道这是否是一种有效的方法。

我尝试过这种方法,其中REQ / REP部分可以工作,但我在PUB / SUB部分

中什么都没有

服务器部分

$ctx = new ZMQContext();
$srvr = new ZMQSocket($ctx, ZMQ::SOCKET_REP);
$srvr->bind("tcp://*:5454");

// add PUB socket to publish progress
$c = new ZMQContext();
$p = new ZMQSocket($c, ZMQ::SOCKET_PUB);
$p->bind("tcp://*:5460");

echo "Server is started at port 5454" . PHP_EOL;
$prog = 0;
while(true)
{
    $p->send($prog++ . '%'); // this part doesn't get to the progress client
    $msg = $srvr->recv();
    echo "Message = " . $msg . PHP_EOL;
    sleep(2);// some long task
    $srvr->send($msg . " Done zipping " . date('H:i:s'));
}

进度客户

$ctx = new ZMQContext();
$stat = new ZMQSocket($ctx, ZMQ::SOCKET_SUB);
$stat->connect('tcp://localhost:5460');
while (true){
    echo $stat->recv() . PHP_EOL; //nothing shows here
}

请求客户

$ctx = new ZMQContext();
$req = new ZMQSocket($ctx, ZMQ::SOCKET_REQ);
$req->connect('tcp://localhost:5454');
for($i=0;$i<100;$i++){
    $req->send("$i : Zip the file please");
    echo $i . ":" . $req->recv().PHP_EOL; //works and get the output
}

2 个答案:

答案 0 :(得分:1)

这个概念是可行的,需要进行一些调整:

所有PUB交易对手都必须设置任何非默认订阅,至少是空订阅 .setsockopt( ZMQ_SUBSCRIBE, "" ) 意味着接收所有主题(无&#34;过滤&#34; -ed) out)。

接下来,PUB端和SUB端都应该配置.setsockopt( ZMQ_CONFLATE, 1 ),因为没有任何值可以填充并将所有中间值提供到en-queue / de-queue管道中,一旦唯一的值是在&#34; last&#34;,最近的消息。

总是,ZeroMQ调用的非阻塞模式应该是首选(.recv( ..., flags = ZMQ_NOBLOCK )等)或者Poller.poll()预测试应该首先用于嗅探(非)存在一个消息,然后花更多的精力阅读其背景&#34;来自&#34; ZeroMQ上下文管理器。简而言之,阻塞模式服务调用在生产级系统中可以很好地发挥作用的情况并不多。

另外一些进一步的调整可能有助于PUB方面,以防更大规模的攻击&#34;来自不受限制的SUB端实体池,PUB必须为这些(不受限制的)交易对手创建/管理/维护资源。

答案 1 :(得分:0)

如果有多个客户希望接收相同的进度更新,则只需使用PUB / SUB。只需使用PUSH / PULL进行简单的点对点传输即可在tcp上运行。

哲学讨论

这样的问题可以解决两种方法。

  1. 使用其他套接字传达其他消息类型,
  2. 仅使用两个套接字,但通过它们传达多种消息类型
  3. 你在谈论做1)。可能值得考虑2),虽然我必须强调我几乎不知道PHP,所以不知道是否有语言功能鼓励人们有单独的请求和进度客户端。

    如果这样做,原始客户端需要一个循环(在发送请求之后)接收多条消息,包括进度更新消息或最终结果。您的服务器在进行10分钟查找时,会定期发送进度更新消息,并在最后发送最终结果消息。您可能会将PUSH / PULL客户端用于服务器,并且从服务器返回客户端的进度/结果也是如此。

    遵循2)在架构上更灵活。一旦您有通过单个套接字发送两个或更多消息类型并在接收端解码它们的方法,您可以发送更多。例如,您可以决定添加&#39;取消&#39;从客户端到服务器的消息,或从服务器返回到客户端的部分结果消息。这比继续向您的体系结构添加更多套接字更容易,因为您希望在客户端和服务器之间添加另一个消息流。再说一遍,我对PHP知之甚少,并说这肯定是用这种语言做这件事的正确方法。它在C,C ++中确实很有意义。

    我发现Google Protocol Buffers(我更喜欢ASN.1)之类的东西对于这种事情非常有用。这些允许您定义要发送的消息类型,并且(至少使用GPB)将它们组合在一个单一的“消息”中。 (在ASN.1中,人们使用标记来区分不同的消息)。 GPB和ASN.1非常方便,因为您可以在系统中使用不同的语言,操作系统和平台,而无需担心发送的内容。作为二进制(而不是文本),它们在网络连接中的效率更高。