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

标签 php linux sockets message-queue zeromq

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

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

这是最小化的 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();

那么,我该怎么办?我运行 zeromqServer.php作为后台服务,使用linux命令

nohup php zeromqServer.php &



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

但问题是,每当任何文件(包括 include -ed 在 zeromqServer 文件中)发生更改时,我都需要重新启动进程。

而且,不知何故,2-3 天后,它就停止工作了。这个过程不会停止,但它只是停止工作。

我觉得这一定是一些套接字问题,也许套接字不再打开了。当时我要重启zeromqServer.php文件过程。

Q1:可能是什么问题?

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

最佳答案

这不是使用消息队列的正确方法。

A1:问题是您的服务器最终必须阻塞,因为客户端代码在 REQ/REP 时没有检索到任何答案。 -pattern 需要这样做。 zeromqServer.phpREP方根本不会尝试recv()来自关联客户端的另一条消息(在正式通信模式的 REQ 一侧),直到客户端物理交付(到内部缓冲区)并具有 recv() -ed 来自 zeromqServer.php 的“回复”消息边。

ZeroMQ 的早期版本,版本。 2.1 et al,在数据被复制到 O/S-kernel 之前,用于节点内部消息队列和内存管理的无限、无限、默认限制大小,用于低级 I/O 线程缓冲资源并从 ZeroMQ 内存占用中释放。

较新版本的 ZeroMQ,版本 3.x+,具有所谓的 HWM -s (a.k.a. High-Water-Mark-s ) 默认情况下“只有” 1000 条“短”消息,之后此类 ZeroMQ 资源的相应部分开始阻塞或丢弃消息。

虽然显式增加 HWM 设置管理的被动尝试看起来像是解决主要设计错误的肮脏方式,但另一个 ZeroMQ 警告对此是公平的,进一步谨慎地朝着这个方向前进(ØMQ 不保证套接字将接受为多达 ZMQ_SNDHWM 消息和 实际限制可能是 最多 60-70% 更低 取决于套接字上的消息流)。

忘记或无法执行此操作( 引用: OP 代码已经证明):

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

表示您的 REQ/REP正式的沟通模式“钟摆”变得不可逆转(永远)。

A2:基础版 REQ/REP正式通信模式听起来很简单,但有一些危险的特征,观察到的阻塞只是其中之一。可能会在代码方面采取一些额外的步骤来部署 XREQ/XREP , DEALER/ROUTER和其他工具,但设计应该彻底修改,而不仅仅是 SLOC来自 SLOC ,因为在设计代码之前似乎有很多事情需要意识到。一个主要的错误是假设一条消息发送一次 send()方法已下令。在 ZeroMQ 中不是这种情况。

此外,代码设计应该假设消息传递的不确定性,并正确处理丢失消息问题和任何类型的分布式服务阻塞事件(死锁、活锁、缓冲区阈值溢出、旧/新 API 冲突,因为那里没有明确保证您的任何消息传递对等方(ZeroMQ 中没有中央消息代理)在其本地主机端实现了完全相同版本的 ZeroMQ API/协议(protocol)——所以确实有很多新的观点,在代码设计)

最好的方法来做到这一点

如果您可以信任并相信亲 body 验,那么您最好的下一步应该是下载并阅读 fabulous Pieter HINTJENS' book "Code Connected, Volume 1" ,其中 Pieter 对分布式处理有很多见解,包括许多关于可靠模式的提示和方向,正如您希望实现的那样。

一定要读这本书,它既值得你花时间,而且你可能会多次重读这本书,如果你一直从事分布式软件设计,所以不要犹豫,立即开始跳到 Master of Masters 的 400 多页食谱,Pieter HINTJENS 出的问题是。

为什么?现实世界通常要复杂得多

就一张图,上述书中的图 60 忘记了个体原型(prototype)的重用,并意识到需要适当的端到端分布式系统设计视角,包括 避免阻塞 死锁解决策略:

Transport Plane + SIG Plane

只是为了有一些想法,请查看以下代码示例,来自一个简单的分布式消息传递,其中 aMiniRESPONDER进程使用多个 ZeroMQ channel 。

enter image description here

如何在相当大的 Web PHP 应用程序域中改进您的实现?

了解如何防止(设计方面)和处理(双机前驱型)其他碰撞。

PHP 拥有用于此类算法化的所有适当的语法构造函数,但架构和设计从头到尾都掌握在您的手中。

只是为了意识到,碰撞感知有多大{ try:, except:, finally: } ZeroMQ 信令基础设施设置/系统部分/ZeroMQ 优雅终止工作的风格是,检查 [SoW]仅按行号:
14544 - 14800 // a safe infrastructure setup on aMiniRESPONDER side   ~ 256 SLOCs
15294 - 15405 // a safe infrastructure graceful termination          ~ 110 SLOCs

aMiniRESPONDER事件处理段的核心逻辑相比例子
14802 - 15293 // aMiniRESPONDER logic, incl. EXC-HANDLERs             ~ 491 SLOCs

关于基于 ZeroMQ 的分布式系统的最后说明

苛求?是的,但非常强大、可扩展、快速且在正确使用时确实有益。不要犹豫,投入时间和精力来获取和管理您在该领域的知识。您所有进一步的软件项目都可以从这项专业投资中受益。

关于php - 这是使用消息队列的正确方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37189154/

相关文章:

php - 如何通过查询从我的数据库中获取复选框插入的数据

php - 如何找出接收到的udp数据包的数据大小

php - 如何防止数据库中存在多个这样的条目?

javascript - 如何在同一页面显示输入和输出?

php - .htaccess 只允许图像

linux - 找到一个文件并将其复制到另一个目录

sockets - 在 SSL 连接中使用异步 sock_recv 时出现 SSLWantReadError

java - 套接字无法接收数据

php - 从一个到多个模态获取 id - Laravel

linux - ls -lrt 显示不存在的文件