要点まとめ
Databricksのコスト最適化における簡単な施策(自動終了、タイムアウト、オートスケーリング、適切なサイズのコンピュート)は、最も費用対効果の高い取り組みです。多くの場合、請求額を20〜40%削減でき、適用には数分しかかかりません。その先にもさらに20〜40%の削減余地が残されていることが多いのですが、実現には数日から数週間の工数がかかり、計算が見合うワークロードでしか元が取れません。本ガイドはその「第2段階」がテーマです。工数をかける価値のあるジョブを見つけ、どのコンピュートで実行するかを決める前に、ジョブの処理量そのものを減らす方法を解説します。
はじめに
Databricksのコストに関するアドバイスの多くは、設定の話で終わります。自動終了を設定する、タイムアウトを追加する、オートスケーリングを有効にする、クラスターの過剰プロビジョニングをやめる。どれも正しいアドバイスであり、まず最初にすべて実施すべきです。これこそがまぎれもなく最も費用対効果の高い施策だからです。出発点にもよりますが、こうした即効性のある施策で請求額の20〜40%を取り戻せることが多く、そのほとんどは数分で完了します。省略すべきではありませんし、本記事もその効果が小さいと主張するものではありません。
ポイントは、そこには上限があるということです。アイドル状態のクラスターがなくなり、タイムアウトが設定され、コンピュートのサイズが適正化されれば、一度きりの大きな削減効果を得て、削減カーブは平坦になります。しかしワークロード自体は、以前とまったく同じ量の処理を行い続けているのです。次の20〜40%を得るには、ジョブが実際に行う処理そのものを変える必要があります。毎晩全履歴を再処理するパイプライン、返す結果の100倍のデータをスキャンするクエリ、1日に1回しか開かれない「リアルタイム」ダッシュボード。これらはクラスターのサイズを変えても安くなりません。処理を再設計して初めて安くなるのであり、それには数分ではなく数日から数週間かかります。しかも効果が出るのは一部のワークロードに限られます。だからこそ、最初の本当のステップは、どのワークロードが対象かを見極めることなのです。本ガイドはこの第2段階を扱います。
なぜ多くのDatabricksコスト削減は簡単な施策の後で停滞するのか
Databricksのコストに最初に取り組むとき、ほぼ必ず同じ数個のコントロールが対象になりますが、それには理由があります。最小の労力で最大のリターンが得られる施策であり、これを飛ばすと請求額は際限なく膨らんでいくからです。まだ実施していない場合は、そこから始めてください。当社の記事Databricksの料金体系を解説では、自動終了、タイムアウト、Job Computeとall-purposeの違いを詳しく説明しています。同記事を前提知識として、本記事をその次のステップとお読みください。
しかし、そこで止まってしまうと問題があります。これらのコントロールはどれも一度きりの是正措置です。自動終了によりアイドル状態のクラスターへの支払いは止まりますが、アイドル時間がゼロになれば、それ以上取り戻せるものはありません。パイプラインをDBUあたり0.55ドルのall-purposeクラスターから0.30ドルのJobs Classicに移行すれば、そのジョブの単価は約45%下がりますが、この切り替えができるのは一度だけです。これらは大きく即効性のある施策で、請求額の5分の1から5分の2に達することも珍しくありませんが、そこで終わりです。カーブは平坦になり、請求額は新しい低いベースラインに落ち着き、それ以上動かなくなります。
そのベースラインを決めるのはジョブの処理量であり、これこそ簡単な施策では決して触れられない変数です。10億行のテーブルを毎日フルで書き換えるパイプラインは、どれほど適切にサイズ設定された最安のJobsクラスターで動かしても高くつきます。次の削減余地はワークロードそのものの中にあります。処理するデータを減らす、実行頻度を下げる、結果を繰り返しではなく一度だけ計算する。これは設定を切り替えるより難しく、数分ではなく数日から数週間を要し、どこでも元が取れるわけではありません。安価なパイプラインや実行頻度の低いパイプラインでは、エンジニアリングの時間が削減額を上回ってしまいます。だからこそ次のステップは、最適化を始めることではなく、そもそもどのワークロードに最適化の価値があるのかを見極めることなのです。
最適化する価値のあるワークロードをどう見つけるか
何かを最適化する前に、実際に何が高コストなのかを把握しましょう。これは思った以上に重要です。エンジニアの直感と請求書が同じものを指すことはめったにないからです。煩わしいと感じているパイプラインは安価なことが多く、誰も気に留めていないパイプラインが大きなクラスターで1日3回実行され、ひっそりと請求額の大半を占めていたりします。
支出をランク付けする最速の方法は、課金システムテーブルを使うことです。system.billing.usage(消費されたすべてのDBU)とsystem.billing.list_prices(SKUごとの実効価格)を結合して数量を金額に変換し、さらにsystem.lakeflow.jobsを結合して人間が読めるジョブ名を付与すれば、実際にアクションにつながるランキングになります。
WITH price AS ( SELECT sku_name, pricing.effective_list.default AS price_effective FROM system.billing.list_prices WHERE price_end_time IS NULL),usage AS ( SELECT * FROM system.billing.usage WHERE usage.billing_origin_product = 'JOBS'コードを展開
これによりジョブ名付きで日次コスト順にランク付けでき、この段階で唯一重要な問い、すなわち「どの名前のジョブが請求額を押し上げているのか」に答えられます。ちなみに、タグ付けに価値を与えるのがこのsystem.lakeflow.jobsとの結合です。タグそのものが請求額を下げることはありませんが、時間とともに変わっていくジョブIDや名前の羅列に埋もれることなく、この出力をチーム、環境、プロジェクト単位でグループ化できるようにしてくれるのがタグなのです。
行動する前にランク付けすべき理由は、最適化自体にもコストがかかり、節約額より多くのエンジニアリング時間を費やしてしまいがちだからです。請求額の1%に過ぎないパイプラインの書き直しは、達成感はあっても請求書には決して表れず、費やした時間は多くの場合、何年分もの削減額を上回ります。コスト順に並べ、上位の少数のワークロードに注目し、高コストのものが片付くまでロングテールは無視しましょう。すべてではなく、外れ値を最適化するのです。
自前でワークロード別に支出をランク付けするには、こうしたクエリを書いて保守し、ジョブ名の変更やパイプラインの進化に合わせてダッシュボードを最新に保つ必要があります。SELECTはこのアトリビューションを自動で行い、最も高コストなワークロード、アイドル状態のコンピュート、コンピュートタイプのミスマッチを、手作業のクエリ構築なしに可視化します。お使いの環境で何が見つかるかをご確認ください。
なぜクラスターのサイズ変更よりジョブの最適化が効くのか
このセクションだけで本記事を読む価値があります。ジョブが遅い、あるいは高コストなとき、直感的な解決策はより大きなクラスターです。設定1つで済み、たいてい効果があるからです。しかしそれは最も高くつく解決策でもあり、根本的な無駄はそのまま残ります。必要以上のデータをスキャンするジョブ、不要なシャッフルを行うジョブ、すでに処理済みの履歴を再処理するジョブは、クラスターのサイズが_どうであれ_余分なコンピュートを浪費します。スケールアップは、その代償をより速く支払うだけです。
具体例を挙げます。私のクライアントが運用していたIoTデータパイプラインを、同じ環境のまま実行時間で約85%、コストで約75%(年間およそ1万ドル)削減しました。コンピュートのサイズは元々ひどく間違っていたわけではなく、最適ではないものの極端でもありませんでした。サイズ変更では請求額は一桁パーセントしか動かなかったでしょう。削減はすべて、パイプラインの処理内容を変えることで実現しました。ブロンズ層とシルバー層をフル再処理ではなく増分ロードにする、高コストなファクトテーブルの結合を日次集計でデータが小さくなった後まで遅らせる、最も重い変換処理を書き直す、データを新しいテーブルに複製する代わりにビュー経由で提供する。それぞれが以下のレバーのいずれかに対応します。単独で全体を説明できるものはなく、コンピュートのサイズ設定はリストにすら入っていませんでした。
クエリプロファイルを読み、高コストな部分を再設計する
Databricksはすべての実行について詳細なクエリプロファイルを公開しており、プランの各ステージでどこに時間がかかったかを確認できます。クエリ履歴から、あるいはジョブやSQLクエリから直接プロファイルを開き、実行プラン全体をJSONとしてダウンロードできます。このJSONこそが、現代のデータエンジニアリングワークフローにおいて最もレバレッジが効き、最も知られていないテクニックの入力になります。LLMに渡すのです。
LLMはクエリプロファイルを読み、コストの所在を特定するのが非常に得意です。どのステージでスピルが発生したか、どの結合が爆発したか、どこでデータ量に見合わない数のパーティションでシャッフルが実行されたか。実際のジョブでは、ボトルネックとして、エンティティごとに1日1行、約14年分の履歴にわたる完全な日付カレンダーを構築してから再び畳み込むSQL変換処理が指摘されました。必要な結果はそのごく一部なのに、数千万行の中間データを生成していたのです。LLMは診断で止まりませんでした。カレンダーをマテリアライズしない、イベントベースのインターバルスイープ方式によるPySparkでの初期の書き直し案を提案し、そこからは解決策づくりの実質的な協働者になりました。私が初版で処理されないエッジケースを指摘すると、修正を取り込み、そのケースをユニットテストとして残し、結果が全面的に正しくなるまでこのループを2〜3日繰り返しました。日次ジョブは約2時間から10分へ、実行時間とDBUコストの両方でおよそ15分の1になりました。
ポイントは分業のあり方であり、それは「AIが問題を見つけ、人間が本当の仕事をする」ではありません。モデルがボトルネックを発見し、アルゴリズムを提案し、コードの大半を書きました。私の仕事は舵取りです。見落とされたケースを捕まえ、解決策が本当に正しいかを判断し、テストで反復の質を担保すること。これはエラーメッセージを貼り付けるのとは本質的に異なる、はるかに高度な使い方です。Databricksワークスペースで編集しているならGenieがこれをうまくこなしますし、IDEで作業しているなら、すでに統合されているアシスタントで十分です。重要なのはツールではなく、より大きなクラスターに手を伸ばす代わりに、プロファイルを読んで高コストな部分を作り直すという習慣なのです。
テーブル全体の上書きではなく増分処理にする
フル上書きは最もシンプルなパイプラインパターンであり、小〜中規模のテーブルでは多くの場合それが正解です。増分処理の複雑さが常に見合うわけではありません。しかしデータ量が多い場合、特にトランザクションデータ、テレメトリー、時系列データでは、実行のたびにテーブル全体を再処理するコストは、テーブルが成長するたびに高くなり、正当化しづらくなっていきます。
増分処理の方法は、不変データなら新規レコードの追記、更新されるデータなら変更レコードのマージであり、このパターンをメダリオンアーキテクチャのできるだけ多くの層に貫くことです。データが小さなサイズまで集約されて初めて、フル上書きが再び妥当な選択肢になります。実用的なツールはSpark Structured Streamingです。ファイル取り込みにはAuto Loaderと組み合わせ、あるいはDeltaテーブルからネイティブに読み取れば、チェックポイントが自動管理され、各実行では前回以降に到着したデータのみが処理されます。多くのチームにとって最大の収穫は、継続的なリアルタイム処理ではなく、ストリーミングが容易にしてくれる信頼性の高い増分バッチパターン、つまり既存データを再スキャンせずに新しいデータだけを処理することです。
「リアルタイム」要件は受け入れる前に問い直す
「ニアリアルタイムのデータが必要」という要件は、データチームが鵜呑みにすると最も高くつくもののひとつであり、本当にそうであることはめったにありません。ステークホルダーが必要としているのは、新鮮なデータの継続的なストリームではほぼありません。実際に見るときに十分新しいビューがあればよいのであり、それはまったく別の、はるかに安価なものです。リアルタイム向けに構築する前に、そのダッシュボードが実際にどのくらいの頻度で開かれ、レポートが実際にどのくらいの頻度で読まれているかを確認してください。毎時、毎日、さらには毎週の更新で十分なケースは、当初の要望が示唆するよりはるかに多いのです。
コスト差はわずかではありません。例として、処理内容を一定に保ったまま実行頻度だけを変えてみましょう。常時実行なら58ユニットかかるところが、毎時実行なら同じ処理が約5ユニットに下がり、1日3回なら1ユニット近くになります。これは丸め誤差の違いではなく、常時実行から毎時実行でおよそ12分の1、そこからさらに大きく下がります。
実践的な進め方は、当初の頻度要件にかかわらず、すべてのパイプラインをStructured Streamingで構築することです。ストリーミングなら、スケジュールバッチと常時実行の切り替えが容易だからです。その上で、実際のビジネスニーズを満たす最低の頻度から始め、より高い鮮度が必要だという確かな根拠があるときだけ引き上げます。スケールアップの手段は必要になれば使えますし、早まってスケールアップしないことによる節約はすぐに手に入ります。
テーブルではなくビューを作る
すべてのテーブルが物理的にデータを保持する必要はありません。典型的なDatabricks環境にあるテーブルのかなりの割合は、複雑な変換処理のためではなく、データを別の形で公開するために存在しています。別のスキーマ、フィルター、列のサブセット、異なるアクセス権限のセット。そうしたケースでデータを物理的にコピーすることは、実質的なメリットなしにストレージコスト、コンピュートコスト、パイプラインの複雑さを増やすだけです。
そこで最適なのがビューです。クエリで定義された仮想レイヤーであり、何もコピーも保存もされません。単純な列選択やフィルターであれば、読み取り体験はテーブルと区別がつきません。物理テーブルは、結果をマテリアライズすることで意味のある再計算を節約できる、本当に高コストな変換処理の出力のために取っておきましょう。それ以外はビューにすることで、ストレージをスリムに、パイプラインをシンプルに保てます。これらのワークフローパターンをより深く知りたい方は、コスト最適化の無料ebookをご覧ください。あるワークロードにどのレバーが当てはまるかを判断するために私たちが使っている診断フローチャートとともに解説しています。
ジョブが効率化できたら、どうコンピュートを選ぶか
ここでの順序に注目してください。コンピュートの選択はワークロード最適化の_後_であり、先ではありません。この順序こそが本記事の主張のすべてです。非効率なジョブに合わせてコンピュートをサイズ設定しても、選んだスケールで無駄が固定されるだけです。ジョブが適切な量の処理をするようになれば、コンピュートの判断はシンプルになり、失敗したときの影響も小さくなります。
デフォルトは、ジョブ、ノートブック、SQLのすべてにわたってサーバーレスにすべきです。これは違和感があるかもしれません。サーバーレスはDBUあたりの単価が高いからです。Azure Premiumでは、Jobs ServerlessはDBUあたり0.45ドルでJobs Classicの0.30ドルより高く、インタラクティブなServerlessは0.95ドルでクラシックのall-purposeの0.55ドルより高くなります。しかしDBU単価は話の半分に過ぎず、比較をするときにチームが最も見落としがちなのがこの部分です。クラシックコンピュートでは、DBU料金が請求のすべてではありません。基盤となるVMの料金をクラウドプロバイダーに別途支払っており、その額を事前に見積もるのは本当に困難です。サーバーレスはインフラをDBU単価に含めているため、見えている価格が支払う価格になります。
このバンドルは、想像以上の頻度で素朴な比較をひっくり返します。あるクライアントの毎時ETLパイプラインが分かりやすい例です。DBUあたり0.30ドルのJob Classicでは1日約44 DBUを消費し、DBUで約13ドル、さらにクラウドVM料金で約10ドル、合計で1日約23ドルでした。同じワークロードのサーバーレス版は、消費DBUがより少なく(実際の処理によりきめ細かくスケールしたため約38)、DBUあたり0.45ドルで、別途のクラウド請求は一切なしで1日約18ドルでした。表面上の単価が高い選択肢のほうが、VM料金を含めれば安く、しかもそこに到達するためのチューニングはゼロでした。
どちらの請求書にも決して表れない第二のコストがあります。クラシッククラスターを適切にサイズ設定しチューニングするエンジニアリング時間です(インスタンスタイプ、メモリとコアの比率、オートスケーリングの挙動、そしてワークロードの進化に合わせたそれらすべての見直し)。ほとんどのワークロードでは、その時間のほうがどんなDBUの上乗せ分よりも高くつきます。小規模なパイプラインを10%削減するために1日チューニングすれば、元を取るのに1年かかることもあります。サーバーレスなら、運用上の問題もまるごと一掃できます。クラスターの起動待ちも、バージョン管理も、消し忘れるアイドルクラスターもありません。
率直に言えばこうです。個々のパイプライン単体で見れば、サーバーレスが唯一の最安の選択肢であることはめったにありません。しかしほとんどのパイプラインでは、チューニングの手間ゼロで80〜90%のところまで到達できます。ポートフォリオ全体で見れば、総所有コストで勝つのはこちらです。大半のパイプラインが、1分も費やすことなくそこそこ効率的になるからです。その上で、コストランキングを使って、予測可能に実行される高頻度・高コストのジョブを少数見つけ出します。クラシックコンピュートに移し、クラウドVMの計算も含めて手動でチューニングする価値があるのは、まさに_それら_です。外れ値を最適化し、それ以外はすべてサーバーレスをデフォルトにしましょう。
クラシックコンピュートを設定する際は、動作する最小のリソースから始め、根拠に基づいてスケールしてください。過剰プロビジョニングは多くのDatabricks環境のデフォルト状態です。設定が同僚からコピーされたり、古いプロジェクトから引き継がれたり、UIの提案値のまま放置されたりするからです。SQLウェアハウスは最小サイズを選び、クエリ時間が許容できなくなったときだけ上げる。クラスターは汎用ノードタイプで始め、ワーカー1台から2台または4台へオートスケールさせる。サイズが2倍のコンピュートはジョブを2倍速く実行してはくれませんが、確実に2倍のコストがかかります。
コストの逆戻りをどう防ぐか
個別の最適化は出発点であって、定常状態ではありません。チームは拡大し、ワークロードは増え、新しいエンジニアがそれぞれの流儀を持ち込み、何かが抑えていない限りコストは再び上昇していきます。その「何か」がガバナンス層であり、一度きりのクリーンアップを持続的なベースラインに変えるものです。
単体で最も確実な一手は、コンピュートのアドホックな作成をやめさせることです。エンジニアが各自でクラスターをプロビジョニングすると、重要な設定(自動終了、スケーリング上限、インスタンスタイプ、タグ)が一貫性なく、あるいはまったく設定されず、他で積み重ねた丁寧な最適化が水の泡になります。クラスターとウェアハウスをInfrastructure as Codeで定義し、CI/CDでデプロイし、エンジニアには自作ではなく事前承認済みのセットから選んでもらいましょう。カスタムコンピュートを本当に必要とするパワーユーザーには、クラスターポリシーが中間の落としどころです。ポリシーで自動終了を強制し、クラスターサイズに上限を設け、インスタンスタイプを制限しつつ、その範囲内で調整する余地は残せます。コスト効率の良い選択肢が、唯一の選択肢になるのです。この問題に専用ツールが必要だと私たちが考える理由については、なぜSELECTをDatabricks向けに作ったのかをご覧ください。
予防ですべてを捕捉できるわけではないので、アラートと組み合わせましょう。Databricksにはアカウントコンソールに支出しきい値を設定できるネイティブな予算機能があり、出発点としては十分です。しかし、より感度の高いシグナルは固定の上限ではなく統計的なものです。ワークロードごとの日次または週次コストの標準偏差を測定し、正常範囲からの逸脱でアラートを出すのです。固定しきい値は、支出がすでに一線を越えた後にしか作動しません。ドリフトを監視すれば、ジョブが異常な振る舞いを始めたその日に問題を捉えられます。請求サイクルの終わりに損害が確定してからではありません。この即日の可視性こそが、小さな是正と手痛い請求の分かれ目です。
Databricksのコスト最適化は一度きりのプロジェクトではありません。プラットフォームは進化し、チームはワークロードを増やし、苦労して下げたベースラインも、継続的な可視性がなければ再び上昇していきます。SELECTはデータプラットフォームチームにその可視性を1か所で提供します。ワークロード別に支出をランク付けし、ドリフトを発生時点で捕捉し、時間とともに積み上がる削減機会を明らかにします。デモを予約して、お使いの環境で何が見えるかをご確認ください。
よくある質問
Databricksのコストを削減する最速の方法は?
最小の労力で最大の金額を取り戻せるのは、2つの設定変更です。すべてのクラスターとSQLウェアハウスに自動終了を設定してアイドルリソースへの課金を止めること、そしてスケジュール実行のパイプラインをall-purposeコンピュートからJobs Computeに移すことです。Azure Premiumでは、これによりジョブの単価がDBUあたり0.55ドルから0.30ドルになり、そのワークロードの単価が約45%下がります。どちらも半日でできる変更です。正直な注意点を言えば、どちらも設計の悪いパイプラインには手が届きません。毎晩全履歴を再処理するジョブや、返す結果よりはるかに多くのデータをスキャンするジョブは、どれほど安く適切にサイズ設定されたクラスターに載せても高コストのままです。即効性のある施策はベースラインを下げますが、そこからさらに下げるには処理の再設計が必要です。
サーバーレスはクラシックコンピュートより安い?
DBU単価では安くなく、総額でも常に安いわけではないため、単純なイエス・ノーでは答えられません。サーバーレスは単価が高い(Azure PremiumではJobs ServerlessがDBUあたり0.45ドル、Jobs Classicが0.30ドル)一方、本来は自分で支払いチューニングするインフラが含まれています。ほとんどのワークロードでは、節約できるエンジニアリング時間が単価の差額を上回るため、サーバーレスは良いデフォルトです。注意すべき罠は、サーバーレスのスケーリングがあまりに滑らかなため、コスト増がクラシックコンピュートよりも見えにくいことです。2回の実行が同じ実時間で終わっても、消費DBU量は大きく異なることがあります。重い方の実行でサーバーレスが静かにスケールアップしているからです。所要時間は横ばいに見えるのに、請求は倍になる。実行時間だけでなく、DBU消費量を監視してください。
Unity CatalogはDatabricksの請求額を増やす?
Unity Catalog自体は個別に課金される製品ではありませんが、有効化するとコストの構造が変わるため、移行前に理解しておく価値があります。Unity Catalogのマネージドテーブルに対してOPTIMIZEとVACUUMを自動実行するPredictive OptimizationはDBUを消費します(一般的にはクエリの削減で元が取れますが、れっきとした請求項目です)。ガバナンス機能、マネージドテーブルのメンテナンス、いくつかのカタログ操作が実行されるサーバーレスコンピュートは、いずれもどこかに計上されます。Unity Catalogがコストに与える影響は別のガイドで扱っていますが、要点を言えば、ガバナンスには価値があるものの無料ではなく、有効化する前に請求のどこに表れるかを知っておくべきだということです。