こんにちは、SREの與島(よしま)です。
Topotalでは、SRE as a ServiceというSREを軸にした技術支援サービスを提供しており、これまで何度かSLOの導入支援を行ってきました。
AWSで稼働しているサービスでSLOを導入するときには、ALBメトリクスでSLIを計測するというのがよくあるパターンです。低コストでSLIを計測できる一方で、SLIがユーザー体験と結びつかずサービスの改善につながらないケースがありました。これは、ALBメトリクスがパス単位で区別できず、重要なパスとそうでないパスが同じ指標に混ざるためです。
この課題に対して、ALBログをもとにPath/Host/Method単位でCloudWatchカスタムメトリクスを投稿するLambda関数を開発し、SLI計測の実装コストと有用性の両立を試みました。
この記事では、この取り組みの背景とアプローチを紹介します。なお、開発したLambda関数はOSSとして公開しており、記事の後半でも触れます。
https://github.com/topotal/cloudwatch-alb-path-metrics
ALBメトリクスによるSLIの計測
AWSの典型的なWebサービスでは、ALBメトリクスを利用して低コストでSLIの計測を始められます。Webサービスのようなリクエスト・レスポンス型のサービスにおいては、可用性(成功したリクエストの比率)とレイテンシー(一定時間内に応答できたリクエストの比率)をSLIにすることで一般的なユースケースをカバーできます。ALBメトリクスにはリクエストのステータスコードやレイテンシーを示すメトリクスがあるため、これらを利用して可用性SLIとレイテンシーSLIを計測可能です。実際に導入支援を行ってきた多くのシステムは、ALB + EC2 or ECS + RDS の構成で動いており、SLOをスムーズに導入するにあたって有効な手法でした。
また、CloudWatchメトリクスを基盤にすることで、SLOダッシュボードやバーンレートアラートをCloudWatchダッシュボードやCloudWatch Alarmで作成できるため、関連コンポーネントを含めてAWSサービスだけで完結させられます。
TopotalではSLOを導入するときに「小さく始めること」を推奨しているため、これまでに何度かこの方法を採用してきました。
具体的なSLI定義の例:
| 分類 | 説明 | メトリクス | 計測方法 |
|---|---|---|---|
| 可用性 | 成功したリクエストの比率 | ALBのCloudWatchメトリクスHTTPCode_Target_XXX_Count |
(2XX + 4XX 系のリクエスト) / (2XX + 4XX + 5XX 系のリクエスト) |
| レイテンシー | 一定時間内に応答できたリクエストの比率 | ALBのCloudWatchメトリクスTargetResponseTime |
一定時間内に応答したリクエストの数 / リクエストの総数 |
課題
SLIがユーザー体験と紐づかない
しかし、ALBメトリクスによるSLIはユーザー体験の代替指標として十分に機能しないケースがあります。
ALBメトリクスはロードバランサーもしくはターゲットグループ単位で集約したデータであるため、重要なリクエストとそうではないリクエストを区別できないという性質があります。
その結果、ユーザー影響が少ないエンドポイントのエラーによってSLIが低下してしまったり、SLIが低下してもその重要度が判断しづらいので改善アクションにつなげづらい、といった課題が生じました。いずれもSLIがユーザー体験と紐づいていないことが原因です。
他の計測手法のハードルの高さ
より正確なユーザー体験を示すSLIの計測は、導入のハードルが高くなります。
たとえば、リバースプロキシでのメトリクス収集やアプリケーションへのAPMの組み込みは、より正確なSLIを計測するためのデータを収集する有効な手段ですが、ワークロードの変更や開発チームとの協力が必要になり、ALBメトリクスによるSLIの計測と比較して検証コスト・実装コストがともに高くなります。
Lambda関数 cloudwatch-alb-path-metrics
そこで、より正確なSLIを計測するためのメトリクスを収集できて、なおかつ手軽に導入できる仕組みとしてcloudwatch-alb-path-metricsを開発しました。ALBログがS3バケットに保存されたときのPutObjectイベントをトリガーに起動して、ALBログを集計してCloudWatchカスタムメトリクスとして投稿するLambda関数です。
https://github.com/topotal/cloudwatch-alb-path-metrics
ここでは要点を説明します。詳しい説明はREADMEをご覧いただければと思います。
メトリクスとディメンション
投稿するメトリクスとそのディメンションは次のとおりです。リクエストを区別するためのディメンションを割り当てているのがポイントです。
- メトリクス
TargetResponseTimeRequestCountFailedRequestCount
- ディメンション
PathHostMethod
cloudwatch-alb-path-metricsで収集するメトリクスは可用性SLIとレイテンシーSLIの計測に利用することを想定しているので、それらに必要なメトリクスのみを投稿するようにしています。TargetResponseTimeはレイテンシーSLIの計測に、RequestCountとFailedRequestCountは可用性SLIの計測に利用します。
ディメンションにはPath, Host, Method を割り当てます。これは次のようなリクエストをそれぞれ別のメトリクスとして区別するためです。
- GET https://example.com/users/
- Path:
/users/, Host:example.com, Method:GET
- Path:
- POST https://example.com/users/
- Path:
/users/, Host:example.com, Method:POST
- Path:
- GET https://admin.example.com/users/
- Path:
/users/, Host:admin.example.com, Method:GET
- Path:
高カーディナリティによるコスト増の回避
高カーディナリティのディメンション設計は、メトリクス数の増加とそれにともなうコスト増につながります。
cloudwatch-alb-path-metricsで投稿するメトリクスはSLIの計測に利用することを想定しているので、以下の方針でメトリクス数の増加を抑えるようにしました。
- ユーザー体験に紐づく少数の重要なパスのみを収集対象に指定できるようにする
- パスを正規化してからディメンションに割り当てる
収集対象とパスの正規化ルールはINCLUDE_PATH_RULESという環境変数で指定します。
[ { "host":"example.com", "pattern":"^/users/[0-9]+$", "name":"/users/:id", "method":"GET" }, { "host":"example.com", "pattern":"^/articles/(?:[a-z0-9-]+)/comments$", "name":"/article/:slug/comments" }, { "host":"admin.example.com", "pattern":"^/dashboard(?:/.*)?$", "name":"/dashboard/*", "method":"POST" } ]
メトリクスの遅延による制約
cloudwatch-alb-path-metricsで収集するメトリクスは常に5分遅延します。これは、ALBログのS3バケットへの保存が5分ごとに行われるためです。
SLO運用の観点では、これはバーンレートアラート戦略に影響があります。『サイトリライアビリティワークブック』1では以下の複数ウィンドウ、複数バーンレートのアラートを推奨しています。
| 重要度 | 長期ウィンドウ | 短期ウィンドウ | バーンレート | エラーバジェットの消費 |
|---|---|---|---|---|
| ページ | 1時間 | 5分 | 14.4 | 2% |
| ページ | 6時間 | 30分 | 6 | 5% |
| チケット | 3日間 | 6時間 | 1 | 10% |
このうち、長期ウィンドウ1時間、短期ウィンドウ5分のバーンレートは運用できません。5分遅延のデータでは短期ウィンドウが適切に評価できないためです。
短時間の急激なバーンレートの上昇は検知できませんが、他のバーンレートアラートや定期的なSLO確認には問題なく利用できます。
Amazon CloudWatch Application SignalsのSLO機能を使ったSLO作成
cloudwatch-alb-path-metricsで収集したメトリクスは、Amazon CloudWatch Application Signals(以下Application Signals)のSLO機能と組み合わせて活用できます。Application SignalsでSLOを作成することで、簡易的なSLOダッシュボードやバーンレートアラートなどの関連コンポーネントをAWSサービスだけでかんたんに準備できます。
必要な仕組みを少ない手間で揃えられることは、SLOをスモールスタートするうえで大きな助けになります。
Application SignalsによるSLOの設定例はREADMEに記載しているので、詳細はそちらを参照してください。
まとめ
SLO導入フェーズにおいては、スモールスタートして素早くフィードバックサイクルを回すことが重要だと考えています。SLIをどの程度厳密に計測するかは悩みどころですが、そんなときに手軽でかつそれなりに有用なSLIを計測することを目指して実践している手法を紹介させていただきました。
- 『サイトリライアビリティワークブック』第5章「SLOに基づくアラート」https://www.oreilly.co.jp/books/9784873119137/↩