こんにちは!バクラク事業部 Platform Engineering部 SREグループの id:sadayoshi_tadaです。
みなさんは監視ツールとして何を使われていますか?バクラクでは、監視にDatadogを使用しています。この記事ではDatadogのメトリクス収集の課題とそれに対する改善について書きます。
Datadogに収集するメトリクスにおける課題
バクラクではサービスの実行基盤としてAWSを採用しています。AWSのメトリクスをDatadogに収集し、メトリクス監視を行っています。従来はDatadogのGetMetricData APIポーリング(以下、APIポーリングと呼称します)を使用してメトリクス収集を行っていたのですが、APIポーリングは10分間隔でメトリクスを収集します。
この間隔でメトリクスが収集されてアラート通知を行う中で、過去にインシデント発生から遅れてアラート通知が届くことがありました。異常なメトリクス推移があれば可能な限り早くアラート通知されるようにしたいと思い、検知を早めたいメトリクスについてはAPIポーリングからCloudWatch Metric Streamsによるメトリクス収集に一部移行する事を決めました。
CloudWatch Metric Streamsとは
CloudWatch Metric Streamsは、CloudWatchメトリクスをほぼリアルタイムで継続的に選択した送信先(Kinesis Data Firehoseを経由してDatadogにメトリクス転送を行うなど)にプッシュ配信する機能です。
以下の引用文にあるように、CloudWatch Metric StreamsとKinensis Data Firehoseを使用することでDatadogへのメトリクス収集が2-3分の遅延で行われるため、APIポーリング方式より早くメトリクス収集が可能になります。
Using Amazon CloudWatch Metric Streams and Amazon Data Firehose, you can get CloudWatch metrics into Datadog with only a two to three minute latency. This is significantly faster than Datadog’s default API polling approach, which provides updated metrics every 10 minutes.
CloudWatch Metric Streamsで収集するメトリクスのフィルタリング
CloudWatch Metric Streamsでは収集したいメトリクスのNamespaceを指定する必要があります(ex. Application Load Balancerのメトリクスを収集する場合、AWS/ApplicationELB を指定する)。Namespaceを指定しそのサービスに関する全てのメトリクスをDatadogに送信することもできますが、CloudWatch Metric StreamsではDatadogに送信するメトリクスをフィルタリングすることができます。
CloudWatch Metric Streamsは更新されたメトリクスに応じて課金されるため(1,000メトリクス更新につき$0.003)、コスト観点でアラートで使用しないメトリクスは収集しないようにしました。
例えば、以下のスクリーンショットでは、AWS/ApplicationELB の中から収集したいメトリクスとしてHTTPCode_ELB_5XX_Count,HTTPCode_ELB_4XX_Count,UnHealthyHostCountを選択した場合の設定例です。合わせてTargetResponseTimeの統計情報も収集したい場合は、個別のパーセンタイルを指定できます。

Kinesis Data Firehoseを経由したDatadogへのメトリクス転送実装
メトリクスをDatadogに送るためにはCloudWatch Metric Streamsと合わせてKinesis Data FirehoseでDatadogへの転送設定を行う必要があります。私達はこれらの設定をTerraformで行いました。IAMやS3、CloudWatch Logsのコード詳細は割愛していますが、以下がCloudWatch Metric StreamsとKinesis Data Firehoseのコード例です。
# CloudWatch Metric Streams resource "aws_cloudwatch_metric_stream" "alb_metric" { name = "alb-metric-stream" firehose_arn = aws_kinesis_firehose_delivery_stream.alb_metric.arn output_format = "opentelemetry0.7" role_arn = aws_iam_role.cloudwatch_metric_streams.arn include_filter { namespace = "AWS/ApplicationELB" metric_names = [ "HTTPCode_ELB_4XX_Count", "HTTPCode_ELB_5XX_Count", "UnHealthyHostCount", ] } statistics_configuration { additional_statistics = [ "p90", "p99", ] include_metric { namespace = "AWS/ApplicationELB" metric_name = "TargetResponseTime" } } } # Kinesis Data Firehose resource "aws_kinesis_firehose_delivery_stream" "alb_metric" { name = "alb-metric-stream" destination = "http_endpoint" http_endpoint_configuration { name = "Datadog" buffering_interval = 60 buffering_size = 4 retry_duration = 60 role_arn = aws_iam_role.firehose.arn s3_backup_mode = "FailedDataOnly" url = "https://awsmetrics-intake.datadoghq.com/v1/input" secrets_manager_configuration { enabled = true secret_arn = aws_secrets_manger.datadog_api_key.arn role_arn = aws_iam_role.firehose.arn } cloudwatch_logging_options { enabled = true log_group_name = aws_cloudwatch_log_group.cloudwatch_metric_stream.name log_stream_name = aws_cloudwatch_log_stream.http_endpoint_delivery.name } request_configuration { content_encoding = "GZIP" } s3_configuration { bucket_arn = aws_iam_role.firehose_failed_log_bucket.arn buffering_interval = 300 buffering_size = 5 role_arn = aws_iam_role.firehose.arn cloudwatch_logging_options { enabled = true log_group_name = aws_cloudwatch_log_group.cloudwatch_metric_stream.name log_stream_name = aws_cloudwatch_log_stream.s3_backup.name } } } }
実装時に考慮したこととして、Kinesis Data FirehoseとSecrets Managerの統合が昨年発表されたので、Datadog APIキーもSecrets Managerに格納・取得するようにしています。また、執筆時点ではDatadogはCloudWatch Metric StreamsでOpenTelemetry v0.7フォーマットのみサポートしているため、アウトプットフォーマットは固定になります。
Note: Metric streaming to Datadog currently only supports OpenTelemetry v0.7 output format.
CloudWatch Metric Streamsへの切替時の考慮点
APIポーリングからCloudWatch Metric Streamsへの切替時は下記の引用文にあるようにCloudWatch Metric Streamsからのデータを受信すると自動的にAPIポーリングでのメトリクス収集を停止するとあります。
If you already receive metrics for a given CloudWatch namespace through the API polling method, Datadog automatically detects this and stops polling metrics for that namespace once you start streaming them.
ただ、検証してみたところ約10分ほどAPIポーリングとCloudWatch Metric Streamsの収集したメトリクスの重複した時間が発生しました。そのため、移行時にはメトリクス収集が重複した時間を発生しても支障がない時間帯での移行を行いました。
以下のスクリーンショットは、実際の切替時のALBにおけるメトリクス推移になります。赤枠で囲った箇所がメトリクス重複した期間を表しており、約10分ほど経過後は増えたメトリクスが収まっていく様子が見えます。

切り替え後の変化と課題
メトリクス収集が早くなったおかげで、アラート検知と調査対応が早まった体感があります。他方で、コストを見てみると APIポーリングにかかるコストの3分の1ほどCloudWatch Metric Streamsのコストがかかっている状況です。コスト観点で収集するメトリクスを減らしましたが、今後も継続的に不要なメトリクス収集していないかをメンテしてコスト最適化を図っていきます。
まとめ
Datadogのメトリクス収集の課題と、その改善としてAPIポーリングからCloudWatch Metric Streamへの移行についてまとめました。より良い監視体制を築けるように今後もDatadogの改善を試みてその内容を記事にしていきます。
最後に
人々の「働くをラクに。ラクをもっと創造的に。」を目指したプロダクトの信頼性を共に高めていく仲間をSREチームでは募集しています。
まずは話だけでも、という方は是非カジュアル面談や、LayerX Casual Nightといったイベントにぜひ応募ください。