KAKEHASHI Tech Blog

カケハシのEngineer Teamによるブログです。

Databricks サーバレスコンピュート導入時の注意点、Tipsの紹介

私たちのデータ基盤はDatabricks on AWSで構築されており、従来、Databricksのコンピュートクラスタは自社のAWSアカウント内のEC2インスタンス上で稼働していました。昨年、DatabricksのサーバレスコンピュートがGA(一般提供)となり、その迅速な起動時間やインフラ管理の簡素化という魅力から、今年の春頃から全社的な利用を開始しました。

しかし、導入を進める中で想定外のコスト増加という課題に直面しました。本記事では、このコスト問題をどのように分析し、解決したのか、また、検証の過程で得られたその他の導入上の注意点やTipsをデータプラットフォームエンジニアの目線でご紹介します。

サーバレスのアーキテクチャを理解する

まず前提として、当たり前ですがサーバレスと従来のクラシックコンピュートのアーキテクチャの違いを十分に理解した上で利用する必要があります。

以下の図のように、クラシックコンピュートが自社のAWSアカウント(VPC)内のEC2インスタンス上で動作するのに対し、サーバレスはDatabricksが管理するAWSアカウント内で動作します。

そのため、サーバレスコンピュートからのアウトバウンドの通信に制限をかけたい場合には別途Databricksアカウントレベルでネットワークポリシーを設定する必要がありますので注意が必要です。

自前のクラウド環境上のクラシックコンピュートによる通信に制御をかけている場合、サーバレスに移行する際はこれらのネットワーク構成の違いに起因するセキュリティホールを作らないように気をつける必要があります。

