在没有 http 的同一台服务器上从 php 向 nginx 发送信息

Sending information to a ngnix from php on the same server without http

我们正在开发一个实时应用程序,我们正在将 nginx 推送流模块用于 websockets 部分。首先,数据从客户端发送到 php 脚本,该脚本执行一些身份验证并将所需信息存储在数据库中,然后将信息推送到 nginx,后者随后将其发送到特定套接字上的订阅用户。经常会出现从该脚本向本地 nginx 发出超过 30 个 http 请求的情况(我不确定这是一件坏事吗?)。

问题
是否可以在没有 http 请求的情况下将信息从 php 发送到 nginx?我的 php 脚本有什么方法可以与 nginx 通信吗?处理此类通信的最佳做法是什么?每个 php 脚本发送 30 多个 http 请求是一个好习惯吗?

我已经阅读了一些 AMQP 解决方案,但没有找到 nginx 是来自 rabbitmq 消息的消费者的信息。

如果有任何不清楚的地方,我很乐意提供任何其他信息。

我假设如下:

当前工作流程:

  1. 来自命令行的用户 运行 php 脚本,它使用 http 请求
  2. 与 Nginx 中的服务器端 script/cgi 设置进行通信
  3. Nginx 中的服务器端 script/cgi 将接收传入的数据,对其进行处理并将其放入数据库,或者发送给最终用户

OP关注点:

命令行的效率php 脚本使用 http 协议与 Nginx 服务器端脚本通信,这可能有点矫枉过正,因为通信发生在同一台服务器内。

提案 1

  1. 命令行php脚本会将所有信息写入文件, 然后向 Nginx 服务器端 cgi 脚本发送一个 http 请求
  2. Nginx服务器cgi脚本,收到请求后,将获取所有 来自文件的信息,然后对其进行处理
  3. ramfs(ram 磁盘)可用于最小化 I/O 到物理 HD

提案 2

将您的命令行 php 脚本合并到 Nginx 服务器端脚本中,并为其创建一个 Web 界面。当前命令行用户将登录网页以控制他们过去使用命令行工具执行此操作的过程。

Pro:不再有inter-scripts/inter-process通讯。整个工作流程在一个过程中。这在未来也可能更具可扩展性,因为多个用户可以通过 Web 界面登录并远程处理该过程。此外,他们不需要 OS 级帐户。

缺点: 可能需要更多开发时间。 (但您只需维护一个代码库,而不是两个。)

您为什么不考虑使用 socket.io 和 Amazon SNS?

在我们的基础架构中,当我们想要向订阅 socket.io 频道的特定客户端发送通知时,我们会将有效负载发送到 Amazon SNS 主题。此负载具有 "channel" 属性和要发送到客户端的 "message"。我只给出了我们代码中的一个易于理解的片段

$msg = array(
                'channel' => $receiver->getCometChannel(), //Channel id of the client to send the message 
                'data' => json_encode($payload) //The message to send to the client
    );
$client = $this->getSNSObject();
$client->publish(array(
            'TopicArn' => $topicArn,
            'Message' => json_encode($msg)
        ));

我们有一个 node.js 脚本在端口 8002 (http://your_ip:8002/receive) 上创建端点当 Amazon SNS 从 PHP 后端接收到负载时,它将此负载转发到此端点然后唯一要做的就是处理有效负载并通过 socket.js 将消息发送到相应的客户端。这是 node.js 脚本:

var fs = require('fs');

var options = {
    pfx:fs.readFileSync('/etc/ssl/certificate.pfx') //optional, for SSL support for socket.js
};


var io = require('socket.io')(8001);


// open the socket connection
io.sockets.on('connection', function(socket) {
        socket.on('subscribe', function(data) { socket.join(data.channel); });
        socket.on('unsubscribe', function(data) { socket.leave(data.channel); });
        socket.on('message', function (data) {
                io.sockets.in(data.channel).emit('message', data.message);
        });
})

var http=require('http');
http.createServer(function(req, res) {
    if(req.method === 'POST' && req.url === '/receive') {
        return client(req, res);
    }
    res.writeHead(404);
    res.end('Not found.');
}).listen(8002);

var SNSClient = require('aws-snsclient');
var client = SNSClient(function(err, message) {
        try{
                var body=JSON.parse(message.Message)
                var channel=body.channel,data=(body.data);
                console.log(channel);
                io.sockets.in(channel).emit('message', {channel: channel, data: data});
        } catch(e) {
                console.log(e);
        }
});

也许看起来很复杂,但我的想法很清楚。

让我一步步回答:

  1. 每个 php 脚本发送 30 多个 http 请求是一个好习惯吗?

在您对速度感到满意之前,这不是问题。该解决方案可能存在两个潜在问题:

a. high timing to reestablish http connection each request; 
b. when concurrent requests reach its maximum nginx can skip some of your requests;
  1. 处理此类通信的最佳做法是什么?

正如您所说,使用查询接口的最佳做法。但我不确定,有没有办法在 nginx 端处理它(我不清楚你在 nginx 端使用的技术)。

您也可以使用长轮询连接向 nginx 发送请求,这将减少问题 (a) 的延迟,但它可能会引发一些新问题。

使用 PHP-FPM 使用 FastCGI 协议通过 Unix 域套接字连接到 Nginx 怎么样?这是在 Nginx 和 PHP 之间进行 IPC 的最快方式 — 与 Internet 套接字相比,IO 开销非常小。

我们之前尝试的另一个解决方案是部署一个 ejabberd 服务器(您可以自定义它)使用 strophe 客户端编写一个小型 javascript 客户端。 http://blog.wolfspelz.de/2010/09/website-chat-made-easy-with-xmpp-and.html?m=1 关于主题的好博客 post。如果你想开发一个聊天应用程序,我会选择这个选项。

另一个优势,您的用户还可以使用 xmpp 客户端连接到您的聊天平台。