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

时间:2015-12-16 05:55:33

标签: php amazon-web-services amazon-sqs amazon-sns

我在rackspace上运行一个托管单个PHP Web应用程序的服务器。

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

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

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

我的计划最初是这样的:

处理表单提交的代码

$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到我的网络应用程序),而不是我的网络应用程序不断轮询AWS以检查要执行的任务。
  3. 我找到了一个可能的建议解决方案here

    建议的解决方案是:

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

    2. SNS主题将同时发送SQS队列和我的网络应用程序。

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

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

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

1 个答案:

答案 0 :(得分:30)

  

我的网络应用会在队列本身有消息之前轮询队列

你还没有尝试过,对吧? :)我担心你会过度思考这个问题。 SQS具有长轮询,这会导致轮询请求在SQS端暂停,直到至少有一条消息可用,此时将返回该消息(最多为您请求的最大数量)。您可以将长轮询等待时间设置为1到20秒。如果在此时间范围内没有可用消息,则返回响应而不发送消息。

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

另一个问题是你断言你不希望应用程序不断轮询SQS。我经常遇到这种反对意见,而且往往是错位的。使用SQS长轮询,“不断”轮询空队列意味着每20秒进行一次请求。这是3 req / minute,180 req / hour,4320 req / day,129600 req / month ......结果是每月少于100万免费请求。

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

在不适用的情况下,不要陷入“轮询不好,推动好”的概念陷阱。在绝大多数情况下,这种情绪绝对是正确的...轮询几乎总是错误的解决方案...但是使用SQS长轮询,你真正拥有的是一种推送机制,其方式使得它与HTTP兼容,以及民意调查的大部分内在......都消失了。如果您正处于长轮询中,队列为空,并且消息到达,您的长轮询将几乎立即返回该消息。它不会等待超时发生。观察队列的后台进程可能是一个很好的方法。