こんにちは。estieのData Management Platformユニットでエンジニアをしている渡邊です。
Data Management Platformユニットでは社内データ基盤の管理者として、Snowflakeの利用に関わる方針の策定、推進に取り組んでいます。
今回はSnowflakeの仮想ウェアハウス(以降、ウェアハウス)の細分化を行い、SQLの実行を高速化しました。具体的なタスクとやったことについてご紹介します。
読んでいただいている方のSnowflakeの利用状況や運用の方針によって、考慮すべき点や作業の進め方は異なるかとは思いますが、今後同様の作業を実施される際の参考になれば幸いです。
ウェアハウスの分割を行った背景
まず、今回の細分化を実施する前の弊社のウェアハウスの運用は、下記の状態でした。
- 基本的に1つのウェアハウスを全社で共有して利用
- 高い安定性や速度が求められる一部の処理については、専用のウェアハウスを割り当てている
Snowflakeの導入当初は利用者や用途も限られており、共有のウェアハウスによる運用でも大きな問題はありませんでしたが、利用者の増加に伴って利便性の低下やコスト管理のやりづらさといった課題がでてきました。
- SQLの実行が集中するタイミングがあり、通常であれば数秒で完了するSQLの実行に10分以上待たされるなどSQL実行のパフォーマンスが低下し、利便性が低下する
- 誰(どのチーム)がどの程度利用しているかを容易に確認できないため、コスト管理が困難
パフォーマンスの課題についてはウェアハウスのサイズを上げるというアプローチもありますが、コスト管理の課題解決については細分化が有効だと判断し、ウェアハウスの細分化を選択しました。
estieのデータ基盤の設計について
ウェアハウス細分化の具体的なご説明をするにあたっての前提として、はじめにestieのデータ基盤の設計についてご紹介させて頂きます。
estieでは「Whole Product構想」のもと複数のプロダクトを提供しおり、プロダクトごとにチームが組成されています。
データ基盤としてはチームごとにSnowflakeのデータベースを作成し、データベース内のスキーマ設計やデータパイプラインの構築・運用など、基本的には各チームが自治できるように権限設計をしています。
少し前の記事ですが、こちらの記事でより詳しくご説明していますので、興味がありましたら参照して頂けると幸いです。
どう細分化するか?
ウェアハウスをどのように細分化するべきかを検討するにあたって、まず今回のゴールは下記の2点としました。
今回のゴール
- 他チームのSQL実行などによるパフォーマンス低下の影響を受けない状態とする
- チーム単位でのコスト利用状況が容易に確認できる状態とする
チーム内でもSQL実行などウェアハウスの利用タイミングが重なることでSQLのパフォーマンスが低下してしまうことは考えられますが、チーム内でウェアハウスを更に細分化するかどうかについては各チームで決められるように権限を移譲する(※)方針としました。
※ ウェアハウスのリソースについてはTerraformで管理しており、各チームでTerraformに定義を追記してもらい、GitHub経由でPull Requestをあげてもらうことで追加や権限の割り当てができる仕組みを提供
また、現状はユーザー単位でのコスト管理までは必要ないため、チーム単位でウェアハウス利用のコスト管理ができる状態を目指します。
細分化の方針
ゴールに設定した2つの条件を満たすにはチームを境界とするのが良さそうなので、今回はチーム単位でウェアハウスを作成する方針としました。
作業の進め方
細分化にあたっての大まかな作業の進め方は下記の流れとなります。(具体的な作業手順は後述します)
- チームごとのウェアハウスを作成する
- 作成したウェアハウスに対して、対応するチームのアカウントロールからの利用権限を割り当てる
- 共有のウェアハウスの割り当てを全てのアカウントロールから外す(最終的にウェアハウスは削除する)
共有のウェアハウスの割り当てを外す意図としては、このウェアハウスの割り当てが残っていると利用者が誤ってチーム用のウェアハウスではなく共有のウェアハウスを選択してしまい、コスト管理が適切に行えなくなってしまうことを考慮したためです。
弊社のアカウントロールの設計方針
チーム単位でウェアハウスを割り当てるにあたっての前提として、弊社ではチームに対してサービスユーザー用とメンバー用のアカウントロールを1セットとして割り当てています。
- サービスユーザー用ロール
- チームが管理するデータパイプラインなどから、データにアクセスする際に利用
- メンバー用ロール
- 人間がSnowsightなどから、データにアクセスする際に利用
ウェアハウスの切り替えについて、ロールの種類で考慮すべき観点や進め方が異なるため、サービスユーザー用ロール → メンバー用ロールの順序(※)で切り替えを実施しました。
※ 子ロールから先にウェアハウスの切り替えを行うとロールの継承関係から親ロールのウェアハウスにも影響を与えてしまうため、順序を意識して作業しました。
サービスユーザー用のロールのウェアハウス切り替え
サービスユーザーがコマンドラインからSnowflakeにアクセスする際にどのウェアハウスを利用するかについては、暗黙的に決まる場合と明示的に指定する場合の2パターンあります。
- Snowflake接続時にウェアハウスを明示的に指定しない場合、ユーザーに設定されているデフォルトウェアハウスが利用される(ただし、接続時に利用するロールにデフォルトウェアハウスが割り当てられている必要があります)
- Snowflake接続時にウェアハウスを明示的に指定した場合、指定したウェアハウスが利用される
前者であればSnowflake側でユーザーのデフォルトウェアハウスの設定を変更することで対応できますが、後者の場合はプログラムコード上でウェアハウスを指定している箇所の修正が必要になります。
上記を踏まえて、下記の手順でウェアハウスの変更を実施しました。
- チーム用のウェアハウスを作成する
- プログラムから明示的にウェアハウスを指定している箇所を、共有のウェアハウスからチーム用のウェアハウスに変更する(変更作業はコードオーナーのチームに依頼)
- チームごとのサービスユーザー用のロールに、チーム用のウェアハウスの利用権限を割り当てる(この段階では共有のウェアハウスの利用権限は付いたまま)
- サービスユーザー用のロールを利用してSnowflakeにアクセスしているサービスユーザーのデフォルトウェアハウスを、チーム用のウェアハウスに変更する
- 一定期間(※)が経過後、下記のSQLを実行してサービスユーザー用のロールの、共有ウェアハウスの利用状況を確認する
- サービスユーザー用のロールから共有のウェアハウスが呼び出されていないことを確認できれば、作業完了
※ 今回は月次処理までを考慮して、1ヶ月くらい経過を観察しました。
select * from snowflake.account_usage.query_history where start_time >= (yyyy-mm-dd) -- 期間を指定しないとレコード数が膨大になるため、切り替えを行った日付以降に絞り込む and warehouse_name = (共有のウェアハウスの名前) and role_name in ( -- サービスユーザー用のロールのみを対象とするための条件を記載 )
チームメンバー用のロールのウェアハウスの切り替え
弊社では原則、チームメンバー用のロールは利用者がSnowsightからSQLやStreamlit in Snowflakeを実行する際に利用されます。
これまでは共有のウェアハウスを利用していたため、利用者がウェアハウスの切り替えを意識する必要はありませんでしたが、ロールによって利用できるウェアハウスが異なるため、ロールを切り替える際に合わせてウェアハウスの切り替えてもらう必要があります。
先述したとおり共有のウェアハウスを削除してロールで利用できるウェアハウスが1つしかない状態にすることで、利用者がウェアハウスを切り替える際に迷ったりミスをしたりすることを防ぐことができます。
ウェアハウスの切り替えを全社にアナウンスする際にも、「複数の中からチーム用のウェアハウスを選んで」ではなく、「1つだけ表示されているものを選んで」と言えるため、利用者にもわかりやすくなります。
チームメンバー用のロールについてはサービスユーザー用のロールと異なり、共有のウェアハウスが利用できなくなることによるインシデントのリスクがないため、作業手順は下記の3つを実行するだけです。
- チームメンバー用のロールにチーム用のウェアハウスの利用権限を割り当てる
- ユーザーのデフォルトウェアハウスを、チーム用のウェアハウスに変更する(複数チームのロールを利用できるユーザーのデフォルトウェアハウスを何にするかは利用状況によって変わるので、適宜設定してください)
- チームメンバー用のロールから共有のウェアハウスの利用権限を外す
余談:Snowsightでのウェアハウス切り替えの注意点
estieではチームごとにデータベースとロールが割り当てられているため、人によってはロールを頻繁に切り替えることがありますが、Snowsightのワークシートでロールを切り替えた際のウェアハウスの選択状態は下記の挙動となります。
例) ロールAからロールBに切り替えた場合
- ロールAで選択していたウェアハウスがロールBでも使える場合、ウェアハウスは選択されたままとなる
- ロールAで選択していたウェアハウスがロールBでは使えない場合、ウェアハウスは未選択の状態となる
後者の挙動は「まあそうだろう」という感じではありますが、ロールBで使えるウェアハウスが1つしかない場合は自動でそのウェアハウスを選択してくれる機能があると便利だろうなと思いました。
また、地味に使いにくいのがロールの選択とウェアハウスの選択を1度に実行できない作りになっている点です。
ロール選択とウェアハウス選択のダイアログは同じなのに、ロールを選択するとダイアログが閉じてしまうため、再度ダイアログを開いてウェアハウスを選択するといった手順が必要になります。
慣れてしまえばどうということはないものの、利用者目線ではウェアハウスを細分化する前と比べて明確に使いにくくなる部分なので、利用者に周知する際などにケアするのが良いと思いました。
Snowflakeではユーザー自身でSnowsightの画面からデフォルトのロールとウェアハウスを指定することができるため、頻繁に使うロールとウェアハウスの組み合わせを指定してもらうことで、ある程度はロール切り替え時のストレスを軽減できるのではないかと思います。
ロールへの割り当て以外でウェアハウスの切り替えが必要な箇所
ここまででウェアハウスの細分化とロールへの割り当て作業が完了しましたが、ウェアハウスの切り替えが必要な箇所が他にもあるため、作業手順をご紹介します。
Streamlit in Snowflakeアプリで利用するウェアハウスの切り替え
Streamlit in Snowflakeアプリの実行でもウェアハウスを利用しているので、そちらをチームごとのウェアハウスに切り替えました。
まず、下記のSQLを実行してStreamlit in Snowflakeアプリに割り当てられているウェアハウスを確認します。
show streamlits;
Streamlit in Snowflakeアプリに割り当てられたウェアハウスが確認できたので、割り当てを変更したいStreamlit in Snowflakeアプリに対して、下記のSQLを実行することで作業完了です。
alter streamlit DB名.スキーマ名.name set query_warehouse = 'xxx';
Snowsightのワークシートのフィルターで利用するウェアハウスの切り替え
Snowsightのワークシートやダッシュボードで利用するフィルターについてもウェアハウスを利用しているため、チーム用のウェアハウスに切り替えました。
実は今回の作業の中で、こちらの作業が最も大変だったかもしれません。
私が調べた限り、フィルターに紐づいたウェアハウスの切り替えはSQLで変更することができず、Snowsightの画面から1件ずつ変更していく必要がありました。
(もしSQLなどで変更できるよ、という情報をお持ちの方がいたら教えて下さい!!)
いつの間にか100件近くフィルターが作成されていたため、1件ずつ開いてはウェアハウスを切り替えると言った作業は、かなり大変でした。
共有のウェアハウスを削除する
ここまでの作業で共有のウェアハウスを利用する箇所をチーム用のウェアハウスに全て切り替えられたので、いよいよ共有のウェアハウスを削除(※)します。
※ ウェアハウスを残してもロールに割り当てなければ利用されないので削除しなくても良いのですが、残っていると誤ってロールに紐づけてしまうかもしれないので、削除する方針としました。使わないものは消す。
共有のウェアハウスの利用箇所を調査したので全て切り替えられているとは思うものの、見落としによってウェアハウスが利用できないことエラーが発生していないか心配になることもあるかと思います。
その場合、下記のSQLを実行することで、ウェアハウスが利用できずにエラーになったSQLの履歴を確認することができます。
select * from snowflake.account_usage.query_history where -- こちらの条件で抽出できる旨は、Snowflakeのサポートに問い合わせて確認しました execution_status = 'FAIL' and error_code = '000606'
user_name
カラムの値が人のユーザーでしたら、SQL実行時にウェアハウスを選択し忘れて実行した際のログだと思うので問題ないでしょうが、サービスユーザーのレコードが抽出された場合はウェアハウスの切り替え漏れが発生している可能性が高いです。
共有のウェアハウスを削除し、特に問題が発生しなければ今回のウェアハウスの細分化の作業は全て完了となります。
番外編
Fivetranで利用するウェアハウス
弊社ではSnowflakeへのデータ連携でFivetranを利用していますが、Fivetranから接続する時に利用するウェアハウスの設定について注意する点がありました。
私が作業を行った2025年1月時点では、FivetranがSnowflakeに接続する際に利用するウェアハウスを明示的に指定することができず、ユーザーのデフォルトウェアハウスが固定で利用されるようです。
そのため、今回の細分化のようにチームごとのロールとウェアハウスを紐づけた状態ですと、FivetranのユーザーがSnowflakeに接続する際に連携先のデータベースに合わせてロールを切り替えるといった指定をすることができません。
例1のように、Fivetranユーザーが利用するウェアハウスが固定であれば問題ないのですが、
例2のように、Fivetranユーザーが利用するロールがユーザーのデフォルトウェアハウス以外を利用するような設定はできないようです。
弊社では例1の方針とすることで、この問題を回避することにしました。
まとめ
ウェアハウスを細分化したことで、チーム間でSQLの実行タイミングが重なっても実行を待たされることがなくなり、SQLの実行が高速化されました。 チーム内でSQLの実行タイミングが重なる場合についても、チーム内でウェアハウスを更に細分化することで高速化できるため、SQLの実行待ちによるパフォーマンス低下問題が解決しました。
コスト管理についても、SnowsightのCost Management画面からチーム単位のコストを確認できるようになったため、とてもやりやすくなり、今回のゴールを無事に達成することができました。
最後に
弊社では全社員にSnowflakeのユーザーを発行し、誰でもデータに触れる環境を提供しているため、Snowflakeの操作方法についての理解度も人によって様々です。
Data Management Platformユニットでは、利用者が迷わずに使えるデータ基盤を提供したいという思いを持って日々、Snowflakeを運用しています。
現在、一緒にSnowflakeの運用に取り組んで頂けるデータ基盤エンジニアを募集中です。
興味がありましたらカジュアル面談でお話しましょう。情報交換だけのカジュアル面談も大歓迎です。