こちらの記事は、アソビュー! Advent Calendar 2024の23日目(表面)です。
はじめに
アソビューのデータ基盤チームでデータエンジニアをやっている米澤です。
今回は、BigQueryのジョブ実行権限とデータ閲覧権限をプロジェクト単位で分けることで、BigQueryのクエリ上限設定を行う方法をご紹介したいと思います。
対応の目的
まず、なぜこの対応を行う必要があるのか?をご説明します。
ご存知の方は多いと思いますが、Google CloudのDWHサービスであるBigQueryは、以下2つの点で課金が発生します。
- ストレージ(データ保存)
- コンピュート(クエリジョブ実行)
ストレージ費用
ストレージの詳細な費用はGoogleのストレージ料金のページを見ると分かります。または、Googleが提供しているPrice Calculatorの方が分かりやすいかもしれません。
費用は契約内容やLocation Typeで変化しますが、契約=On-Demand & Location Type=Multi-region(US)の条件で「20TB」のデータを保持していたとしても、「$400=¥60,000/月」程度(1$=150円計算)です。企業の1事業(サービス)単位であれば「100TB」もデータはないと思います。
数千数万人単位の大企業であればPB(ペタバイト)くらいのかなり大きなデータ量になるとは思いますが、その規模の大企業からすれば利用料はたいした額ではありません。
つまり、ストレージ費用は企業にとってそれほど大きな負担にはならない、ということです。
コンピュート費用
BigQueryの費用の大半は、SQLクエリジョブを実行する際にスキャンするデータ量から算出されるコンピュート費用です。
ストレージ費用同様、コンピュートの費用もヘルプページで分かります。こちらも契約内容、Regionで異なりますが、On-Demand契約で、一番安いUS Regionで「$6.25/TB」です。
しかし、ストレージとは異なり、例えば10TBほどのデータしかBigQueryに格納していないとしても、仮に1TBと1TBのテーブルをJOINすれば、JOINのやり方によってはその数倍のデータ量をスキャンする結果となり、費用はどんどん加算されていきます。ストレージ費用は静的なデータにかかる費用なので月によって大きくブレることはありませんが、コンピュート費用は使い方次第で大きく変動します。
つまり、BigQueryのコスト管理=コンピュート費用管理、と言えます。コスト管理は、どのようにコンピュート使用料をモニタリングし、適切に制限するかが肝になります。
ただし、もちろんモニタリングも重要なのですが、仮に今日誰かが非常に高コストなクエリを実行したとして、明日それが判明したとしても、今日使ったコストが返ってくるわけではありません。事後予防も大事ですが、事前予防が最も重要。今回ご紹介する「クエリ上限設定」は、この事前予防を行うための機能になります。
クエリ上限設定とは
「クエリ上限設定」自体はそれほど難しい機能ではないのですぐに実行できます。
設定方法は他サイトにいくらでも情報が転がっていますので、説明はそちらに譲りたいと思います(こちらのページはまとまっていて非常にわかりやすいです)。
上記ページにも記載ある通り、設定は以下2種類あります。
- Query usage per day
- Query usage per day per user
「Query usage per day」は文字通り、1日のスキャンデータ量を制限します。また、「 Query usage per day per user」は、1日&1ユーザのスキャンデータ量を制限します。
重要なことは、この設定は「プロジェクト単位」でしか行えません。
つまり、上記1の制限であれば、一度上限に達してしまうと、問答無用でそのプロジェクトでBigQueryクエリジョブ実行できなくなります。上記2はユーザ単位なので、あるユーザが上限に達しても、別ユーザには影響がありませんが、例えばある部署のユーザは無制限の設定にしたい、という要望には答えられません。
今回紹介するのは、この要望を実現する方法になります。
なお、クエリ上限設定を行ってクエリスキャン量の制限を行う必要があるのはOn-Demand契約の場合のみで、Editions契約の場合は料金体系が異なるため行う必要がない、いうことは留意しておいてください。
BigQueryの権限
まず、BigQueryの権限について簡単なおさらいです。
BigQueryに限らず、Google CloudではIAMでユーザ(プリンシパル)の権限を設定します。権限は「組織・フォルダ・プロジェクト・リソース」単位で設定可能です。
事前にGoogleが提供する基本ロールや事前定義ロールを設定しても良いですし、自分で好きなパーミッションを付けたカスタムロールを作って権限付与しても良いです(詳細はGoogle Cloudの「ロールと権限」や「BigQuery の IAM ロールと権限」などを参照ください)。
権限管理は企業の状況によりケースバイケースですが、通常は事前定義ロールを付与することが多いかと思います。例えば、クエリジョブ実行だけ行うユーザであれば「BigQuery User (roles/bigquery.user)」ロールを、データセットやテーブル作成まで行うユーザであれば「BigQuery Admin (roles/bigquery.admin)」を与えてしまおう、など。この方法は手間が少ないですが、不必要な権限を与えてしまうリスクもあります。
ロールは複数のパーミッションで構成されており、どんなパーミッションを付与するかで、BigQueryで何が行えるかが決まります。
BigQueryにおいて、重要なパーミッションは以下の2つでしょう。
- bigquery.jobs.create:クエリジョブ実行
- bigquery.tables.getData:テーブルデータ取得
このパーミッションが付与されていないと、SQLクエリのジョブ実行がそもそもできないですし、テーブルデータも閲覧できません。
あと、データセットやテーブルの一覧を見るのに必要なパーミッションも重要です。
- bigquery.datasets.get:データセットのメタ情報取得
- bigquery.datasets.list:データセットの一覧取得
- bigquery.tables.get:テーブルのメタ情報取得
- bigquery.tables.list:テーブルの一覧取得
listのパーミッションがないと、Web上でBigQueryを開いても左側のメニューに何も表示されません。
BigQueryだけでも他にも細かいパーミッションが多数ありますが、詳細は割愛させてもらいます(ご興味あれば調べてみてください)。
ジョブ実行とデータ閲覧は分けられる
事前定義ロールにしろ、カスタムロールにしろ、通常であれば上記で説明した基本的なパーミッションは「同一プロジェクト」で付与すると思います。私もこの対応をするまでは、それが当たり前だと思っていました。
しかし、ロール(パーミッション)はプロジェクト単位で付与可能なので、当然プロジェクトAにパーミッションA、プロジェクトBにパーミッションBを付与することができます。
例えば以下のような構成です。
ユーザ1は、クエリジョブの実行を「run-job01」プロジェクトで行います。厳密に言えば、「run-job01」プロジェクトのBigQuery APIを使ってクエリジョブを実行します。
ただし、データの中身は「run-job01」プロジェクトにありません。よって、「run-job01」プロジェクトのBigQuery画面を開いてもデータセットやテーブルは何も表示されません。しかし、「data-view01」プロジェクトにはデータ閲覧権限が付与されており、テーブルデータもこのプロジェクトにあります。
そして、以下のSQLクエリジョブを実行すれば、「data-view01」プロジェクトのテーブルにアクセスすることが出来ます。
SELECT * FROM `data-view01.dataset01.table01`
なお、クエリジョブ実行は「run-job01」プロジェクトで行っているので、クエリスキャン量課金は「run-job01」プロジェクトに対して発生します。
この構成の利点は、以下2点です。
- クエリスキャンコストの管理が行いやすい
- クエリ上限設定の影響が他プロジェクトに及ばない
例のように部署ごとにプロジェクトを分ければ、各部署のクエリスキャンコストが一目で分かります。また、 クエリ上限設定は「プロジェクト単位」で設定するので、部署1に適用したとしても、部署2のユーザ2に影響が及びません。
プロジェクトを増やしすぎると管理が煩雑になりますが、部署2のチームA/チームBで分ける、などの細かい調整も可能です。
まとめ
今回はプロジェクト単位でロール(パーミッション)権限を分け、クエリ上限設定する方法を紹介させていただきました。
クエリ上限設定を行う/行わないを問わず、プロジェクトで権限を分ける方法は別の用途でも使えるように思います。BigQueryのコスト管理をしっかり行いたいという方であれば、実施する価値はあると思います。
同じような課題に直面されている方の一助になれば幸いです。
アソビューでは「生きるに、遊びを。」をミッションに、一緒に働くメンバーを募集しています。 ご興味がありましたらお気軽にご応募いただければと思います。