PHP 中消息队列和工作系统的有效架构?

Posted

技术标签:

【中文标题】PHP 中消息队列和工作系统的有效架构?【英文标题】:Valid Architecture for a Message Queue & Worker System in PHP? 【发布时间】:2015-11-19 05:07:18 【问题描述】:

我正试图围绕我想在 php 应用程序中实现的消息队列模型和作业:

我的目标是卸载需要发送到多个第三方 API 的消息/数据,因此访问它们不会减慢客户端的速度。所以将数据发送到消息队列是理想的。

我考虑只使用 Gearman 来保存 MQ/Jobs,但我想使用云队列服务,如 SQS 或 Rackspace 云队列,这样我就不必管理消息了。

这是我认为我应该做的图表:

问题:

我的工人,会用 PHP 编写,他们都必须轮询云队列服务吗?这可能会变得昂贵,尤其是当您有很多工人时。

我在想可能有 1 个工作人员只是用于轮询队列,如果有消息,通知其他工作人员他们有工作,我只需要使用 supervisord 让这 1 个工作人员在线吗?这种轮询方法是否比使用可以通知的 MQ 更好?我应该如何轮询 MQ,每秒一次或尽可能快地轮询?如果我发现它变慢了,然后增加投票工作人员?

我还考虑为所有消息设置一个队列,然后工作人员监控根据需要处理的位置将消息分发到其他云 MQ,因为可能需要处理 1 条消息2 名差异工作者。

我是否还需要gearman 来管理我的工人,或者我可以只使用supervisord 来调动工人吗?

在发送消息时向主工作人员发送通知与轮询 MQ 相比不是更有效、更快捷吗?我假设我需要使用gearman 来通知我的主要工作人员MQ 有一条消息,以便它可以开始检查它。或者如果我每秒有 300 条消息,这将生成 300 个作业来检查 MQ?

基本上我如何才能尽可能高效地检查 MQ?

对我的架构有什么建议或更正吗?

【问题讨论】:

对于每秒必须处理 300 条消息的东西,构建一个原型以查看它是否正确扩展是值得的。我预计 Gearman 会工作,但有 plenty of queueing systems to choose from。不过,正如您所说,也许只通过数据库队列工作的脚本可能工作正常。 对于 Gearman,我的理解是如果服务器出现故障(等待项目需要重新排队),则没有队列持久性。考虑如何将排队的项目存储到磁盘,以及如果您的服务器崩溃,您将如何从它们中恢复。如果您有要处理的项目的数据库存储(例如,您的脚本仅使用 supervisord),那么它将从中断处继续。 我相信正确队列的要点是,如果您有多个工作节点,则分配工作的代码已经为您完成。工作人员不能仅仅帮助自己处理队列项,因为它可能会导致竞争条件(一项工作被多次声明)。 是的,我想弄清楚我是否需​​要gearman。我认为 Cloud MQ 服务可以很好地工作,并且我的工作人员可以帮助自己加入队列,因为大多数 Cloud MQ 都有一个声明流程,因此项目不能由超过 1 个工作人员处理。 supervisord 将运行多个工作人员来检查 MQ。在这里,虽然我不确定如何管理工人的数量,所以我不会过多地轮询 MQ 我根本不了解 Cloud MQ 或 AWS - 我唯一担心的是您将自己与一个云提供商捆绑在一起。如果需要队列,我会倾向于适用于任何主机的解决方案。 【参考方案1】:

我会推荐一条不同的路线,那就是使用套接字。 ZMQ 是已经编写的基于套接字的库的示例。使用套接字,您可以创建一个 Q 并在消息进入时管理如何处理它们。机器将处于待机模式并在等待消息进入时使用最少的资源。

【讨论】:

我会在未来需要非常快速的响应并且不需要来自不同后端的持久队列时考虑这个。【参考方案2】:

我的建议基本上可以归结为:保持简单

考虑到这一点,我的第一个建议是删除DispatcherWorker。根据我目前的理解,worker的唯一目的是监听MAIN队列,并将消息转发到不同的任务队列。您的应用程序应该负责将正确的消息排入正确的队列(或主题)。

