配置 SQS 死信队列以在收到消息时引发云监视警报

Posted

技术标签:

【中文标题】配置 SQS 死信队列以在收到消息时引发云监视警报【英文标题】:Configure SQS Dead letter Queue to raise a cloud watch alarm on receiving a message 【发布时间】:2020-05-29 08:42:27 【问题描述】:

我在 Amazon SQS 中使用死信队列。我希望每当队列收到新消息时,它都应该引发 CloudWatch 警报。问题是我在指标上配置了一个警报:队列的number_of_messages_sent,但是在Amazon SQS Dead-Letter Queues - Amazon Simple Queue Service 文档中提到的死信队列的情况下,此指标无法按预期工作。

现在对此的一些建议是使用number_of_messages_visible,但我不确定如何在警报中配置它。因此,如果我设置此 metric>0 的值,那么这与在队列中获取新消息不同。如果有旧消息,则度量值将始终为>0。我可以做一些数学表达式来获得这个指标在某个定义的时间段内的增量(比如说一分钟),但我正在寻找一些更好的解决方案。

【问题讨论】:

DLQ 的来源是什么?换句话说,结果是什么导致了 DLQ 的失败?它是一个拉姆达吗? SNS 交付? 我有一个 java 应用程序,它不断地轮询数据并处理它。如果在处理时引发异常,则将其添加到 DLQ。将消息添加到 DLQ 的代码也在我的应用程序中。 所以您是“手动”向您的 DLQ 添加内容?它不是像 lambda 那样的自动 DLQ? 考虑当消息在您的 DLQ 中而不是在收到消息时发出警报:简单地在 ApproximateNumberOfMessagesVisible 上发出警报。从操作的角度来看,只要消息在您的 DLQ 中,您就会遇到问题;只有当 DLQ 为空并且您已处理所有 DLQ 消息时,警报才应从 ALARM 变为 OK。尤其如此,因为您有时间限制来处理 DLQ 消息,因为队列的最长保留期为 14 天。 【参考方案1】:

我遇到了同样的问题,而我的答案是改用 NumberOfMessagesSent。然后我可以为在我配置的时间段内收到的新消息设置我的标准。这就是在 CloudFormation 中对我有用的方法。

请注意,如果警报因持续故障而保持警报状态,则不会发生单独的警报。您可以设置另一个警报来捕捉这些警报。 ie: 1小时内出现100个错误时报警。

已更新:由于 NumberOfMessagesReceived 和 NumberOfMessagesSent 的指标取决于如何消息排队,因此在向 dlq 设置添加延迟后,我使用指标 ApproximateNumberOfMessagesDelayed 为我们的需求设计了一个新的解决方案。如果您手动将消息添加到队列中,则 NumberOfMessagesReceived 将起作用。否则在设置延迟后使用 ApproximateNumberOfMessagesDelayed。

MyDeadLetterQueue:
    Type: AWS::SQS::Queue
    Properties:
      MessageRetentionPeriod: 1209600  # 14 days
      DelaySeconds: 60 #for alarms

DLQthresholdAlarm:
 Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: "Alarm dlq messages when we have 1 or more failed messages in 10 minutes"
      Namespace: "AWS/SQS"
      MetricName: "ApproximateNumberOfMessagesDelayed"
      Dimensions:
        - Name: "QueueName"
          Value:
            Fn::GetAtt:
              - "MyDeadLetterQueue"
              - "QueueName"
      Statistic: "Sum"
      Period: 300  
      DatapointsToAlarm: 1 
      EvaluationPeriods: 2       
      Threshold: 1
      ComparisonOperator: "GreaterThanOrEqualToThreshold"
      AlarmActions:
        - !Ref MyAlarmTopic

【讨论】:

使用 ApproximateNumberOfMessagesDelayed 实际上并不适合我。在我的 sqs 消息传递失败后,我将我的 sqs 配置为将其发送到我的 DLQ。然后查看 CW 仪表板中的图表并使用 NumberOfMessagesReceived 来触发警报,我让它工作了。你能更新你的答案吗 有很多变数,包括消息如何排队。在我们的例子中,我们在状态机中的错误处理以及通过 lambdas 进行了排队。我支持我对答案的更新,因为它处理了更多会导致您的方法失败的场景。延迟必须在队列上正确配置才能使用 ApproximateNumberOfMessagesDelayed。 @alex2017 在此AlramActions 将向SNS 发送事件,而SNS 又发送电子邮件? @Karthik,是的,因为我们对该主题的订阅配置为发送电子邮件。【参考方案2】:

