こんにちは、喜田です。
実はこれまでSnowflakeのプレビュー機能をぜんぜん触っていませんでした。プライベートの申請もだし、パブリックになっても。。。今回はちょっと話題になってる&得意分野が来たので勇気を出して、でもプレビュー触ってきたわけではない真っ白な目線でマニュアルを読み解いてみたいと思います。
SnowflakeのHybrid tables(Unistore)がパブリックプレビュー
2年ほど前に発表になり、OLAP(分析)ワークロードとOLTP(トランザクション)ワークロードをメンテナンスフリーで統合できるとして注目を集めていたUnistore。長らくのプライベートプレビューを経てプライベートプレビューになりました。
Hybrid Tableでは、CREATE時に指定できるテーブルのタイプで、CREATE HYBRID TABLE
とすると専用のフォーマットでデータを持つテーブルを作ることができ、OLTPワークロードにフィット、かつ、裏ではちゃんと列指向のファイルを維持するので既存のDWHとして期待されるワークロードにも耐えられるというものです。
これは期待できますが、どういう仕組みで、何かできて、どんな制限があるのか、めちゃめちゃ気になるところです。
Hybrid Tableのドキュメント
パブリックプレビューになったことでドキュメントが公開されましたので、そんな気になるポイントをドキュメントに説明されている範囲で読み解いていきたいと思います。
私はPostgreSQLやOracleでミッションクリティカルなDBの設計、監視、トラブルシュート等やってきましたので、こんなにワクワクする速報を出せる機会はなかなかないですね~~~。
Hybrid Tableとは
軽量・少数の行を検索して更新するために低レイテンシ、高い並列実効性を実現したテーブルフォーマットです。
operational queryとanalytical query
軽量・少数の行を検索して繰り返し更新することをoperational(操作的)と呼んでいます。
1つの出来事(商品が売れた)が1行になり、梱包→配送→配達完了→入金 のようなステータスを行に持たせ、その行を状態が変わるごとに繰り返し更新していくイメージです。(状態を持たすな、入金済みテーブルみたいにテーブルを移せといったテーブル設計論はあるとは思いますが、それもDELETEとINSERTが細かく走りますね。)
それに対するanalyticalワークロードはSnowflakeの従来の処理、大量行を一気に読んでそのデータ全体を分析することで知見を得るという処理内容・対象とするデータ範囲・期待する応答時間といった面で違いがあります。
operationalとanalyticalの共存
細かい更新をバラバラとたくさんやるoperationalと、一括更新・一括リードするanalytialでは最適なデータ格納方式が異なり、一般にDB製品はどちらかにフォーカスして作られています。
これを単一のシステムで扱おうと思うと、特性の異なる2つのデータベースを用意し、異種DB間のデータ連携を行う必要があります。
それぞれにフィットするテーブル設計(正規化するか否かみたいな)があり、DBをまたいでJOINは当然できずデータ連携して1か所に集めるとやっと使えるが、連携するなら鮮度がどの程度か、ネットワーク負荷、複数DBの運用コスト・・・など苦労が絶えません。
共存=Hybrid Workloadを実現するのがHybrid Table
SnowflakeのHybrid Tableでは以下の利点が紹介されています。
- 通常のテーブルと同じガバナンスなどの設定が可能(ただしTime Travel、クローン、PIPEなど非対応な機能も多数ある、サイズも100GBまで!)
- operationalとanalytialどちらも行うハイブリッドなワークロードを実行可能
- Hybrid Tableを従来のSnowflakeテーブルとJOINできる
- 2相コミット不要でトランザクションの原子性を保てる
通常のテーブルと同じようには、CREATE文を見るとHYBRIDを指定すること以外は特別なオプションはなく、普段通りテーブルに対して実装するような設定・機能が使えるということです。(ガバナンス=ロールによる権限管理など)
ただし、SQLリファレンスを見ると気になるオプションが。HYBRIDなりのできることには対応しています。インデックスや制約を定義して使うようになっていますね。
CREATE [ OR REPLACE ]
HYBRID TABLE [ IF NOT EXISTS ] <table_name>
( <col_name> <col_type> 中略
[ NOT NULL ]
[ inlineConstraint ]
[ , <col_name> <col_type> [ ... ] ]
)
inlineConstraint ::=
[ CONSTRAINT <constraint_name> ]
{ UNIQUE | PRIMARY KEY | { [ FOREIGN KEY ] REFERENCES <ref_table_name> [ ( <ref_col_name> ) ] } }
[ <constraint_properties> ]
JOINできるとは、言葉通り、Hybridと通常のテーブル同士のJOINができるんだ~と読むと全然普通のことのようで流してしまいそうな表現ですが、データ連携を廃し、単一のDB内で両ワークロードに対応した形をとれることを言っていると思われます。
上記でも挙げた苦労の一つにテーブル設計にはoperational用のテーブルは正規化、analytics用にはスタースキーマにするといったワークロードにフィットする形があり、それは1か所でJOINできるだけでは解消しない問題です。ある程度のところまではこのような製品機能で救えるとしても、従来のRDBMSのワークロードすべてを移すのではなくHybrid Tableに特化したユースケースや、そのうえでのテーブル設計の工夫といったことが必要になってくるのではないかと思います。
もう一つの原子性について書いている箇所は、データ連携をせずにoperationalとanalyticalを両立するもう一つの形として、1つのアプリケーションから2つのDBを同時に更新する方法と比較されているものと思います。
原子性とは、トランザクションに含まれる複数の更新(INSERT UPDATE DELETE)や複数の宛先に対する更新(テーブルをまたいだ更新、データベースをまたいだ更新)は同時に確定されるべきで、仮にロールバックするなら同時にロールバックされなければならないという決まりです。
operationalとanalyticalな2つのDBを同時に更新するとした場合、両DBが矛盾した状態になることを防ぐために、片方が障害で停止していたら正常なほうでも更新を受けてはいけないといった2相コミット(Two phase commit、両者にいきなり更新を投げるのではなく「準備OK」がちゃんと帰ってきてから実際の値を更新しにいく仕組み)を考える必要があります。Hybrid Tableでは単一のデータに対する更新なので、そういった煩わしさをなくせる機能ですよと言っています。
どうやって実現しているのか
動作はごく簡単に紹介されています。
Hybrid Tableに対する更新は rowstore
(メモリ上の領域?詳細不明)に格納され、準同期的(asynchronously )にオブジェクトストレージ(S3層のファイルと思われる)に格納されます。
準同期とは、各更新につき即座にではなく、ある程度まとめて、ただしインターバルに従う定期とも違って処理された内容にあわせてと読めます。
準同期でファイルに書く目的は、同じテーブルに対する分析ワークロードがoperationalワークロードの妨げにならないように、と説明されています。またウェアハウス内のcacheには列指向に変換しながらデータを持つので分析ワークロードにもベターな性能を発揮するそうです。
これはメモリ上で更新を完結し、後でファイルに書き込んでおくRDBMSのトランザクションログ+チェックポイント動作と似ています。とはいえ、RDBMSはクラッシュリカバリのためにデータを永続化する目的で、「ファイルを直読みすることがメリット」ととれる上記の説明はまるで異なる目的に見えます。またトランザクションログは同期的に、チェックポイントは非同期的にやるのが通常で、準同期とは乖離があります。数MBのマイクロパーティション単位で細かく書き込むのだとしたら別のメリットデメリットがありそうですね。(詳細は公開されていない)
また、ここでいうオブジェクトストレージについて、
従来から格納データ量を把握するために用意されているSTORATE_USAGEビューを見るとSTORAGE_BYTES
、STAGE_BYTES
、FALESAFE_BYTES
に並んで新たにHYBRID_TABLE_STORAGE_BYTES
列が追加されています。つまり、最終的に列指向に変換してanalyticalワークロードに備えるとしていますが、そのためのファイル形式はHYBRID固有の形であり、従来のテーブルとは扱いが違うようです。STORAGE_BYTESなどの説明を細かく読むとTimetravel用のデータも含むといったことが書かれていますので、HYBRIDのほうはTimeTravelないんだなーとか。あと独自フォーマットの行ストアで4kBのブロックで扱うともどこかにあったかな。Hybrid Tableの従量課金についてで記載がありました。
Hybrid Tablesを取り巻く機能
以下に紹介されているものは通常のテーブルにはないHybrid Tableの独自機能です。
- データレイアウトは行指向で、事後的にカラム指向に変換されます。
- 行レベルロックに対応しています。
- プライマリキーや外部キーに対応し、それに期待される一意制約、参照整合性制約に対応します。(従来テーブルでは定義できるが制約として機能しない)
- パフォーマンスのためのインデックス作成、インデックスは同期的に更新される。(従来テーブルではSearch Optimization機能で事後更新)
前々から気になっていたのはインデックス更新を担うのは誰か?
従来テーブルのインデックスに近い動きをするSearch Optimizationはメタデータ収集用ウェアハウスがバックグラウンドで動く(=課金対象)でした。
インデックス更新はメインのSQLを担当している仮想ウェアハウスが同時にやってくれるのだとすれば、それが直接課金になることはないんじゃないかな~と思います。そもそも仮想ウェアハウスのサイズをXSにした場合でもOLTPにはまあまあな性能を持っていると思われるので、そういう余力はありそう。
(該当しそうなところを見つけたので追記)
Hybrid Tableの従量課金について、行指向データのメンテナンスに専用のサーバーレスウェアハウスが動くことが明記されていました。インデックス更新するのもこの子ですね。
- ストレージ(独自フォーマットではあるが今までとほぼ同じ、TiveTravel分が不要)
- 仮想ウェアハウス(従来通り)
- Hybrid Table用のサーバーレスウェアハウス(ウェアハウスが稼働するけど、読み書きしたデータ量で課金)
他のSnowflakeのサーバーレスインスタンスはバックグラウンドで稼働していた時間依存ですが、Hybrid Tableに関しては読み書きしたデータサイズが課金対象になるそうです。が、今のところ単価が示されていないですね。
以下、マニュアルにない気になるポイント
実務でHybrid Tableを扱おうと考えている皆様には、ぜひこのあたりの要件と、それに対してSnowflakeがどう対応しているか、ぜひ情報発信お願いしたいところです。(ぶっちゃけ要件が緩ければそれでいい世界ではあるので、その辺の判断を含めて聞きたいな~。)
ACIDのA(原子性)C(一貫性)以外への考慮は?
原子性
上記で対応が説明されていました。もともとSnowflakeはBEGIN~COMMITに対応しているし、テーブル特性が変わってもそこは守るようです。
一貫性
制限事項をみると記載がありました。セッション内では一貫性を維持し、他セッションからは100ms程度遅れる可能性がある。パラメータで救済可だがオーバーヘッドがあるとのこと。
これは外部キー制約のチェックのことを言っていると思われます。制約を課す側の商品マスタに商品を追加し、売上テーブルにその商品が売れたことを登録しようとする場合、同時多重のシビアなタイミングで売上テーブルを更新しようとすると、まだ商品マスタに反映が追い付いていない(エラーor待たせる)可能性があるというような話に見えます。
独立性
特に記載を見つけられていません。
複数人が同時に更新や参照する状況で、COMMITされるまでの途中経過を他人に見せないのが独立性です。ある瞬間にまだ古い行を見ているAと、更新者だけが見える行A’が両方存在し、このAとA’のように行レベルのバージョン管理が考慮されているものです。このためには、A’で上書きしないようAをどこかに逃がしておく(OracleのUNDO領域)やA’とAが共存し、Aを後から削除する(PostgreSQLのVACUUM)といった実装があり、これらのメンテナンスはRDBMS製品では何かしらがつきまとう悩ましい問題です。
Snowflakeではどこまで実現されるのか、どうやるかまだマニュアルだけ見る限りでは不明です。ただ、一貫性のところでセッション内外で取れる結果が違うことがわかるので、セッション固有のメモリ内で処理したことを確定後に全体に反映するような動きで独立性もカバーしているのかなと予想しています。
永続性
特に記載を見つけられていません。
SnowflakeはTime Travelとバックグラウンドのオブジェクトストレージの(ハードウェア的な故障リスクに対する)強さに期待している点で、RDBMSのようなバックアップリカバリの仕組みから解放されていていました。
ただし、OLTP業務処理を真面目に扱おうと思うと、リアルタイムな業務処理に対して、COMMIT済みのデータを確実にロストしないためのクラッシュリカバリの仕組みは知っておく必要があります。
RDBのチェックポイントとトランザクションログは、更新差分を確実に永続化することでサーバーやプロセスが停止しても確実にデータを復旧できるといったことを目的にしています。では、Snowflakeは?クラッシュリカバリやそのためのトランザクションログといった概念は説明されていないので、仮想ウェアハウスが寝るタイミングでは書き込みが走るんだろうな~と想像しているものの、24/365、常時起きっぱなしが期待されるOLTPのユースケースで、仮想ウェアハウスが(背後にあるコンピュートインスタンスの障害などで)予期せず停止してしまうような場合を考慮しなければならないと考えています。ストレージ層に届いていないデータがどうなるのかまだ不明です。S3層まで届く前に、仮想ウェアハウスのローカルストレージにトランザクションログっぽいファイルを持つのかな???
考察:リアルタイムデータをもっと簡単に扱う世の中へ
ここまでも想像盛りだくさんで書いていますが、ここから先は根拠のない妄想です。
ここまで挙げたようにOLTP業務を代替するにはまだ明らかになっていない懸念点が多く、すべて置き換えるようなものではない、という前提で、じゃあどういう目的で使うのか?を考えています。
これまでのデータとこれから生み出されるデータ
ストリームデータの取り込みのためにsnowpipeなど便利な仕組みが用意されていますが、手前にKafkaがいる前提であったり、マイクロバッチ的にロードするにもAWS側でファイルが置かれたことをチェックする仕組み化が必要です。(SQL過激派の私としてはそこが馴染み薄いところだったりしてます。それすらSQLで定義できちゃうの?で勇気をもらっているポイントでもあります。)
一方、街中にはセンサー、カメラなど溢れ、リアルタイムな行動がデータ化され、それをAIで瞬時に判別してアクションに繋げるといったことも当たり前の施策として考え得るようになってきました。このようなデータを生み出し、入力に特化したアプリケーションがSnowflakeに直接書き込める道ができたことはリアルタイムなデータを前提にしたアクションに大変有益な一歩だと思います。センサーからRDBに高スループットで書き込むというのはこれまでも普通にあったわけで、データ基盤に取り込むためにバッチ化する、ストリーム化するところが丸ごと無くせるような使いどころを期待したいです。
従来業務のOLTP処理をそのままSnowflakeに置き換える目的ではなく、あくまでデータ基盤に取り込むべきデータ(それなら途中で書いた正規化の問題もクリアしている。別にOLTP業務をそのまま実行したいわけではない)、しかも、そのデータは今までは存在・発生すらしていなかった新しい種類のデータで、次世代のライブデータに対する受け口になるんじゃないかと希望に満ちた考察でこの記事を終わりたいと思います。
この記事へのコメントはありません。