【書き起こし】BigQueryのコンピューティングリソース管理の取り組み – Go Kojima【Merpay & Mercoin Tech Fest 2023】

Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。
この記事は、「BigQueryのコンピューティングリソース管理の取り組み」の書き起こしです。

@gouki:「BigQueryのコンピューティングリソース管理の取り組み」にと題して発表します。

株式会社メルペイ ソフトエンジニアのGo Kojimaです。よろしくお願いします。私は2年前にメルペイにジョインし、当初は機械学習システムの基盤開発に携わりました。その後、現在も所属しているデータマネジメントチームに異動し、主に今回発表するBigQueryコンピューティングリソースの最適化を担当しております。

メルカリ・メルペイではデータ管理データ分析の基盤となるデータウェアハウスとして、Google社が提供するBigQueryを利用しております。

本発表ではBigQueryを利用するにあたって必要となるコンピューティングリソース管理の取り組みについてお話しします。内容としてはこちらの通り、初めにBigQueryとその課金モデルについて触れ、管理に当たっての課題をお話した上で、その解決に向けた取り組み内容をご紹介し、最後に今後予定している取り組みについてもご紹介いたします。

BigQueryはGoogleが提供するデータウェアハウスサービスです。サーバーレスアーキテクチャを採用しており、利用者としてもサーバーインスタンスのサイズや台数等を管理する必要のないサービスです。

対象のデータが大量にあったとしても、ほとんどの場合、数秒もしくは数分程度の実行時間で結果を返してくれます。ただし、クエリやデータによっては数時間以上かかるようなケースもあって、この後お話しする課題にも繋がってくるというような問題になります。

参照記事:https://cloud.google.com/bigquery/docs/introduction?hl=ja

こちらの表がBigQueryの課金モデルをざっくりと表現したもので、BigQueryは大きくクエリ処理とデータ保存に使われるストレージに対して課金がなされます。ストレージについては保存領域ごとのデータ量で課金される方式となっていますが、本日はこちらの処理側の方を中心にお話ししますので、ストレージ側の詳細は割愛します。

処理側は、オンデマンド型と定額型の二つのモデルにわかれています。オンデマンド型の場合、処理データ量に基づいて課金されるモデルになっています。月単位で1TBまでは無料で使えます。

ただし、オンデマンド型の場合は、一度に利用できるSLOTは2000までという制限があります。SLOTという概念についてはこの後すぐに説明しますが、クエリ処理に使われる仮想CPUの単位をお考えください。この制限があるので、より多くの計算リソースが必要な場合は、定額型を利用することになります。

定額型の場合、特定の期間の間、仮想CPUを利用する権利を予約購入して利用するモデルになっています。

通常月単位や年単位で購入しますが、これらを超えて必要なったときのみ、秒単位で利用仮想CPUを増加させて利用するFlex Slotsという方法もあります。Flex Slotsは通常BigQueryを実行する前後で、Flex Slotsの追加とキャンセルの処理を事前にプログラムとして自動実行するような使い方になります。必要な間だけFlex Slotsによる仮想CPUを追加して使っていくという形になります。

すでにSLOTとはBigQueryがクエリを処理するときの仮想CPUのことであるとご説明しましたが、特に定額型の課金モデルで利用する場合に、運用上非常に重要な要素となります。

一定の期間、一定数のSLOTの利用料金を支払う方式となっていますので、全く使わない場合でも、その分の料金を支払う必要があります。実際にクエリを実行する際にどれほどのSLOTを利用するのかは、利用者側で指定することができず、BigQueryが実行を進めながら判断して余剰SLOTがあれば利用して実行する仕組みになっています。

余剰SLOTが不足しているような場合は、その時点で使える分だけのSLOTを使って実行が継続され、SLOTが十分にある場合と比較して、実行時間が遅くなる形です。

このような仕組みになっているので消費SLOTを利用者側でコントロールすることは完全にはできません。よって、非常に難しいのですが、無駄にならず、かつ、許容できる実行時間でクエリ処理が完了できる程度のSLOT数になるように予約しておく必要があります。

不足した場合に備える手段としてFLEX SLOTや自動スケールの機能もあるのですが、その場合のSLOTの単価は通常のものに比べて高くなっていますので、それも踏まえてSLOT予約量を調整する必要があります。

