※このストーリーは、noteで発信した記事を転載しています。
こんにちは!
SREチームでエンジニアリングマネージャーを努めている井上です。
SREチームでは各プロダクトチームと協力しながら、SLOを取り決めて収集しています。
収集はDatadogにて行っており各チームと数値を見ながら改善施策を打ち立て、信頼性の維持・向上のために役立てています。
モバイルアプリのSLO収集において困っていたこと
モバイルアプリにて提供するプロダクトでは、SLOの構成要素としてクラッシュ率を利用するケースがあるかと思います。
DatadogではRUM (Real User Monitoring) を使うことでクラッシュに関する数値を収集できますが、これを直接SLOに設定することはできずカスタムメトリクスを収集してSLOにする必要がありました。
今回設定したいSLOは以下の数式で表現できます。
(総セッション数 - クラッシュしたセッション数)/ 総セッション数
そのためRUMから「総セッション数」と「クラッシュしたセッション数」のカスタムメトリクスを作成していきます。
なおDatadogのSLOについての詳細は、以下をご確認ください。
方針
方針は以下としました。
- RUMイベント収集とカスタムメトリクス送信自体は処理として軽いのでLambdaで実装
- SLOとしての収集を目的としているため、頻度はそれほど高くなくてよい
- 今後別プロダクトでも汎用的に利用できるような形としたい
構成図
上述の方針を基に構成は以下としました。
![]()
構成図
SLOに設定するまでの流れ
RUMにてクラッシュに関する数値をカスタムメトリクスで収集するには、以下のステップが必要です。
- RUMを仕込み、エンドユーザーのイベント情報をDatadogに送信する
- LambdaによってRUMのイベントを取得し、カスタムメトリクスとしてDatadogに送信する
- LambdaはEventBridgeにて定期実行
- Datadogに蓄積されたカスタムメトリクスをベースにSLOを設定する
SARでアプリケーションを作成し展開する
カンリーではAWS Organizationsで各プロダクトごとにAWSアカウントを分けていますが、そのうちの一つに開発者が使う機能を集約したアカウントがあります。
開発者用アカウントにSAR (Serverless Application Repository)を作成し、そのアプリケーションの1つとして作成しました。
SARはアプリケーションをカプセル化して利用できるので、既に作成してある各種リソースを考慮せず展開できる点が大きなメリットです。各チームが使いたいときに使えるようにしています。
またSARの実態はCloudFormationのStackなので、展開したい機能をまとめてテンプレートに興すイメージです。
今回のケースだと、Lambda, EventBridge, IAM Roleなどが該当します。
Stackのサンプルコードは以下です。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: This function is aggregating and submiting Datadog RUM custom metrics
Parameters:
DdApiKey:
Type: String
Description: Datadog API Key
DdAppKey:
Type: String
Description: Datadog APP Key
AppID:
Type: String
Description: App ID
Resources:
# Lambda
DatadogRUMCustomMetricsFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: datadog-rum-custom-metrics
CodeUri: # 関数を配置するS3などを記載
Description: ''
MemorySize: 128
Timeout: 30
Handler: hello.handler
Runtime: provided.al2023 # Goで関数を作成する想定
Architectures:
- arm64
EphemeralStorage:
Size: 512
Environment:
Variables:
DD_API_KEY: !Ref DdApiKey
DD_APP_KEY: !Ref DdAppKey
APP_ID: !Ref AppID
PackageType: Zip
SnapStart:
ApplyOn: None
RuntimeManagementConfig:
UpdateRuntimeOn: Auto
# IAM Role for EventBridge
EventBridgeRole:
Type: AWS::IAM::Role
Properties:
RoleName: datadog-rum-eventbrige-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: scheduler.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: invoke-lambda
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource:
- !GetAtt DatadogRUMCustomMetricsFunction.Arn
# EventBridge Scheduler
EventBridgeScheduler:
Type: AWS::Scheduler::Schedule
Properties:
Name: datadog-rum-custom-metrics-scheduler
ScheduleExpression: cron(0 * * * ? *)
ScheduleExpressionTimezone: "Asia/Tokyo"
FlexibleTimeWindow:
Mode: "OFF"
Target:
Arn: !GetAtt DatadogRUMCustomMetricsFunction.Arn
RoleArn: !GetAtt EventBridgeRole.Arn
SARを展開するには各AWSアカウントにて以下のようなterraformで実行できます。
なおこちらは、SARにてアプリケーションが発行されている前提です。terraformのサンプルコードは以下です。
data "aws_region" "current" {}
data "aws_serverlessapplicationrepository_application" "this" {
application_id = "arn:aws:serverlessrepo:${data.aws_region.current.name}:111111111111:applications/xxx" # アカウントIDとSARで作成したアプリケーション名を入力
}
resource "aws_serverlessapplicationrepository_cloudformation_stack" "this" {
name = "xxx" # アプリケーション名を入力
application_id = data.aws_serverlessapplicationrepository_application.this.application_id
capabilities = data.aws_serverlessapplicationrepository_application.this.required_capabilities
semantic_version = "1.0.0" # SARでのセマンティックバージョンを入力
parameters = {
DdApiKey = # DatadogのAPI Keyを入力
DdAppKey = # DatadogのApplication Keyを入力
AppID = # RUMのApp IDを入力
}
}
カスタムメトリクスを収集した後にはDatadogのSLOを設定します。
SLO設定のためのterraformサンプルコードは以下です。
data "datadog_rum_application" "mobile" {
name_filter = "xxx" # Datadogで作成したRUMの名前
type_filter = "react-native"
}
locals {
total_session = "sum:custom.datadog_rum.session{host:${data.datadog_rum_application.mobile.id}}.as_count()"
crash_session = "sum:custom.datadog_rum.crash_session{host:${data.datadog_rum_application.mobile.id}}.as_count()"
}
resource "datadog_service_level_objective" "datadog_rum" {
name = "SLO Datadog RUM Crash Session"
type = "metric"
query {
numerator = "${local.total_session}-${local.crash_session}"
denominator = local.total_session
}
thresholds {
timeframe = "30d"
target = 99.95
warning = null
}
}
気にしたいポイント
DatadogのAPIはエンドポイント毎でタイムスタンプの取り扱いが違う
Lambdaの関数でRUMのイベント集計とカスタムメトリクスとして送信を行います。
前者は時間を指定する際ISO 8601のフォーマットで、後者はUNIX時間で取り扱う必要があります。
利用したいエンドポイントにて時間の取り扱いは注意してください。
なお、今回利用したエンドポイントは以下です。
カスタムメトリクスの料金
DatadogではInfrastructureのプランによってカスタムメトリクスの考え方が変わります。
いろんな側面で利用できるため便利ですが、闇雲に収集するとコスト増につながるため注意しながら収集してください。
さいごに
今回はRUMで収集したイベントをSLOに設定する仕組みをご紹介しました!
引き続きSLOの改善を行い、信頼性の維持・向上に努めていきます!
カンリーでは一緒に働く仲間を募集しています。
SREはもちろん、全職種で積極的に募集しております。
気になった方はぜひご連絡ください!