PrometheusでAWS SQSを監視する方法

By 清水 孝郎 - FEBRUARY 4, 2021

SHARE:

本文の内容は、2021年2月4日にDavid de Torres Huertaが投稿したブログ(https://sysdig.com/blog/monitor-aws-sqs-prometheus/)を元に日本語に翻訳・再構成した内容となっております。
 
今回は、AWS SQSをPrometheusで監視する方法を解説します。AWS SQSを監視するために、YACE exporter(Yet Another CloudWatch Exporter)を使ってPrometheusにメトリクスをエクスポートしてCloudWatchが提供するデータを活用します。最後に、何を監視し、何をアラートするのかを詳細にみていきます。

AWS SQS (Simple Queue Service)は、非同期アプリケーションの通信やデカップリングを行う方法として人気を集めていますが、特にAWS Lambda関数との統合が容易であることが理由です。

2つのデカップリングされたアプリケーションを持つことで、両極端を独立して実装し、スケールすることができます。このデカップリングを実現するためには、アプリケーション間のメッセージを異なるレートで生成し、処理するためのシステムの準備が必要です。任意のボトルネックは、メッセージが時間通りに処理されない原因となり、システムの全体的なパフォーマンスを損なう可能性があります。

ボトルネックの状況を見つけ、メッセージの生成者と消費者を適切にスケーリングし、可能な限り早くエラーを検出するために、AWSのSQLキューを綿密に監視する必要があります。

しかし、このようなマネージドサービスをどのように監視するのでしょうか?

また、インフラ全体を監視するのと同じ場所から監視できるのでしょうか?

It is possible to monitor AWS SQS next to your cloud-native infrastructure
このサービスに関連するメトリクスはすべてAWS CloudWatchで確認できます。WebインターフェイスやAPIから参照することができます。Prometheus対応のモニタリングソリューションからこれらのメトリクスを確認するには、Prometheus exporterを使用します。

ここでは、SQS がどのように機能するのか、Prometheus でモニタリングする方法、および注目すべき主要なメトリクスについて、詳細に掘り下げてみましょう。

AWS SQSキューの仕組みとは?

AWS SQS キューがどのように動作するのか、共通項を決めておきましょう。これにより、後から何を監視してアラートを出すのが重要なのかを簡単に把握することができます。
The AWS SQS producer send messages to the queue. The delayed messages wait for a bit and the rest are visible. When a receiver procesed a message it becomes invisible until it is processed and removed from the queue.
SQS キュー内のメッセージのワークフローを以下に示します:
  1. メッセージは、プロデューサーサービスによって作成され、SQS キューに送信されます。
  2. メッセージは、可能性のあるすべての受信者に対して、キュー内にvisibleとして表示されます。このステップは、即効性がない場合もあります。たとえば、メッセージに「delay」を設定した場合、メッセージは遅延状態でキュー内に残り、delayが切れるまで受信者が利用できなくなります。
  3. 可能な受信の方法の1つは、SQSキューのメッセージのポーリングを行う。この操作は、キューからvisibleメッセージを取得し、それらをnot Visible状態に切り替えるが、それらを削除しない。これにより、他の受信者が新たなポーリングを実行した場合、それらのメッセージを取得しないようにする。
  4. 受信者がメッセージの処理を終了した場合、明示的にキューからメッセージを削除します。
 
さて、受信者がメッセージの処理を終了し、キューから削除しなかった場合はどうなるでしょうか?

設定可能な遅延の後、メッセージは再び可視化され、他の受信者がメッセージを取得して処理できるようになります。

うわー、それは面白そうですね。受信者でエラーを発生させるメッセージを受信した場合、その直後に別の受信者がそのメッセージを受信して再び処理するということです。

その他の受信もエラーになったら?その後の他のすべての受信はどうなるのでしょうか?

これは厄介な質問です。

これらの古いメッセージがキューに流入してポールに繰り返し現れるのを防ぐために、AWS SQSでは、別のキューをデッドレターとして設定することができます。デッドレターキューとは、何度もポーリングされた後にメッセージが終了するキューのことです。これにより、開発者やサイト運用エンジニアはこれらのメッセージを検知し、適切な方法で処理することができます。
 

PrometheusのメトリクスでAWS SQSを監視する

SQS キューがどのように動作するかを理解したところで、それらを使って作業している間に見つけられる可能性のあるすべての状況に対処するためのメトリクスをどのようにして取得できるかを見てみましょう。
 
AWS SQS は、CloudWatch サービスが AWS/SQS というネームスペースの下で収集できる特定のメトリクスを放出します。ここでは、これらのメトリクスを抽出して、PrometheusでAWS SQSを監視できるようにする方法を見ていきます。
 
Prometheusはオープンソース監視ソリューションの代表格であり、エクスポーターを記述することで簡単に統合を作成する手段を提供しています。Prometheusを利用することで、複数のクラウドプロバイダーにまたがっている可能性のあるインフラ全体からメトリクスを収集することができます。
 
Prometheusのエクスポーターは、サービスからメトリクスを収集し、PrometheusサーバーとSysdigエージェントの両方がネイティブにスクレイプできる標準化されたフォーマットで公開します。AWS CloudWatchからメトリクスを取得するために、YACE exporter (Yet Another CloudWatch Exporter)を使用します。私たちはこのエクスポーターをより効率的で信頼性の高いものにするためにコントリビュートしました
 
このユースケースでは、以下を行います:
 
  1. CloudWatch エクスポーターを Kubernetes クラスターにデプロイする。
  2. AWSのSQSのメトリクスを収集するように設定します。
このエクスポーターにはPrometheusタグが便利にアノテーションされているので、PrometheusサーバーとSysdigエージェントの両方がスクレイプすることができます。AWS SQSのメトリクスはCloudWatchで確認できます。Prometheus エクスポーターはCloudWatch APIを通じてそれらをポーリングし、PrometheusサーバーとSysdigエージェントでPrometheus形式で利用できるようにします。
AWS SQS metrics are available in CloudWatch. The Prometheus Exporter polls them through the CloudWatch API and makes them available in Prometheus format for Prometheus Servers and Sysdig Agents.
 
 

Prometheus CloudWatch エクスポーターのインストールと設定

CloudWatchメトリクスへのアクセス許可の設定

エクスポーターはAWS CloudWatch APIに接続してメトリクスを引っ張ってきますが、メトリクスを取得するためには正しいパーミッションを付与する必要があります。
 
まず、以下のパーミッションを含むAWS IAMポリシーを作成する必要があります。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "CloudWatchExporterPolicy",
            "Effect": "Allow",
            "Action": [
                "tag:GetResources",
                "cloudwatch:ListTagsForResource",
                "cloudwatch:GetMetricData",
                "cloudwatch:ListMetrics"
            ],
            "Resource": "*"
        }
    ]
}