回答您的问题:

我的工人,会用 PHP 编写,他们都必须轮询云队列服务吗?这可能会变得昂贵,尤其是当你有很多工人时。

是的,没有免费的午餐。当然,您可以按天/周时间(如果您的用户在特定时间处于活动状态)等应用程序使用情况(当更多消息到达时会增加轮询率)来调整和优化您的工作轮询率。请记住,工程成本可能很快就会高于未优化的轮询。

相反,您可以考虑推送队列(见下文)。

我在想可能有 1 个工作人员只是为了轮询队列,如果有消息,通知其他工作人员他们有工作,我只需要使用 supervisord 保持这 1 个工作人员在线吗?这种轮询方法是否比使用可以通知的 MQ 更好?我应该如何轮询 MQ,每秒一次或尽可能快地轮询?如果我看到它变慢了,然后增加投票工作人员?

这听起来太复杂了。通信是不可靠的,但是有可靠的消息队列。如果您不想丢失数据,请坚持使用消息队列,不要发明自定义协议。

我还考虑为所有消息设置一个队列,然后根据需要处理的位置将消息分发到其他云 MQ 的工作人员监控,因为 1 条消息可能需要由 2 个不同的工作人员处理.

如前所述,应用程序应根据需要将您的消息排入多个队列。这使事情变得简单而到位。

我是否还需要 gearman 来管理我的工人,或者我可以只使用 supervisord 来调整工人吗?

有这么多消息队列,甚至还有更多使用它们的方法。一般来说,如果您使用 poll queues,您需要自己让您的工作人员保持活力。但是,如果您使用 推送队列,队列服务将调用您指定的端点。因此,您只需要确保您的员工可用。

基本上我怎样才能尽可能高效地检查 MQ?

这取决于您的业务需求和员工的工作。什么时间跨度是关键的?秒、分、小时、天?如果您使用工作人员发送电子邮件,则不应花费数小时,最好是几秒钟。每 3 秒或每 15 秒轮询一次(对于用户而言)有区别吗?

解决您的问题(使用推送队列):

我的目标是卸载需要发送到多个第三方 API 的消息/数据,因此访问它们不会减慢客户端的速度。因此将数据发送到消息队列是理想的。我考虑过只使用 Gearman 来保存 MQ/Jobs,但我想使用像 SQS 或 Rackspace Cloud Queues 这样的云队列服务,这样我就不必管理消息了。

确实,您描述的场景非常适合消息队列。 正如您所提到的,您不想管理消息队列本身,也许您也不想管理工作人员?这是推送队列出现的地方。

推队列基本上呼叫你的工人。例如,Amazon ElasticBeanstalk Worker Environments 在后台执行繁重的工作(轮询),只需使用包含队列消息 (refer to the docs for details) 的 HTTP 请求调用您的应用程序。我个人使用过 AWS 推送队列,并且对它们的易用性感到满意。请注意,还有其他推送队列提供程序,例如 Iron.io。

正如您提到的,您使用的是 PHP,Symfony 有 QPush Bundle,它处理传入的消息请求。您可以查看代码来推出自己的解决方案。

【讨论】:

谢谢,你是对的。我应该保持简单,应用程序发送到正确的队列。我最终使用了轮询队列,但使用了 Laravel 的 Illuminate Queue 的变体:github.com/illuminate/queue 它支持不同的消息队列,并具有推送器、侦听器和工作器。通过阅读它的代码,我学到了很多东西。我现在有 3 个队列,一个高、正常和低优先级队列,应用程序推送到正确的队列,工作人员按重要性顺序处理所有队列。

以上是关于PHP 中消息队列和工作系统的有效架构?的主要内容,如果未能解决你的问题,请参考以下文章

消息队列RabbitMQ的几种工作模式

基于共享内存的无锁消息队列设计

系统架构分布式消息队列

大型网站架构之分布式消息队列

大型网站架构之分布式消息队列

大型网站架构之分布式消息队列