我们遇到了同样的问题,并通过使用 2 个指标并创建一个数学表达式来解决它。

    ConsentQueue:
        Type: AWS::SQS::Queue
        Properties:
            QueueName: "queue"
            RedrivePolicy:
                deadLetterTargetArn:
                    Fn::GetAtt:
                        - "DLQ"
                        - "Arn"
                maxReceiveCount: 3 # after 3 tries the event will go to DLQ
             VisibilityTimeout: 65
    DLQ:
        Type: AWS::SQS::Queue
        Properties:
            QueueName: "DLQ"

    DLQAlarm:
        Type: AWS::CloudWatch::Alarm
        Properties:
            AlarmDescription: "SQS failed"
            AlarmName: "SQSAlarm"
            Metrics:
            - Expression: "m2-m1"
              Id: "e1"
              Label: "ChangeInAmountVisible"
              ReturnData: true
            - Id: "m1"
              Label: "MessagesVisibleMin"
              MetricStat:
                  Metric:
                      Dimensions:
                      - Name: QueueName
                        Value: !GetAtt DLQ.QueueName
                      MetricName: ApproximateNumberOfMessagesVisible
                      Namespace: "AWS/SQS"
                  Period: 300 # evaluate maximum over period of 5 min
                  Stat: Minimum
                  Unit: Count
              ReturnData: false
            - Id: "m2"
              Label: "MessagesVisibleMax"
              MetricStat:
                  Metric:
                      Dimensions:
                      - Name: QueueName
                        Value: !GetAtt DLQ.QueueName
                      MetricName: ApproximateNumberOfMessagesVisible
                      Namespace: "AWS/SQS"
                  Period: 300 # evaluate maximum over period of 5 min
                  Stat: Maximum
                  Unit: Count
              ReturnData: false
            ComparisonOperator: GreaterThanOrEqualToThreshold
            Threshold: 1
            DatapointsToAlarm: 1
            EvaluationPeriods: 1

周期很重要,因此最小值和最大值是在更长的周期内评估的。

【讨论】:

【参考方案3】:

很难实现问题中提出的问题。如果 cloudwatch 警报的端点是发送电子邮件或通知用户 DLQ 消息到达,您可以在 SQS、SNS 和 Lambda 的帮助下做类似的事情。通过 cloudwatch,您可以看到每当您收到任何电子邮件时 DLQ 消息如何按时增长。

    为现有队列创建 SQS DLQ。 创建一个 SNS 主题并订阅该 SNS 主题以发送电子邮件。 创建一个小型 lambda 函数,用于侦听 SQS 队列中的传入消息,如果有任何新传入消息,则将其发送到 SNS。由于 SNS 订阅了电子邮件,因此每当有新消息进入 SQS 队列时,您都会收到电子邮件。显然,lambda 函数的触发器是 SQS,batch size 是 1。
#!/usr/bin/python3
import json
import boto3
import os

def lambda_handler(event, context):
    batch_processes=[]
    for record in event['Records']:
        send_request(record["body"])


def send_request(body):
    # Create SNS client
    sns = boto3.client('sns')

    # Publish messages to the specified SNS topic
    response = sns.publish(
        TopicArn=#YOUR_TOPIC_ARN
        Message=body,    
    )

    # Print out the response
    print(response)

【讨论】:

【参考方案4】:

我使用度量数学函数RATE 来在消息到达死信队列时触发警报。

为您的死信队列选择两个指标 ApproximateNumberOfMessagesVisibleApproximateNumberOfMessagesNotVisible

将度量表达式配置为RATE(m1+m2),将阈值设置为0,并选择比较运算符为GreaterThanThreshold

m1+m2 是给定时间队列中的消息总数。每当有新消息到达队列时,此表达式的速率将高于零。这就是它的工作原理。

【讨论】:

【参考方案5】:

我遇到了同样的问题,即当队列条目自动流入 DLQ 时 Cloudwatch 警报不会触发,我相信我已经找到了解决方案。

你需要设置:

考虑一个时间段,我设置了 5 分钟 通过 SQS 集合为您需要的 dlq 添加一个指标,然后选择“ApproximateNumberOfMessagesVisible”。将统计信息设置为最大值。 复制上述行,并将统计信息设置为最小值。 添加一个新的空表达式 Metric,详细信息为:(最大指标的 id)-(最小指标的 id) 确保只勾选并单击上面创建的新表达式的“选择指标”。

现在应该定期检查 DLQ 中条目数量的差异,无论它们是如何到达那里的,这样我们就可以绕过有问题的指标,例如 NumberOfMessagesSent 或 NumberOfMessagesReceived。

更新:我刚刚意识到这是 Lucasz 上面提到的确切解决方案,因此请认为这是对其有效的确认:)

【讨论】:

【参考方案6】:

您可以做的是创建一个带有事件源的 lambda 作为您的 DLQ。您可以从 Lambda 将自定义指标数据发布到 CloudWatch。当您的数据满足条件时将触发警报。

使用此参考配置您的 lambda,以便在向您的 DLQ 发送消息时触发它:Using AWS Lambda with Amazon SQS - AWS Lambda

这是一个很好的解释,其中包含代码,建议我们如何将自定义指标从 Lambda 发布到 CloudWatch:Sending CloudWatch Custom Metrics From Lambda With Code Examples

一旦发布指标,就会触发 CloudWatch 警报,因为它会匹配指标。

【讨论】:

这种方法的缺点是 DLQ 中的消息实际上会丢失。您希望将它们存储在某个地方,这会产生另一种失败的可能性,尽管肯定会降低。 其实我一直在寻找一种解决方案,使用相同 DLQ 的某些指标来触发警报。 也许保存到云观察日志组就足够了

以上是关于配置 SQS 死信队列以在收到消息时引发云监视警报的主要内容,如果未能解决你的问题,请参考以下文章

AWS SQS:当消费者发生错误时移动到死信队列

当 DLQ 尚不存在时,如何通过 Terraform 配置 SQS?

CloudWatch SQS 指标问题上的 AWS Autoscaling

apache camel - 向死信队列添加消息警报

AWS SQS Boto3 手动将消息发送到死信

Amazon SQS 死信队列:真的是死信还是毒药?