AWS IAMポリシーを設定する

 
また、AWS IAMアカウントの資格情報をCloudWatch エクスポーターに提供する必要があります。これは標準的な方法で、$HOME/.aws/credentialsファイルで行うことができます。

# CREDENTIALS FOR AWS ACCOUNT
aws_region = us-east-1
aws_access_key_id = AKIAQ33BWUG3BLXXXXX
aws_secret_access_key = bXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
HOME/.aws/credentialsファイルにAWSのIAMアカウントを設定します。
 
IAMポリシーを直接IAMアカウントに割り当てるか、IAMロールに割り当ててエクスポータに権限を付与することもできます。
 

エクスポーターの設定

YACE エクスポーターには、Stable版のイメージがあり、Kubernetesにデプロイする準備ができています。ということで、あとは:
 
  1. CloudWatchから何をスクレイプするかをconfig.ymlファイルで指定します。
  2. デプロイメントファイルを作成します。
  3. Kubernetesクラスターにデプロイする。
設定ファイルに注目してみましょう。ここでは、以下のように定義します:
 
  • エクスポータがスクレイプするメトリクス
  • どのリージョンから
  • CloudWatchにどのようなディメンジョンで集約を行うか
以下に config.yml 設定ファイルの例を示します:
discovery:
  jobs:
  - regions: 
    - us-east-1
    type: sqs
    enableMetricData: true
    metrics: 
      - name: ApproximateAgeOfOldestMessage
        statistics:
        - Maximum
        period: 300
        length: 3600
      - name: ApproximateNumberOfMessagesDelayed
        statistics:
        - Average
        period: 300
        length: 3600
      - name: ApproximateNumberOfMessagesNotVisible
        statistics:
        - Average
        period: 300
        length: 3600
      - name: ApproximateNumberOfMessagesVisible
        statistics:
        - Average
        period: 300
        length: 3600
      - name: NumberOfEmptyReceives
        statistics:
        - Sum
        period: 300
        length: 3600
      - name: NumberOfMessagesDeleted
        statistics:
        - Sum
        period: 300
        length: 3600
      - name: NumberOfMessagesReceived
        statistics:
        - Sum
        period: 300
        length: 3600
      - name: NumberOfMessagesSent
        statistics:
        - Sum
        period: 300
        length: 3600
      - name: SentMessageSize
        statistics:
        - Average
        - Sum
        period: 300
        length: 3600

