本記事では弊チームで新たに導入したモニタリング構成について紹介します。
BigQuery を使って API リクエストを集計する構成で可視化した際の知見を記載してみました。
想定読者
- GCP 環境で複数の集計軸でモニタリングをしたいと考えている方
- サービス全体の可用性だけでなく API x 特定の HTTP Header ごとの可用性を可視化したい、など
- 今回は例として API x UserAgent で集計しましたが、その他にも API x IP Address で集計することも可能です1
背景・モチベーション
弊チームでは社内外のプロダクトから利用される共通プラットフォームを開発しています。
もともと API のリクエストをもとにプラットフォーム全体の Availability や Latency をモニタリングしていたのですが、全体の結果だけでは下記のような気になる動きを見せた場合に別途調査が必要。という状況でした。
- 瞬間的にリクエスト数が増えたが、実際どの API のリクエスト数が増えたの?
- 可用性が低下した場合に、社内のどのプロダクトのチームに影響があるの?
これを改善するために、追加で監視を導入することになりました。
課題
もともと使用していたこともあり、当初は Grafana の機能を使用して集計しようとしました。
ですが、
- API 単位で連携されているデータを API x 特定の HTTP Header の形式で集計するにはどうすれば..?
- API の PATH に含まれるプレースホルダの値を無視して集計するにはどうすれば..?
と Grafana の機能だけで実現するには少し難易度の高い面がありました。
今回は上記のような課題を BigQuery にロジックを集約する形で解決しています。
サービス構成
下図の構成で実現しました。 BigQuery との連携の容易さから BI には Data Portal を使用しています。
簡単な処理の流れとしては下記です。
- Load Balancing のログを Log Router で BigQuery に転送
- BigQuery の View を使用し加工・集計
- Data Portal に連携し可視化
View(BigQuery)
BigQuery の View はデータ加工と集計の二段構えで実装しました。
例として下記の内容を想定したクエリを記載します。
- ゴール
- 直近1日の API x UserAgent2 ごとに 5xx レスポンスを返却した割合を算出する
- クエリ詳細
- API は下記の条件で同一リクエストとみなし集計する
- HTTP Method が異なる場合、別の API リクエストとみなす
- PATH に含まれる ID 等の変数は無視し、変数が異なる場合も同一の API リクエストとみなす
- 今回は ID に UUID を使用している想定で集計します
-
5xx レスポンスを返却した割合は分単位で集計する
- 荒く見たい場合(日単位、等)は Data Portal 側で分単位 -> 日単位に変更することが可能
- API は下記の条件で同一リクエストとみなし集計する
- 補足
- クエリ中の変数にはそれぞれ適した値を使用ください
-
<PROJECT_ID>
: GCP のプロジェクト ID -
<BIGQUERY_DATASET_NAME>
: Log Router が連携している BigQuery のデータセット名 -
<BIGQUERY_TABLE_NAME>
: Log Router が連携している BigQuery のテーブル名
-
- クエリ中の変数にはそれぞれ適した値を使用ください
1. 加工用の View(base_view
)
SELECT
httpRequest.status AS status_code,
httpRequest.userAgent AS user_agent,
TIMESTAMP_TRUNC(timestamp, MINUTE) AS minute_trunc_timestamp,
FORMAT("%s %s",
httpRequest.requestMethod,
REGEXP_REPLACE(
httpRequest.requestUrl,
r'\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b',
'UUID'
)
) AS api
FROM `<PROJECT_ID>.<BIGQUERY_DATASET_NAME>.<BIGQUERY_TABLE_NAME>`
WHERE TIMESTAMP_SUB(CURRENT_TIMESTAMP() , INTERVAL 24 HOUR) < timestamp;
2. 分単位で集計する View(aggregate_view
)
SELECT
minute_trunc_timestamp,
api,
user_agent,
SUM(IF(status_code >= 400 AND status_code < 500, 1, 0)) AS client_error_count,
SUM(IF(status_code >= 500, 1, 0)) AS server_error_count,
SUM(IF(status_code < 400, 1, 0)) AS success_count,
SUM(IF(status_code is not NULL, 1, 0)) AS total_request_count,
FROM `<PROJECT_ID>.<BIGQUERY_DATASET_NAME>.base_view`
GROUP BY
minute_trunc_timestamp, api, user_agent
;
あとは Data Portal にaggregate_view
を連携し server_error_count / total_request_count
の値を可視化すれば完成です3
注意点
- 料金を不要に増やさないようパーティションの設定を推奨します
- Log Router 作成時にパーティション分割テーブルを設定してください
- BigQuery で View の作成時にパーティションをなるべく跨がないよう
WHERE
条件を記載してください- 前述のクエリ例では日ごとにパーティションを設定している想定で下記
WHERE
句を記載していますWHERE TIMESTAMP_SUB(CURRENT_TIMESTAMP() , INTERVAL 24 HOUR) < timestamp;
- 前述のクエリ例では日ごとにパーティションを設定している想定で下記
-
BigQuery の料金監視を推奨します
- パーティションを設定していても、その他の要因(リクエスト数の増加等)により BigQuery の料金が増える可能性があります
その他、本構成で良かった点
本構成は下記の観点から比較的お手軽に実現できたと考えています。
**どういった情報を得られるかわからないけど、ひとまず可視化してみたい。**というユースケースには相性がいいと思います。
- Google のサービスで完結するためデータ連携が容易
- Datadog や Grafana といったサービスとログのデータを連携させる場合、Cloud Pub/Sub や専用の Plugin を使用する必要がでてくると思いますが、Data Portal では標準機能で GCP と連携することができます
- 無料で使用できる範囲が多く費用を抑えられる
- Data Portal の使用にお金がかからないため、金額的に気にすべきは BigQuery だけになります
- BigQuery も無料枠4があり、保存するデータサイズや前述のパーティションに気をつければそこまで増大することはなさそうです
今後の展開
今後の展開として下記などの理由から Data Portal ではなく別のサービスに移行することも考えています。
- データ同期のリアルタイム性を向上させたい
- API リクエスト量が増え UI でグラフの拡大・縮小したい
ですが、 BI を変更することになっても、現状 BigQuery に集計ロジックを集約しているため比較的楽に移行できると考えています。
Special thanks
今回の導入は @i_am_miko さんら弊社 CRE チームのメンバーにも協力してもらいました
参考文献
-
Load Balancing のログ をもとに集計しています。その他のフィールドでも集計することが可能です。 ↩
-
弊社ではサービス識別子を UserAgent に指定する運用となっています。現状社内サービスからの連携が主であり、社内サービスごとに集計するために使用しています。 ↩
-
グラフの値は記事用に適当な値を表示しています。 ↩