またFLEX SLOTの場合は、先ほども簡単に触れました通り、通常はプログラムの中で利用する用なので、その中で無駄遣いが発生しないように慎重に準備しておく必要があります。

予約購入したSLOTはそのまま利用できるようにはなってません。SLOTには、Commitment、Reservation、Assignの概念があり、予約購入した状態ですと、Commitmentとして購入したSLOTが存在するしているという状態になります。

SLOTはGoogle CloudのOrganization単位で購入利用できるようになっているのですが、一つ以上のグループにSLOTを振り分けて利用する形式になっております。この振り分けの単位がReservationです。

一つのグループにはOrganizationのプロジェクトを一つ以上割り当てることができ、グループ内の数のプロジェクトで、グループに割り当てられたSLOTを利用することになります。このReservationに対するプロジェクト割り当てのことを、Assignと呼んでいます。

こちらはGoogleのマニュアルにあるSLOTの利用の例の図になっており、Commitment Reservation Assignの関係を示しています。この例では、まず、トータルのCommitmentとしてSLOTとして1000SLOT分保持してる状態で、Reservationのグループとしてds、elt、biの三つを作成して、それぞれSLOTを割り当てています。この例では保持しているSLOT全てを割り当て切った状態になっています。

例えばdsプロジェクトで、実行プロジェクトとしてBigQueryで、クエリを実行します。とdsグループに割り当てられた500SLOTの中からSLOTが割り当てられて実行されます。

なお、この図の中に両方向に矢印が書いてあるマークが意味するところとして、JOB実行の際にReservationに割り当てられているSLOTでは不足しているというような場合に、他のReservationで利用していないSLOTがあれば、それを利用することができることを表現しています。

このとき利用される余剰SLOTのことをアイドルSLOTと呼ぶのですが、このアイドルSLOTの利用を設定上停止することもできます。

ただし設定できるのは、他のReservationのアイドルSLOTを利用しないという設定で、反対方向にある他のReservationにアイドルSLOTを使わせないという設定ができません。

Reservationが二、三個程度の数しかないようなケースであれば、アイドルSLOTを優先的に利用するReservation以外のReservationで、アイドルSLOTを使わないという設定をすればいいわけですが、Reservation数がそれ以上に多い場合は、アイドルSLOTを融通し合うように設定しておいた方が、CommitmentのSLOTを使い切りやすくなります。

ここから我々のBigQuery SLOTの管理について、課題とその解決策をご紹介いたします。

まず我々のBigQuery環境ですが、定額のSLOT Commitmentを予約購入するモデルで利用しております。規模としては、データセット数にすると1500超、JOB数にすると1日あたり30万件超、ユーザー数であれば1日あたり700人超程度です。

BigQueryはSQLクエリさえかければ、大量データに対しても、数分程度の実行時間で結果が返ってくる非常に便利なデータウェアハウスです。利用者も非常に多くてQueryも多数使われており、利用者に対して、特に使い方の制限もしていないので、ほぼコミットしているSLOTの上限まで利用されています。
それにより実行時間が遅くなってしまったり、タイムアウトしてしまうというような問題も発生しております。

この問題に関して、SLOTの追加のCommitmentを購入することで、この問題に対処することもできるのですが、無限にSLOTを購入し続けることもできないのでそれ以外の対策が必要でした。

対策として、三つの柱を立てました。

最終的にSLOT消費削減のために施策を進めていたいきたいのですが、その前の準備段階として状況把握と管理効率化を進めました。SLOTの管理者だけでなく利用者の方々自らSLOTの利用状況や自分の状況を把握し、今どうなっているのか、SLOT量が増えているのか・減っているのかを認識できるように準備を進めました。

目的や優先度が異なるJOBが一つのReservationに混在していると、優先度の高いJOBのためのSLOTを優先度が低い所が食いつぶしてしまって、優先度が高い所のために十分なSLOTと配分できないという状況があります。

これを解消するために、目的や優先度を見定めてReservationを整理する作業も実施しました。順にこの三つについてご紹介いたします。