以下の注意点にご注意ください:
 
  1. 追加のメトリクスを追加したい場合は、正しい統計量を使用するためにAWS SQSメトリクスを必ずお読みください。
  2. CloudWatchでは、異なるディメンションによる集計を提供しています。YACE Exporterは自動的にデフォルトのディメンジョンとしてFunctionNameを選択してメトリクスを集約します。
  3. CloudWatchのメトリクスを収集すると、AWSの請求書に一定のコストが発生することがあります。CloudWatchのサービスクォータの制限については、AWSのドキュメントを必ず確認してください。
最後のステップは、実際にYACE exporterをデプロイすることです。簡単にするために、IAMアカウントの資格情報と設定をファイルにまとめておくと、以下のようになります。

apiVersion: v1
kind: Namespace
metadata:
  name: yace
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: yace-sqs
  namespace: yace
spec:
  selector:
    matchLabels:
      app: yace-sqs
  replicas: 1
  template:
    metadata:
      labels:
        app: yace-sqs
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "5000"
    spec:
      containers:
      - name: yace
        image: quay.io/invisionag/yet-another-cloudwatch-exporter:v0.21.0-alpha
        ports:
        - containerPort: 5000
        volumeMounts:
          - name: yace-sqs-config
            mountPath: /tmp/config.yml
            subPath: config.yml
          - name: yace-sqs-credentials
            mountPath: /exporter/.aws/credentials
            subPath: credentials
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
      volumes:
        - configMap:
            defaultMode: 420
            name: yace-sqs-config
          name: yace-sqs-config
        - secret:
            defaultMode: 420
            secretName: yace-sqs-credentials
          name: yace-sqs-credentials
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: yace-sqs-config
  namespace: yace
data:
  config.yml: |
    discovery:
      jobs:
      - regions: 
        - us-east-1
        type: sqs
        enableMetricData: true
        metrics: 
          - name: ApproximateAgeOfOldestMessage
            statistics:
            - Maximum
            period: 300
            length: 3600
          - name: ApproximateNumberOfMessagesDelayed
            statistics:
            - Average
            period: 300
            length: 3600
          - name: ApproximateNumberOfMessagesNotVisible
            statistics:
            - Average
            period: 300
            length: 3600
          - name: ApproximateNumberOfMessagesVisible
            statistics:
            - Average
            period: 300
            length: 3600
          - name: NumberOfEmptyReceives
            statistics:
            - Sum
            period: 300
            length: 3600
          - name: NumberOfMessagesDeleted
            statistics:
            - Sum
            period: 300
            length: 3600
          - name: NumberOfMessagesReceived
            statistics:
            - Sum
            period: 300
            length: 3600
          - name: NumberOfMessagesSent
            statistics:
            - Sum
            period: 300
            length: 3600
          - name: SentMessageSize
            statistics:
            - Average
            - Sum
            period: 300
            length: 3600
