如何通过 PHP 将 AWS SQS/SNS 用作繁重处理任务的推送通知队列?

How to use AWS SQS/SNS as a push notification queue for heavy processing tasks via PHP?

我在机架空间上有一个服务器 运行,它托管一个 PHP 网络应用程序。

PHP 网络应用程序将接受表单提交,然后需要根据表单字段条目执行任务。

该任务(我们称之为生成元数据任务)需要相当多的处理时间。我想知道如何让表单提交直接保存到数据库并立即向用户显示成功页面,同时 运行 在后台生成元数据任务。

我已经 "aws/aws-sdk-php": "~3.11" 使用 composer 安装到同一个网络应用程序中。

我的计划最初是这样的:

处理表单提交的代码

$result = $model->save($_POST);
// this code will send the information to either SQS or SNS
$awsClient->sendsMessage($_POST);
if ($result) {
  $this->redirect('success.html');
}

我已经阅读了 AWS 声明的 fanout architecture

我对扇出架构示例的问题(据我所知)是这样的:

  1. 将消息发送到 SQS 或 SNS 的服务器也将是处理生成元数据任务的同一台服务器。事实上,它是同一个网络应用程序。
  2. SQS 完成队列部分(因为我想在 FIFO 中执行任务,而任务确实需要很长时间才能完成)。但是,它需要我的网络应用程序连续轮询 SQS。我想要一个推送通知(从 AWS 到我的 Web 应用程序)而不是我的 Web 应用程序不断轮询 AWS 以检查要执行的任务。

我找到了建议的可能解决方案 here

建议的解决方案是:

  1. 将消息发送到 SNS 主题。

  2. SNS 主题将向 SQS 队列和我的 Web 应用程序发送消息。

  3. 我的网络应用程序,在被触发后,将轮询同一个 SQS 队列,该队列现在已经连续排队消息,直到队列为空

我从中看到的缺点是我的网络应用程序将在队列本身有消息之前轮询队列。

使用 AWS 服务实施推送队列的最佳方式是什么?

my web app will poll the queue before the queue itself has the message

那你没试过吧? :) 恐怕你想多了。 SQS 具有 长轮询,这会导致轮询请求在 SQS 端暂停,直到至少有一条消息可用,此时该消息(最多为您请求的最大数量)将被 return 编辑。您可以将长轮询等待时间设置为 1 到 20 秒。如果在此时间范围内没有消息可用,则响应 return 没有消息。

如果您轮询队列以响应来自 SNS 的通知,如果您使用长轮询,您在那里找到消息。消息有可能延迟,但高度不太可能。

但是,另一个问题是您断言您不希望该应用程序不断轮询 SQS。我经常遇到这种反对意见,而且经常放错地方。使用 SQS 长轮询,"constantly" 轮询一个空队列意味着每 20 秒一个请求。那是 3 req/minute, 180 req/hour, 4320 req/day, 129600 req/month... 结果证明少于每个月允许的 100 万个免费请求。

您的服务器对通知做出反应而不是在后台轮询适当数量的工作人员的队列的问题在于,您可能很容易被大约同时到达的大量作业淹没。如果你得到 10 个并发请求,你能处理吗? 100? 1000?通常,对于像这样的异步作业,请求作业的成本(就资源而言)比执行作业的成本低(例如,上传图像需要的 CPU 比调整图像大小要少得多要求)。除非你协调你的反应,否则你可能会压垮你的系统。

不要陷入 "polling is bad, push is good" 不适用的概念陷阱。绝大多数时候,这种观点是绝对正确的……轮询几乎总是错误的解决方案……但是对于 SQS 长轮询,您真正拥有的是一种推送机制,以使其与 HTTP 兼容的方式包装,以及投票的许多固有的邪恶......消失了。如果您正在进行长轮询,队列为空,并且有消息到达,您的长轮询几乎会立即 return 收到该消息。它不会等待超时发生。毕竟,监视队列的后台进程可能是一个好方法。