一つ目のSLOTの状況把握ですが、まずその状況を定義することから始めました。SLOTが枯渇すると、同じクエリでもそうでない場合と比べて実行時間が延びてしまう、いわゆる重い状態になるので、統一的に表現できるように試行錯誤し、データ処理量あたりの実行時間、一定SLOTを消費するのにかかる時間を、SLOT状況を表すメトリクスとして採用しました。

また、タイムアウト発生を避けたいので、その有無もSLOT状況を表すメトリクスとして採用しました。メトリクスについて、過去に緊急的にSLOT Commitmentを追加した前後で、どのようにそれらのメトリクスが変化したのかを分析した上で、Reservationごとにスレッショルドを定めて、そのスレッショルドに収まるメトリクスになることを各Reservationのキャパシティの要件として定めることとしました。

なお、相当の初期状況についてBigQueryの機能としてモニタリング用のWeb UIも提供されているのですが、我々が定義したキャパシティ要件メトリクスのような、より詳細な情報を得たい場合は、Web UIでは不可能なので、そういった場合に備えてBigQueryの機能として、特別なViewが提供されております。ここで紹介したようなメトリクスもそのViewを利用してモニタリングしています。

そのViewは、具体的には、JOB単位でJOBの詳細に関する情報が得られるJOBS_BY_ORGANIZATION view、各JOBの1秒ごとのタイムスライス単位で情報が得られるJOBS_TIMELINE_BY_ORGANIZATION viewが提供されています。これらを活用することで、Web UIでは得られないJOBごとの詳細な情報を得ることもできます。

こちらは、それらのViewの利用例のクエリになります。画面左側の部分でJOBS_BY_ORGANIZATIONからJOB終了時間を秒単位にならしたエラージョブズを取得して、画面右上側の部分でJOBS_TIMELINE_BY_ORGANIZATIONから行間隔でJOB数および平均SLOT消費を取得し、時刻とReservationグループ単位で、その二つをジョインしています。

こちらのクエリを実行しますと、このような結果が得られます。JOB単位の情報とタイムスライスごとの情報を組み合わせることで秒単位でJOBとSLOTの推移を確認できます。

今ご紹介したViewを活用してSLOT管理者および利用者向けにこのようなダッシュボードを作成し、社内公開して随時状況を把握できるようにしております。

また定期的にキャパシティ要件の状態をチェックして、違反の状態を検知したらすぐにSlackで通知する仕組みも用意して、タイムリーに状態を把握して、必要に応じて対策を打てる形にしております。状況把握については以上になります。

次に管理効率化のためのReservation整理について紹介します。課題として、一つのReservationに大きく2種類にわかれるJOBが同居してしまっているという状況がありました一つはAd-hocな分析用、もう一つはシステム開発用途です。

Ad-hocなものは使われ方としては比較的処理時間は短めで、素早く結果を得て活用するというタイプ。システム開発用途とはシステムが必要とするデータを整備するパイプラインを開発するための用途で結果を直接業務に活用するというよりかは本番用の動作検証という側面が大きいものになります。

このような使い方の違いから、Ad-hoc側はSLOT消費が比較的少ないものが大量に頻度で実行されるという傾向があって、システム開発用途ではバッチ処理系のSLOT消費の大きい少量のJOBが実行されるという傾向がありました。

そのため、要件としてもAd-hocでは長時間の実行が控えてSLOT消費を抑えるようにして、その他の通常のJOBに影響が出ないようにししばらくデータが得られるようにしたいという意見があり、システム開発用途では逆に実行が長時間になってしまったとしても安定的にデータ処理部を運用したいという要件があって、共存させたままだと非常に管理しづらいという問題がありました。

対策として元のReservationに所属しているプロジェクトごとにJOBの傾向を見定めた上で、新たにもう一つ別のReservationを作成して、JOB傾向に合わせてプロジェクトを振り分け直すことをしました。

これによってSLOTの配分がしやすくなったことに加えて、Ad-hocについてはReservation内の一定のSLOT消費以上、実行が続いている長時間JOBを強制停止するという仕組みを導入することも可能となりました。

一緒のままだとシステム開発用途のバッチ処理などを停止することになってしまっていましたけれども、Reservationを分離することによってそれも可能となって、優先度の高いJOBが長時間JOBにSLOT消費を奪われずに効率的に実行できるように改善することができました。