---
apiVersion: v1
kind: Secret
metadata:
  name: yace-sqs-credentials
  namespace: yace
data:
  # Add in credentials the result of:
  # cat ~/.aws/credentials | base64
  credentials: |
    XXX

デプロイメントファイルの中にAWSの認証情報を残しておくことは、最も安全なオプションではないことに注意してください。代わりにシークレットストアを使うべきですが、この例ではフォーカスを保つために単純化しています。
 
このファイルの中には:
 
  1. namespace: yace
  2. エクスポーターを使ったkind: Deployment。アノテーションに注意してください: スクレイピング用の Prometheus タグとスクレイピングポートです。このデプロイメントには2つのボリュームがあります: 1つは設定ファイル、もう1つは資格情報です。
  3. config.yml ファイルの内容を含む kind: ConfigMap。
  4. kind: Secret には IAM アカウントの認証情報が入っています。
 
あとは、いつものようにデプロイするだけです:

kubectl apply -f deploy.yaml

 動作していますか?
 
エクスポーターポートにHTTPリクエストを投げるテストをしてみましょう。これを行うには、ウェブブラウザを使用するか、コンソールでcurlを使用します。例のポッドyace-sqsではポートを5000に設定しているので、以下のようにします。

curl http://<our machine>:5000/metrics
 
問題なければ、このようなメトリクスのWebページが表示されるはずです(サイズの関係で出力は切り捨てています)。

# HELP aws_sqs_approximate_age_of_oldest_message_maximum Help is not implemented yet.
# TYPE aws_sqs_approximate_age_of_oldest_message_maximum gauge
aws_sqs_approximate_age_of_oldest_message_maximum{dimension_QueueName="queue_01",name="arn:aws:sqs:us-east-1:029747528706:queue_01",region="us-east-1"} 2
# HELP aws_sqs_approximate_number_of_messages_delayed_average Help is not implemented yet.
# TYPE aws_sqs_approximate_number_of_messages_delayed_average gauge
aws_sqs_approximate_number_of_messages_delayed_average{dimension_QueueName="queue_01",name="arn:aws:sqs:us-east-1:029747528706:queue_01",region="us-east-1"} 3
# HELP aws_sqs_approximate_number_of_messages_not_visible_average Help is not implemented yet.
# TYPE aws_sqs_approximate_number_of_messages_not_visible_average gauge
aws_sqs_approximate_number_of_messages_not_visible_average{dimension_QueueName="queue_01",name="arn:aws:sqs:us-east-1:029747528706:queue_01",region="us-east-1"} 12
# HELP aws_sqs_approximate_number_of_messages_visible_average Help is not implemented yet.
# TYPE aws_sqs_approximate_number_of_messages_visible_average gauge
aws_sqs_approximate_number_of_messages_visible_average{dimension_QueueName="queue_01",name="arn:aws:sqs:us-east-1:029747528706:queue_01",region="us-east-1"} 1
 

AWS SQSの監視:何を探すべきか?

AWS SQSキューはシンプルな設計なので、監視すべきことはあまりありません。しかし、どのように使用しているかによっては、異なるメトリクスのセットを監視したくなるでしょう。
 
いくつかのシナリオと関連するメトリクスを探ってみましょう。
 

シンプルなプロデューサー– 消費者

このアプローチでは、メッセージを処理しているのはプロデューサーと消費者だけであると考えます。我々は、遅延メッセージやデッドレター・キューをカバーしません。
 
Visible messages:このメトリクスは、システムのサチュレーションについての情報を与えます。
 
Visible messagesとは、処理の準備ができているが、まだ受信者によってポーリングされたり削除されたりしていないメッセージのことです。これは、キューにどれだけの保留メッセージがあるかの良い指標になります。
 