(引用:high-level-architecture

サーバレスの利点を理解する

利用に際して、クラシックコンピュートと比較した場合のサーバレスコンピュートの利点を理解することも重要です。

詳細は公式ドキュメントで説明されていますが、弊社でも以下の利点が大きいと認識しています。

  • コンピュートの起動時間の短縮
  • ワークロード毎のコンピュートの運用工数の削減
  • 自前のクラウド環境のインスタンスの運用工数の削減

一方で、サーバレスを会社で全社的に利用するとなると、気をつけるべき注意点も多いので、後述していきます。

サーバレスのDBUの仕組みについて理解する

DBU(Databricksの消費リソースの単位)ですが、前提としてサーバレスの場合はクラシックと比較して相対的にDBU自体は高めの設定になっています。

これもサーバレスとクラシックのアーキテクチャの違いが前提となっています。

サーバレスではDatabricks側のDBU消費に基づく請求のみであるのに対して、クラシックでは自前のクラウド環境のリソースの料金が別途発生します。

サーバレスとクラシックを併用する場合、クラシックコンピュートのリソースに関しても自前のクラウド環境上で追跡する必要があり、Databricksと自前のクラウド環境の金額を合算して計算しようとするとロジックが非常に複雑化します。

Databricks側からクラウドのリソースにタグを付与できるので、組織のコスト配賦等のルールに合わせてこれらを事前に設計しておくことをおすすめします。

また、サーバレスで行う処理内容に応じてDBUに乗数が掛けられる仕様ですので、新規のユースケースやクラシックからの移行時にはこれらの仕様を理解した上でコストの見積もりを行うと良いと思います。

サーバレス利用時の予期せぬDBU増に注意する

クラシックでは事前にインスタンスタイプやオートスケールの設定等を細かく指定できたのに対して、サーバレスではリソースのスケーリングの設定や実際に使用されるリソースの詳細は指定できず、後から知ることもできません。

そのため、実際にサーバレスで処理を行うと実は予想以上にDBUが消費されていたことが判明するケースが往々にしてあり得ます。

公式のドキュメントでも言及されていますが、実際のワークロードをサーバレスに切り替えてDBUの消費量を計測することをお勧めします。

サーバレス移行時の予期せぬDBU増の事例紹介

実際に弊社でもクラシックからサーバレスに移行した際に、事前の想定以上にDBU消費が発生した事例がありましたので紹介します。

Lakeflow Declarative Pipelines(旧DLT)で分析用テーブルを作成する処理をサーバレスに移行したのですが、クラシックと比較するとトータルで10倍近くのDBUが消費されました。 ※先に結論を述べると、根本原因はサーバレス機能そのものではなく、弊社のSparkのコードに問題よる部分が大きいので、その前提で以降を読んでいただければと思います。

問題のワークロードの実行結果のクエリプロファイルを深掘りすると、元々Spillが大量に発生していること、サーバレスではSpill量が減少していることが判明しました。

クラシックコンピュートのSpill量: 528GB

サーバレスコンピュートのSpill量: 52GB

SpillはExecutorメモリから処理データ量が溢れた際にディスクへの退避を行う挙動のため、同じデータ量に対して、サーバレスではより多くのコンピュートリソースが利用されたと考えられます。

元々Spillが大量発生する問題のあるコードですので、不必要にリソースがスケールしてDBU消費量がスパイクしたと推測できます。

参考までに、このケースのSpillの原因及びチューニングの流れについても紹介します。

結論としては、調査の結果Spill発生箇所は特定のテーブルに対してMERGE INTO構文でデータを書き込む部分で非効率的なデータのJOINが発生しており、メモリ上で大量のデータを処理していたことが判明しました。

該当箇所のロジックを修正することでSpill自体が解消し、DBUも許容範囲に抑えることができました。

事前に懸念はしていましたが、クラシックと比較してサーバレスはSparkアプリケーションのレイヤーで非効率的な処理をしてしまうと、予期せぬDBU消費スパイクが発生するリスクが高いと感じます。

サーバレスを活用する際は、アプリケーションのレイヤーのチューニングの重要性、アカウント全体でのDBU消費量は注意深く監視することが重要性が高まると思います。

余談ですが、チューニングを行う際は事前にチームのメンバーがDelta Lakeのソースコードを読んでMERGE INTOの内部動作を調査してくれていたので、その知見をベースに調査することで非効率的なデータのJOIN箇所をすぐに特定することができました。

Databricksの主要機能は内部まで深くダイブし、組織の共有知としていくことも重要です。

アカウント全体のDBU消費を日々監視する

前項のDBU増の事例からの学びでもありましたが、DBU消費量の監視は強化するに越したことはありません。

まずアカウント全体の消費DBUを可視化したい場合はDatabricks公式が公開しているUsageダッシュボードを取り込むのがオススメです。

一方で、予期せぬ急激なスパイクは早めに自動検知して能動的に対応したいところです。

弊社の場合、SystemテーブルのUsageを日次で監視しています。

DBUの消費量に対して閾値をWarningとCriticalの2段階のレベルを設定し、超過時はスパイクの内容に応じて検知体制を敷いています。

予算を使い切ってしまう前に対策を打てるように適宜アラート等を設定しておくと安心です。

DBU消費の監視はサーバレスに限った話ではないですが、サーバレスの利用を開始して以降この監視の重要性が非常に高まった感触があります。

さらに細かい粒度でDBU消費量を可視化する

利用者目線で見ると自身の利用がどの程度DBUを消費したのかが心配になるものです。

弊社ではUsageログから各利用者や開発チームのマシンアカウント等が日々どの程度DBU消費しているのかを確認できるダッシュボードを提供し透明性を上げることで、あまり躊躇せずDatabricksを利用できる環境を作れるように努めています。

また、WorkflowのJob単位、Declarative Pipeline単位のUsageもDatabricks公式が公開しているダッシュボードを利用して可視化しています。

これらを用意しておくことで、予期せぬスパイクの調査や日々のアカウント全体のコスト削減、パフォーマンスチューニングを効率よく行えるようになります。

DBU消費を抑えられる機能を駆使する

これもサーバレスに限った話ではありませんが、ワークロードのパフォーマンスチューニングを行うとDBU消費を抑えられるので、使える機能は使い倒しましょう。

弊社の既存のワークロードをクラシックからサーバレスに切り替えた際に、コスト削減効果として大きかった機能を少し紹介します。

Performance Mode

Workflow Jobをサーバレスで動かす場合にPerformance Modeを選択できます。

弊社で既存のワークロードを移管する際にPerformance optimizedのON/OFFでDBU消費量を比較する検証を行いました。結果としてはPerformance optimizedをOFFにすると約40%の削減効果がありました。

ユースケース毎の性能要件を踏まえた上でModeの切り替えを徹底するとコストの最適化につながります。

Deletion Vectors

Deletion Vectorsは現状では基本的にデフォルトで有効ですが、有効化以前に作成された既存のストリーミングテーブル、マテリアライズドビューで有効化するには一度テーブルを作り直す必要があります。

弊社のケースだとサーバレスでストリーミングテーブルを更新するワークロードが多いのですが、Deletion VectorsをONにするとDBU消費量を約30%削減できました。

その他

その他、弊社ではまだ十分に活用できていませんが、Liquid clusteringPredictive optimization等は今後性能改善の面で有効な打ち手だと見ています。

Databricksのサイトでも性能改善のベストプラクティスが公開されているので、これらが参考になるかと思います。

サーバレスとクラシックを適切に使い分ける

現時点はサーバレスは制限が多いので出来ることも限られてきます。

弊社の場合、こうした制限の都合で、ノートブックのアドホックな分析業務以外はすんなりとサーバレスに置き換えることはできないため、しばらくはクラシックコンピュートと使い分けていく関係性になるかと思います。

より解像度高く特性を理解し、それぞれ適合する/しないユースケースについて整理することが重要です。

例えば、サーバレスは常に最新のDatabricks Runtimeで実行される仕様です。サーバレスを選択する際はこの仕様を前提に考える必要があります。

Runtimeのバージョンが上がると当然Sparkのバージョンも上がります。弊社の主要Workflow Jobでは外部ライブラリに依存する箇所が多く、これらのバージョンの互換性の問題で現時点ではサーバレスに移行できないケースが多いです。

また、Runtime Ver17.0からはANSI SQLがデフォルトになりました。これまでHive準拠のSpark SQLで記述されていたワークロードは予期せぬ挙動になることも懸念されます。

マテリアライズドビューを作成する際に使用するLakeflow Declarative Pipelineは、元々実装上の一定制約があるかつコンセプト自体がバージョンレスでRuntimeを意識しないので、元々クラシックコンピュートで実装していた場合でもサーバレスに容易に移行できる可能性が高いかつ、マテリアライズドビューの増分更新はサーバレスのみで実現できるので、サーバレスに移行するメリットが大きいです。

最後に

本記事では弊社のデータプラットフォームエンジニア目線でのサーバレスの導入から運用を通じて得られた知見、注意点、Tips等をご紹介しました。

本記事が、これからサーバレス導入を検討されている方々の一助となれば幸いです。

カケハシのデータ基盤チームでは、データ基盤の利用体験の向上を目指して今後もサーバレス等のDatabricks最新機能の社内導入を積極的に推進していきたいと思います。

データ基盤開発チームの職務内容・募集職種に興味を持っていただいた方は是非こちらをご参照ください。

文責:大木康平