并行轮询AWS SQS标准队列-消息处理太慢

时间:2018-11-23 13:28:04

标签: java amazon-ec2 aws-sdk amazon-sqs

我有一个模块,该模块以指定的时间间隔ReceiveMessageRequest一次轮询一个AWS消息队列。方法如下:

public static ReceiveMessageResult receiveMessageFromQueue() {

    String targetedQueueUrl = sqsClient.getQueueUrl("myAWSqueueName").getQueueUrl();
    ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(targetedQueueUrl)
            .withWaitTimeSeconds(10).withMaxNumberOfMessages(1);
    return sqsClient.receiveMessage(receiveMessageRequest);
}

一旦收到并处理了一条消息,它就会使用DeleteMessageResult从队列中删除。

public static DeleteMessageResult deleteMessageFromQueue(String receiptHandle) {

    log.info("Deleting Message with receipt handle - [{}]", receiptHandle);
    String targetedQueueUrl = sqsClient.getQueueUrl("myAWSqueueName").getQueueUrl();
    return sqsClient.deleteMessage(new DeleteMessageRequest(targetedQueueUrl, receiptHandle));

}

我创建了一个可执行的jar文件,该文件部署在大约40个实例中,并正在主动轮询队列。我可以看到他们每个人都收到消息。     但是在AWS SQS控制台中,我在“飞行消息”列中只能看到数字0、1、2或3。为什么即使有40多个不同的使用者都从队列中接收消息,也为什么呢?另外,队列中可用消息的数量减少得非常缓慢。

以下是队列的配置参数。

Default Visibility Timeout: 30 seconds
Message Retention Period:   4 days
Maximum Message Size:   256 KB
Receive Message Wait Time:  0 seconds
Messages Available (Visible):   4,776
Delivery Delay: 0 seconds
Messages in Flight (Not Visible):   2
Queue Type: Standard
Messages Delayed:   0
Content-Based Deduplication:    N/A 

为什么即使有多个使用者也无法快速处理消息?我是否需要修改任何队列参数或接收消息/删除消息请求中的某些内容?请告知。

更新:

所有EC2实例和SQS都位于同一区域。使用者(轮询队列的jar文件)作为EC2实例启动脚本的一部分运行。而且它有一个计划的任务,每12秒轮询一次队列。在将消息推送到队列之前,我启动了2-3个实例。 (当时我们可能有一些已经在运行的实例-这将增加队列的接收方数量(上限为50)。收到消息后,它将执行一些任务(包括一些数据库操作,数据分析和计算,报告文件)生成报告并将其上传到S3等。)大约需要10到12秒。完成后,它将删除队列中的消息。下图是过去1周的SQS指标的屏幕截图(来自SQS)监视控制台)。

SQS Metrics for the targeted Queue for last 1 week

1 个答案:

答案 0 :(得分:4)

我将尽力提供所提供的信息。有关处理循环逻辑,区域设置和指标的更多详细信息(请参阅下文)将有助于改善此答案。

  

我创建了一个可执行的jar文件,该文件部署在大约40个实例中,并正在主动轮询队列。我可以看到他们每个人都收到消息。但是在AWS SQS控制台中,我在“飞行消息”列中只能看到数字0、1、2或3。为什么即使有40多个不同的使用者都从队列中接收消息,也为什么呢?另外,队列中可用消息的数量减少得非常缓慢。

     

为什么即使有多个使用者也无法快速处理消息?我是否需要修改任何队列参数或接收消息/删除消息请求中的某些内容?

您没有看到与正在处理邮件的主机数量更紧密相关的机上号码这一事实肯定说明了一个问题-邮件处理速度很快(似乎不是情况),否则您的房东没有按照您认为的去做。

通常,从SQS提取和删除单个消息应花费几毫秒的时间。如果没有更多详细的设置,这应该可以帮助您开始进行故障排除。 (其中一些步骤似乎很明显,但是其中每一个都是我见过开发人员遇到的现实生活问题的来源。

  1. 如果您要为每个receive-process-delete启动一个新进程,那么此开销将使您的速度大大降低。我假设您没有这样做,并且每个主机都在单个进程中运行一个循环
  2. 验证您的处理循环不会使您丧命并重新启动您(有效地将其转化为上述情况)。
    • 我认为您还已经验证了您的流程在消息处理之外还没有做很多工作。
  3. 您应该生成一些客户端指标,以指示SQS请求在每个主机上花费的时间。
    • Cloudwatch将部分为您执行此操作,但是实际的客户端指标始终很有用。
    • 推荐以下基本指标:(1)接收延迟,(2)进程延迟,(3)删除延迟,(4)整个消息循环延迟(5)成功/失败计数器
  4. 您的EC2实例(执行处理的主机)应与SQS队列位于同一区域。如果您正在进行跨区域呼叫,这将影响您的延迟。
    • 确保这些主机具有足够的CPU /内存资源来进行处理
    • 作为一种优化,我建议每台主机使用更多的线程,而更少的主机-重用客户端连接并最大化计算资源的使用率总是更好的。
  5. 验证运行测试时没有中断或持续的问题
  6. 在某些初始化步骤中,仅执行一次getQueueUrl即可在应用程序的生命周期内执行一次。您不需要重复调​​用它,因为它是相同的URL
    • 这实际上是我在您的代码中注意到的第一件事,但这已经很困难了,因为上述问题如果是起因,则会产生更大的影响。
  7. 如果您的消息处理时间非常短(比检索和删除消息所需的时间短),那么最终您的主机将花费大部分时间来提取消息。衡量指标也很重要。
    • 在这种情况下,您应该应该批量提取而不是一次一次。
    • 根据您队列中的邮件数量以及运行缓慢的评论,听起来好像并非如此。
  8. 验证所有主机是否实际上都在同一队列中(而不是某个时候用于测试的某些beta / gamma版本或较旧版本)

更多说明:

  • 另一个答案表明可见性超时是一个潜在原因-这完全是错误的。可见性超时不会阻塞队列-仅 影响消息在另一个receiveMessageRequest接收该消息之前“进行中”的时间。
  • 如果您想在出现错误/处理器速度较慢时尝试尽快重新处理邮件,则可以考虑减少此费用。