この情報を提供するメトリクスは aws_sqs_approximate_number_of_messages_visible_average です。
PromQL ダッシュボードのパネルでは、Visible messagesのスパイクが表示されています。 
Not visible messages:このメトリクスは、各瞬間に処理されているメッセージの良い指標です。
 
Not visible messagesとは、受信者によってポーリングされたが、まだ削除されていないメッセージのことです。
 
この情報を提供するメトリクスは、aws_sqs_approximate_number_of_messages_not_visible_averageです。
PromQL ダッシュボード パネルでは、表示されていないメッセージが急増しています。
 
Deleted messagesこのメトリクスは、受信者によって実際に処理されたメッセージの数を示す良い指標です。
 
受信者がメッセージを処理するとき、キューから手動でメッセージを削除することを覚えておいてください。
 
この情報を与えるメトリクスは aws_sqs_number_of_messages_deleted_sum です。
削除されたメッセージのスパイクを示す PromQL ダッシュボード・パネル。

Received messagesReceived messagesは、キューから出て行ったメッセージの数です。メッセージがキューから削除されていない場合、メッセージは消費者によって数回受信される可能性があることを考慮に入れてください。
 
この情報を与えるメトリクスは、aws_sqs_number_of_messages_received_sum です。
受信したメッセージのスパイクを示す PromQL ダッシュボードパネル。
Empty receivesこのメトリクスでは、空のリクエストが何件行われたかを検出して、アプリケーションのリクエスト作成方法を最適化することができます。
 
Amazon は、行われたリクエスト数に基づいて SQS に課金します。ポーリングとはリクエストのことで、各リクエストでは、最大 256 KB までの合計ペイロードに対して 1 から 10 までのメッセージを取得することができます。
 
この情報を与えるメトリクスは、aws_sqs_number_of_empty_receives_sumです。
PromQL ダッシュボード パネルで、空の受信数のスパイクを表示しています。 
課金を最適化するには、リクエスト頻度を減らすか、ロングポーリングを使用します。この機能を使用すると、10秒間、表示されているメッセージを受信することができます。さらに、リアルタイムで到着するすべてのメッセージを受信することで、リクエストの回数を減らすことができます。
 

メッセージを遅延させることができるプロデューサーを監視する

メッセージを処理するのに必要な時間を見積もることができれば、プロデューサーはメッセージに遅延を加えることができます。メッセージ間に時間を空けることで、同時に送信される大量のメッセージによるボトルネックを軽減することができます。
 
このシナリオで追跡する価値のある追加のメトリクスは以下の通りです:
 
Delayed messagesこのメトリクスは、次の数分後にやってくる仕事の負荷に合わせて、受信者の数を増減させるのに役立ちます。
 
キューに遅延したメッセージの数は、aws_sqs_approximate_number_of_messages_delayed_average というメトリクスで知ることができます。
 
プロデューサがKubernetesでデプロイされている場合は、Kubernetes horizontal pod autoscaler(HPA)Prometheusアダプターを使用して、このメトリクスの値に応じてポッドの数を調整することができます。
 
キュー内のメッセージの総数:メッセージの数は、パイプラインの占有率とサチュレーションを知ることができます。
 
送信者が生成したメッセージの数と、まだ処理を待っているメッセージの数の推定値を持つために、遅延メッセージ、Visible(受信者に送信する準備ができている)とnot Visible(現在処理中)を合計することができます。メッセージの処理が即時であった場合、この結果は0になります。
 
この値を生成する promQL は:
 
aws_sqs_approximate_number_of_messages_delayed_average  + aws_sqs_approximate_number_of_messages_not_visible_average + aws_sqs_approximate_number_of_messages_visible_average
 

デッドレターキューへの対応

デッドレターキューを扱っている間は、メッセージがいつキューに到着するかを監視することが重要です。
 
Sent messagesこれは、受信者が処理できなかったエラーやメッセージのアイデアを与えることができます。
 
この情報を与えるメトリクスは aws_sqs_number_of_messages_sent_sum です。
送信されたメッセージのスパイクを示すPromQLダッシュボードパネル。 