Reservationは元々、BigQueryのマニュアル上にも目的や優先度が聞かれたものを集めて構成するのが良いとされており、それによってSLOT管理をより効率的に行えるようになるメリットがあることについてご紹介しました。

最後に、SLOT削減に向けた取り組みについてご紹介いたします。不要なSLOT消費を削減するためには管理者だけではできることが限られており、実際に利用者の方々にご協力いただく必要があります。

そこで、先ほどご紹介した、JOBS_BY_ORGANIZATION、やJOBS_TIMELINE_BY_ORGANIZATIONを活用してSLOT消費が大きいテーブル作成JOBで、そのテーブルへのアクセスは全くないというものを探し出して、JOBの作成者に対してメンション付きでSlackで通知しています。

これらのViewやその他関連するテーブルに対して、クエリ実行し結果をもとに、JOBに対する操作を行うとか、あるいは結果データを使って通知を行うという処理自体は、いろいろな使い道が考えられるため、汎用的に利用できるように、SQLと通知内容をテンプレートで定義すれば、通知処理が行えるフレームワークを独自に開発し、これをBigQueryのJOB間に関連する通知の仕組みとして整備しました。

こちらは現段階では定量的な効果検証までできていないのですが、すでにSLOT消費の大きな情報を作成した方々には、見直しをしていただいていたり、アクセスのないJOBについては適時停止していただいたりしています。

これ以外のその他の取り組みについて、こちらにリストしております。

テーブルを特定のカラムの値をもとに分化するPartition filter requirement機能がBigQueryにはあるのですが、こちらはWHERE句で特定の値に絞り込んで実行することで、実行時間とSLOT消費を抑えられます。その絞り込みを行っていない場合は、クエリの実行自体を許可しないように強制する機能があり、この機能をオンにしています。もちろん実際に適用する際には、既存の定期JOBなどにも影響がありますので、その対策は必要です。

次はBI Engineです。こちらはBigQueryの機能として提供されているEメモリのキャッシュ機能として、実行プロジェクトごとにキャッシュサイズを設定して、キャッシュできます。

データセットを保持しているプロジェクトに対する設定をするのではなくて、実行プロジェクトの設定になります。キャッシュを利用したい対象のテーブル郡に対するクエリを実行するプロジェクトに対してキャッシュを設定する必要があります。

キャッシュ定義としてはメモリサイズの他にキャッシュを優先するテーブルを列挙するというようなことができるようになってます。

続いて、中間テーブルの作成活用となります。複数種類のJOBの間で共通的に実行している部分テーブルを中間テーブルとして定期的に作成しておくことで、こちらの自分の実行を効率化することができます。

メルカリ、メルペイではこうした中間テーブル作成するためのOSSのdbtを使った中間テーブルを作成を運用しております。

次はダッシュボードになります。複数のダッシュボードのソリューションを利用していますが、利用者はこれらを活用することで個別に分析用にSQLクエリを作成することなく、分析作業を行うことができます。SQLを直接利用する場合に比べて効率的なクエリになりやすく即座にビジュアライズすることもでき、SLOT消費の削減にもつながります。

最後に、今後の課題を述べます。BigQueryは最初にご紹介した料金体系から新たな料金体系に変更が予定されており、これまでよりもSLOTの単価が上がります。一方でAuto scaling SLOTと呼ばれる新たな機能で、SLOTが不足した場合のみ利用されるように事前に定義しておくことが可能になってます。

Auto scaling SLOTは単価が通常のSLOTより高めなものを使った分だけ課金されるというモデルになっていて、通常のCommitmentとAuto scaling SLOTが最適なるように設定していくことが重要になります。どのReservationにどれだけのAuto scaling SLOTを設定するのかが重要です。

また、BI Engineについてですが、こちらも設定したキャッシュメモリの量の分だけ課金されます。ただ、クエリ実行時にキャッシュヒットした場合はSLOT消費をしないので、SLOT割当とBI Engine用のメモリ量を最適に設定することが重要となります。こちらも利用しながら最適な設定を見定める予定です。

以上、メルカリ、メルペイにおけるBigQueryのSLOT管理について、課題と対策、今後の取り組みについてご紹介しました。ご清聴ありがとうございました。

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加