这是使用消息队列的正确方法吗?

时间:2016-05-12 13:57:28

标签: php linux sockets message-queue zeromq

我是消息队列的新手,现在我在Linux服务器上使用ZeroMQ。我使用 PHP 来编写客户端和服务器。这主要用于处理推送通知。

我在单个I / O线程 ZMQContext 实例上使用了基本的REQ - REP形式通信模式,正如他们所展示的那样。< / p>

以下是最小化的 zeromqServer.php 代码:

include("someFile.php");

$context = new ZMQContext(1);

//  Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder->bind("tcp://*:5555");

while (true) {
    $request = $responder->recv();
    printf ("Received request: [%s]\n", $request);

    //  -----------------------------------------------------------------
    //                                    Process push notifications here
    //
    sleep (1); 

    //  -----------------------------------------------------------------
    //                                          Send reply back to client
    $responder->send("Basic Reply");
}

这是最小化的ZeroMQ 客户

$context = new ZMQContext();

//  Socket to talk to server
echo "Connecting to hello world server…\n";
$requester = new ZMQSocket($context, ZMQ::SOCKET_REQ);
$check = $requester->connect("tcp://localhost:5555");

var_dump($check);
$requester->send("json string payload with data required to process push notifications.");

//$reply = $requester->recv();

那么,我做什么?我使用linux命令

运行zeromqServer.php作为后台服务
  

nohup php zeromqServer.php &

这将它作为后台进程运行。现在,当客户端调用它时,它会完成所需的工作。

但问题是,每当任何文件发生变化时,我都需要重新启动该过程(包括include文件中的zeromqServer - 。

此外,不知何故,2-3天之后,它就会停止工作。这个过程不会停止,但它会停止工作。

我觉得它必须是一些套接字问题,也许套接字不再打开了。那时我必须重新启动zeromqServer.php文件进程。

Q1:可能是什么问题?

Q2:这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

我只能部分回答这个问题。我不知道为什么这个过程会在2-3天后挂起。

总的来说,PHP脚本在脚本执行时加载一次,似乎没有任何解决此限制的方法。但是,您当前的代码可以按如下方式重写:

<强> someFile.php

$context = new ZMQContext(1);

//  Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder->bind("tcp://*:5555");

while (true) {
    $request = $responder->recv();
    printf ("Received request: [%s]\n", $request);

    $subscriptParams = [
        "Request" => $request //Add more parameters here as needed
    ];

    $result = shell_exec("php work.php ".base64_encode(serialize($subscriptParams)));       

    //  Send reply back to client
    $responder->send("Basic Reply");
}

<强> work.php

if (!isset($argv[0])) {
   die("Need an argument");
}

$params = unserialize(base64_decode($argv[0]));
//Validate parameters
$request = $params["Request"];
//  Do some 'work'
//Process push notifications here!
sleep (1); 

这是我的假设:

  1. 脚本的设置部分,例如设置$context$responder将永远保持不变(或者您可以忍受重启脚本所需的停机时间,因为更改了该脚本)。

  2. 循环的开始和结束保持不变,我的想法是shell_exec将返回一个响应,响应者可以将其作为实际响应使用。

  3. 更多澄清:

    我使用serialize传递work.php需要使用的参数数组。我正在进行base64编码解码,因为我想确保整个参数适合$argv[0],而不是在参数中找到的潜在空格上拆分。

    相同的serialize -> base64_encodebase64_decode -> deserialize组合可用于work.php的结果。

    请注意,我根本没有亲自尝试过此代码,因此我无法保证其有效。我只是没有看到任何原因导致它无法正常工作(确保php在您的路径中,或者在/usr/bin/php中致电shell_exec,如果它不是&#39;吨)。

    值得注意的是,此解决方案比将所有代码放在一个文件中要慢得多,但这是在每次迭代时刷新脚本的成本。

答案 1 :(得分:0)

Q2:这样做的正确方法是什么?

在我看来,做任何事情的正确方法是在开始时为您选择最适合的选项,以免花费时间在一个可以产生二年级成绩的方法上。我没有反对ZeroMQ,尽管我遵循的逻辑是程序员应该始终努力做最干净的代码并使用最好的工具。在使用PHP创建Message队列的情况下,使用Pheanstalk可以获得更多成功:https://github.com/pda/pheanstalk

这是一个强烈推荐的在线开源选项,可以在linux上完美运行。安装队列非常简单,我在以下主题中写了关于如何安装 pheanstalk 的完整答案:Unable to get Beanstalkd Queue to work for PHP

Pheanstalk使用beanstalkd库,重量轻,效率高。要根据您的问题建议预先形成消息队列,您可以使用两个简单的PHP脚本来执行此操作:

消息制作人:

<?php
$pheanstalk = new Pheanstalk('127.0.0.1:11300');
$pheanstalk
  ->useTube("my_queue")
  ->put("Hello World");
?>

工人脚本:

<?php
    if ($job = $pheanstalk
    ->watch('testtube')
    ->ignore('default')
    ->reserve())//retreives the job if there is one in the queue
    {
        echo $job->getData();//echos the message
        $pheanstalk->delete($job);//deletes the job from the queue
    }
}
?>

消息生成器将包含在用户将创建消息的页面中,并且将被发送到由beanstalkd生成的队列。可以以不同方式设计工作者脚本。您可以将其置于while循环中以每秒搜索一个新队列,甚至可以让多个工作人员搜索队列。 Pheanstalk是非常有效的,强烈推荐。