AWS SQSの監視:何をアラートするか?

長時間キューに入っているメッセージ数が多い: キュー内のメッセージの総数は、パイプラインがサチュレーションしていることを示すメトリクスです。制限値(100メッセージなど)を設定して、それ以上のメッセージ数が長時間続いた場合にアラームを受け取ることができます。
 
(aws_sqs_approximate_number_of_messages_delayed_average  + aws_sqs_approximate_number_of_messages_not_visible_average + aws_sqs_approximate_number_of_messages_visible_average) > 100
 
このアラートは、デッドレターキューが設定されていない場合に、Visible状態に戻ってくるメッセージを繰り返し検出することもできます。
 
キュー内の最も古いメッセージ:このメトリクスは、キューの最も古いメッセージの経過時間を示します。これは、パイプラインの最大遅延の優れたメトリクスです。 このアラートは、最大Ageが5分(300秒、必要に応じて調整可能)を超えるとトリガーされます。
 
aws_sqs_approximate_age_of_oldest_message_maximum > 300
 
このアラートが正しく動作するためには、メッセージがVisible状態に再帰的に送信されるのを防ぐために、デッドレターキューを設定する必要があります。
 
Recurring empty receivesアプリケーションが空のキューから新しいメッセージをフェッチしようとしていることを検出することができます。これにより、ポーリング頻度や受信者の数を調整して、インフラストラクチャーのコストを下げることができます。
 
aws_sqs_number_of_empty_receives_sum > 0
 
デッドレター・キューにメッセージを受信:新しいメッセージがデッドレターキューに到着したかどうかを、送信されたメッセージメトリクスでアラートすることで検出できます。デッドレターキューをフィルタリングするには、さまざまな方法があります。例えば、デッドレターキューに dead-letter- のようなプレフィックスをつけて名前をつけることができます。
 
この promQL は、デッドレターキューのいずれかにメッセージが到着したときにアラートを発します:
 
aws_sqs_number_of_messages_sent_sum{dimension_QueueName=~"dead-letter-.+"} > 0
 

CloudWatchのメトリクスをSysdig Monitorに取り込む

Sysdigエージェントの設定

Sysdigエージェントを使用してメトリクスをスクレイピングするには:
 
yace Deploymentでは、エクスポーターのポートをスクレイピングポートとして設定するPrometheusアノテーションを忘れずにインクルードしてください。
 
また、Sysdigエージェントの設定では、Prometheusアノテーションでコンテナのスクレイピングを有効にする以下の行があることを確認してください。
 
process_filter:
  - include:
      kubernetes.pod.annotation.prometheus.io/scrape: true
      conf:
        path: "{kubernetes.pod.annotation.prometheus.io/path}"
        port: "{kubernetes.pod.annotation.prometheus.io/port}"
 

ダッシュボードとアラートでAWS SQSを監視する

Sysdig MonitorでSQSのメトリクスを取得したら、AWS SQSダッシュボードを使ってキューの全体像を把握することができます。ダッシュボードでは、クラスターごとにフィルタリングしたり、必要な数だけSQSキューを選択したりすることができます。これは、SQSキューとそのデッドレターキューを関連付ける必要がある場合に特に便利です。
Sysdig Monitor:AWS SQS ダッシュボード
Sysdig Monitor:AWS SQS ダッシュボード
 
PromCat.ioでは、AWS SQSを監視するためのすぐに使える設定とともに、エクスポーターのインストール方法を紹介しています。また、GrafanaとSysdigの両方のフォーマットで紹介したダッシュボードや、サービスのアラートの例も掲載されています。
 

まとめ

AWS SQSをクラウドネイティブのインフラストラクチャーと同じ場所で監視することが可能です。Prometheusが標準化されたインターフェースを提供しているおかげで、既存のエクスポートツールを活用してPrometheusのメトリクスをインジェストすることができます。
 
 
Prometheusの統合についての詳細は、ドキュメントをご覧いただくか、ブログをご覧ください