本文の内容は、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キューを綿密に監視する必要があります。
しかし、このようなマネージドサービスをどのように監視するのでしょうか?
また、インフラ全体を監視するのと同じ場所から監視できるのでしょうか?
このサービスに関連するメトリクスはすべてAWS CloudWatchで確認できます。WebインターフェイスやAPIから参照することができます。Prometheus対応のモニタリングソリューションからこれらのメトリクスを確認するには、Prometheus exporterを使用します。
ここでは、SQS がどのように機能するのか、Prometheus でモニタリングする方法、および注目すべき主要なメトリクスについて、詳細に掘り下げてみましょう。
AWS SQSキューの仕組みとは?
AWS SQS キューがどのように動作するのか、共通項を決めておきましょう。これにより、後から何を監視してアラートを出すのが重要なのかを簡単に把握することができます。
SQS キュー内のメッセージのワークフローを以下に示します:
- メッセージは、プロデューサーサービスによって作成され、SQS キューに送信されます。
- メッセージは、可能性のあるすべての受信者に対して、キュー内にvisibleとして表示されます。このステップは、即効性がない場合もあります。たとえば、メッセージに「delay」を設定した場合、メッセージは遅延状態でキュー内に残り、delayが切れるまで受信者が利用できなくなります。
- 可能な受信の方法の1つは、SQSキューのメッセージのポーリングを行う。この操作は、キューからvisibleメッセージを取得し、それらをnot Visible状態に切り替えるが、それらを削除しない。これにより、他の受信者が新たなポーリングを実行した場合、それらのメッセージを取得しないようにする。
- 受信者がメッセージの処理を終了した場合、明示的にキューからメッセージを削除します。
さて、受信者がメッセージの処理を終了し、キューから削除しなかった場合はどうなるでしょうか?
設定可能な遅延の後、メッセージは再び可視化され、他の受信者がメッセージを取得して処理できるようになります。
うわー、それは面白そうですね。受信者でエラーを発生させるメッセージを受信した場合、その直後に別の受信者がそのメッセージを受信して再び処理するということです。
その他の受信者もエラーになったら?その後の他のすべての受信者はどうなるのでしょうか?
これは厄介な質問です。
これらの古いメッセージがキューに流入してポールに繰り返し現れるのを防ぐために、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)を使用します。私たちはこのエクスポーターをより効率的で信頼性の高いものにするためにコントリビュートしました。
このユースケースでは、以下を行います:
- CloudWatch エクスポーターを Kubernetes クラスターにデプロイする。
- AWSのSQSのメトリクスを収集するように設定します。
このエクスポーターにはPrometheusタグが便利にアノテーションされているので、PrometheusサーバーとSysdigエージェントの両方がスクレイプすることができます。AWS SQSのメトリクスはCloudWatchで確認できます。Prometheus エクスポーターはCloudWatch APIを通じてそれらをポーリングし、PrometheusサーバーとSysdigエージェントでPrometheus形式で利用できるようにします。
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にデプロイする準備ができています。ということで、あとは:
- CloudWatchから何をスクレイプするかをconfig.ymlファイルで指定します。
- デプロイメントファイルを作成します。
- 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
以下の注意点にご注意ください:
- CloudWatchでは、異なるディメンションによる集計を提供しています。YACE Exporterは自動的にデフォルトのディメンジョンとしてFunctionNameを選択してメトリクスを集約します。
- 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の認証情報を残しておくことは、最も安全なオプションではないことに注意してください。代わりにシークレットストアを使うべきですが、この例ではフォーカスを保つために単純化しています。
このファイルの中には:
- namespace: yace
- エクスポーターを使ったkind: Deployment。アノテーションに注意してください: スクレイピング用の Prometheus タグとスクレイピングポートです。このデプロイメントには2つのボリュームがあります: 1つは設定ファイル、もう1つは資格情報です。
- config.yml ファイルの内容を含む kind: ConfigMap。
- 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 です。
Not visible messages:このメトリクスは、各瞬間に処理されているメッセージの良い指標です。
Not visible messagesとは、受信者によってポーリングされたが、まだ削除されていないメッセージのことです。
この情報を提供するメトリクスは、aws_sqs_approximate_number_of_messages_not_visible_averageです。
Deleted messages:このメトリクスは、受信者によって実際に処理されたメッセージの数を示す良い指標です。
受信者がメッセージを処理するとき、キューから手動でメッセージを削除することを覚えておいてください。
この情報を与えるメトリクスは aws_sqs_number_of_messages_deleted_sum です。
Received messages:Received messagesは、キューから出て行ったメッセージの数です。メッセージがキューから削除されていない場合、メッセージは消費者によって数回受信される可能性があることを考慮に入れてください。
この情報を与えるメトリクスは、aws_sqs_number_of_messages_received_sum です。
Empty receives:このメトリクスでは、空のリクエストが何件行われたかを検出して、アプリケーションのリクエスト作成方法を最適化することができます。
Amazon は、行われたリクエスト数に基づいて SQS に課金します。ポーリングとはリクエストのことで、各リクエストでは、最大 256 KB までの合計ペイロードに対して 1 から 10 までのメッセージを取得することができます。
この情報を与えるメトリクスは、aws_sqs_number_of_empty_receives_sumです。
課金を最適化するには、リクエスト頻度を減らすか、ロングポーリングを使用します。この機能を使用すると、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 です。
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キューとそのデッドレターキューを関連付ける必要がある場合に特に便利です。
PromCat.ioでは、AWS SQSを監視するためのすぐに使える設定とともに、エクスポーターのインストール方法を紹介しています。また、GrafanaとSysdigの両方のフォーマットで紹介したダッシュボードや、サービスのアラートの例も掲載されています。
まとめ
AWS SQSをクラウドネイティブのインフラストラクチャーと同じ場所で監視することが可能です。Prometheusが標準化されたインターフェースを提供しているおかげで、既存のエクスポートツールを活用してPrometheusのメトリクスをインジェストすることができます。
この統合をお試しになりたい方は、AWSマーケットプレイスから直接Sysdig Essentialsの無料トライアルにサインアップすることをお勧めします。
Prometheusの統合についての詳細は、ドキュメントをご覧いただくか、ブログをご覧ください。