BigQueryでクエリのスキャン量をしきい値にアラートを飛ばしたい

2023.10.24

Google Cloudデータエンジニアのはんざわです。

ご存知の方とも多いと思いますが、BigQueryには従来のオンデマンドと後発のEditionsの2つの料金体系が存在します。
オンデマンドではクエリがスキャンしたデータ量に応じた従量課金制です。
デフォルトの設定ではスキャン量に上限がないため、API側で割り当ての上限を設けるのが一般的な対処法です。

設定した上限をが超えるような場合は次のようなエラーが発生し、クエリを発行できなくなってしまいます。

Custom quota exceeded: Your usage exceeded the custom quota for QueryUsagePerDay, which is set by your administrator. For more information, see https://cloud.google.com/bigquery/cost-controls

このような場合に上限を超える前に事前にアラートを飛ばし、クエリの使い過ぎを通知させたいことがあったのでその方法を共有したいと思います。

アラートの設定手順

1. アラートの通知先を設定する

まずはアラートの通知先を設定します。既に設定されている場合この作業は必要ありません。
コンソール画面のサービス一覧からMonitoringに移動します。

次にアラートに移動し、画面上にある赤枠のEDIT NOTIFICATION CHANNELSをクリックします。

今回はアラート先にメールアドレスを設定します。
Emailの右にあるADD NEWをクリックします。

通知させたいメールアドレスと表示名を入力したら設定完了です。

2. スキャン量の上限を設定する

次にBigQuery APIからスキャン量の上限を設定します。
コンソール画面のサービス一覧からAPIとサービスに移動します。

フィルタからBigQuery APIと検索し、該当した項目をクリックします。

次に割り当てをクリックし、再度フィルタからQuery usage per dayと検索します。

右にある3点リーダーの割り当てアラートを作成からアラートを作成することができます。
しかし、下記のように上限を無制限にしている場合はクリックできないのでまずは上限を設定しましょう。

Query usage per dayのチェックボックスにチェックを入れ、右上の赤枠の割り当てを編集を選びます。

Unlimitedのチェックを外し、上限に適当な数値に設定します。
今回の検証では0.1TB(約100GB)に設定しました。

リクエストを送信をクリックし、しばらくすると上限が反映されます。

3. アラートを作成する

再度、Query usage per dayの右側の3点リーダーから割り当てアラートを作成をクリックします。

下記の画像のようにアラートは最初から用意されており、デフォルトではクエリのスキャン量が上限の80%を超えた際に通知される設定になっています。
また、通知チャンネルには最初に設定したメールアドレスを設定しています。
最後にポリシーの作成をクリックしたらアラート作成完了です。

まずはデフォルト設定での通知内容などを確認してみましょう。

アラートの確認

Monitoring -> アラート -> Policiesから作成したポリシーを確認できます。
下記の画像のグラフの通り、アラートを発生させるために意図的にしきい値以上のスキャン量を消費しました。

しきい値を超えてからしばらくすると最初に設定した通知先に下記の画像のような警告メールが届きました。

件名:[ALERT] Quota usage reached defined threshold for hanzawa-yuya labels {project_id=hanzawa-yuya, service=bigquery.googleapis.com} with metric labels {limit_name=QueryUsagePerDay, quota_metric=bigquery.googleapis.com/quota/query/usage, usage_time_day=20231021}

内容:

期待通りにアラートを受け取ることができました。

アラートをカスタマイズする

Monitoring -> アラート -> Policiesから作成したポリシーを選択し、EDITで既存のアラートを編集することができます。

このアラートポリシーはMonitoring Query Language (MQL)で設定されています。
MQLは他の方法では作成できないようなアラートを作成することができるカスタマイズ性が高いクエリ言語です。

今回のアラートは下記のようなクエリで構成されています。
このクエリをさらに自分好みにカスタマイズすることも可能です。

fetch consumer_quota
| filter resource.project_id == 'hanzawa-yuya'
| { metric serviceruntime.googleapis.com/quota/rate/net_usage
    | filter metric.quota_metric == 'bigquery.googleapis.com/quota/query/usage'
    | map add[metric.limit_name: 'QueryUsagePerDay']
    | map
        add[
          usage_time_day:
            end().timestamp_to_string('%Y%m%d', 'America/Los_Angeles')]
    | group_by
        [resource.project_id, resource.service, metric.quota_metric,
         metric.limit_name, usage_time_day],
        1d, .sum()
  ; metric serviceruntime.googleapis.com/quota/limit
    | filter
        metric.quota_metric == 'bigquery.googleapis.com/quota/query/usage'
        && metric.limit_name == 'QueryUsagePerDay'
    | map
        add[
          usage_time_day:
            end().timestamp_to_string('%Y%m%d', 'America/Los_Angeles')]
    | group_by
        [resource.project_id, resource.service, metric.quota_metric,
         metric.limit_name, usage_time_day],
        1d, .min() }
| ratio
| map
    add[
      aggregation_time_day:
        end().timestamp_to_string('%Y%m%d', 'America/Los_Angeles')]
| filter usage_time_day == aggregation_time_day
| map drop[aggregation_time_day]
| every 30s
| condition gt(val(), 0.8 '1')

試しにアラートのしきい値を80%から50%に下げてみます。
最後の行を次のように変更し、ポリシーを保存をクリックします。

- condition gt(val(), 0.8 '1')
+ condition gt(val(), 0.5 '1')

下記の画像のようにしきい値が50%に変わりました。

まとめ

今回はクエリスキャン量の上限を超える前に事前にアラートを飛ばす方法を紹介しました。
検証ではEmail経由で通知する方法を紹介しましたが、他にもSlackやWebhooks、Pub/Subなど様々な方法で通知チャンネルを設定することが可能なので状況に応じて使い分けてみてください。