Simplifying Big Data Disaster Recovery with Delta Clones - The Databricks Blogの翻訳です。
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
ノートブック:Using Deep Clone for Disaster Recovery with Delta Lake on Databricks
多くのビジネスにとって、災害イベント、緊急事態や他の問題においてデータストアのような重要なサービスがオンラインであり続けるようにするために、ビジネス継続性プランの作成は非常に重要となっています。多くの場合、ハリケーンのような災害や、未知のイベントによって引き起こされる稀なリージョナルのクラウド障害においても、データチームがDatabricksプラットフォームを使いつづけられることはミッションクリティカルなこととなっています。AzureやAWSのディザスターリカバリーガイドにあるように、Databricksは多くの場合、上流のデータ取り込み、洗練されたデータパイプライン、クラウドネイティブのストレージ、機械学習と人工知能、ビジネスインテリジェンスとオーケストレーションを含むデータエコシステム全体のコアパーツとなっています。いくつかのユースケースは特に、リージョン規模の障害にセンシティブかもしれません。
本書で説明するでィザスターリカバリーの全体の流れを説明する動画(別のブラウザタブが開きます)
みなさまのデータインフラストラクチャの継続性を保証し、復旧のためのツール、ポリシー、手順を策定するディザスターリカバリーは、あらゆるビジネス継続性プランにおいて重要なコンポーネントとなっています。Deltaクローンは、データ複製をシンプルなものとし、お使いのDeltaテーブルに対する効果的なリカバリー戦略の立案を可能にします。Deltaクローンを用いることで、あなたのプライマリーサイトとセカンダリーサイト、あるいはリージョン間で適切な順序でデータを容易かつインクリメンタルに同期することができるようになります。DeltaはRDBMSレプリケーションがデータベースを安定状態に復旧する際にログを使用するのと同じように、この同期を行うためにトランザクションログを使用します。クラウドのマルチリージョンの同期のようなソリューションが問題の一部を解決するかもしれませんが、これらの処理は通常非同期であり、オペレーションがうまく動作せずデータの破損を引き起こすことになります。
本書では、Deltaクローンがどのようにこれらの問題を回避し、データセンター間のデータ同期のプロセスをコントロールすることでDRを押し進めるのかを説明します。
クローンとは?
おそらくですが、最初の質問は「クローンって何?」ではないでしょうか。
クローンとは、ある時点におけるソーステーブルの複製です。これらは、ソーステーブルと同じメタデータを持ちます。すなわち、同じスキーマ、同じ制約、同じコラムのコメント、統計情報、パーティショニングを持ちます。しかし、クローンはソーステーブルとは別の独立した履歴を持つことに注意してください。例えば、ソーステーブルとクローンに対するタイムトラベルのクエリーは同じ結果を返さない場合があります。
シャロー(浅い、あるいはゼロコピー)クローンは、クローンされるテーブルのメタデータのみを複製します。テーブル自身のデータファイルはコピーされません。このタイプのクローンは別の物理的なデータコピーを作成しないので、ストレージコストは最小になります。シャロークローンはリソース集約型ではないので、非常に高速に作成することができます。しかし、これらのクローンは自己完結型ではなく、クローンしたソースに対する依存関係を維持します。シャロークローンは、実際にプロダクションテーブルを変更することなしに、プロダクションテーブルに対する構成変更をステージングするようなテストや実験にはメリットがあります。詳細に関しては、Easily Clone your Delta Lake for Testing, Sharing, and ML Reproducibilityをご覧ください。
ディープクローンは、クローンされるテーブルのメタデータとデータファイルの完全なコピーを作成します。これはCTAS(CREATE TABLE... AS... SELECT...)コマンドと同じようなものです。しかし、ある時点でのオリジナルテーブルの現行バージョンの公正なコピーを作成するので、CTASでは指定しなくてはならないパーティショニングのオプション、制約や他の情報を指定する必要はありません。さらに、はるかに高速で堅牢であり、インクリメンタルに動作することも可能です。最後に、全てのデータではなく、障害から防御すべきデータのみを複製する効率的なソリューションを実現できる点が重要です。
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone.png
ディープクローンは以下のケースで有用です。
- プロダクションのデータプロセスのリスクを与えず、ユーザーに影響を与えることなしに、プロダクション環境におけるテストの実施
- プロダクションテーブルに対する大きな変更のステージング
- ML結果の再現性の保証
- データ移行、データ共有やアーカイブ
本書では、ディザスターリカバリーにおけるDeltaのディープクローンの役割にフォーカスします。
クローンを見せて!
以下のSQLコマンドでクローンを作成することができます。
CREATE OR REPLACE TABLE loan_details_delta_clone
DEEP CLONE loan_details_delta;
以下のSQL文を用いることでオリジナルのテーブル(loan_details_delta
)とクローンされたテーブル(loan_details_delta_clone
)両方に対してクエリーを発行することができます。
-- Original view of data
SELECT addr_state, funded_amnt FROM loan_details_delta GROUP BY addr_state, funded_amnt
-- Clone view of data
SELECT addr_state, funded_amnt FROM loan_details_delta_clone GROUP BY addr_state, funded_amnt
以下の図ではDatabricksノートブックの地図の可視化を用いた結果を示しています。
https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-original-clone-view-map.png
ディープクローンの重要な機能には、インクリメンタルなアップデートがあります。オリジナルとクローンの間の一貫性を保証するためにテーブル全体をコピーするのではなく、データに加えられた変更行(更新、削除、マージ、インサートされたレコード)のみが、次回テーブルがクローンされる時にコピー、更新されます。
https://raw.githubusercontent.com/databricks/tech-talks/master/images/deep-clone-incremental-update.png
ディープクローンでインクリメンタルなアップデートがどのように動作するのかを説明するために、以下のSQLを用いてオリジナルテーブルから行を削除してみましょう(上の図におけるステップ1)。
DELETE FROM loan_details_delta WHERE addr_state = 'OH';
この時点では、オリジナルテーブル(loan_details_delta
)にはオハイオ(OH)の行は含まれていませんが、クローンされたテーブル(loan_details_delta_clone
)にはこれらの行は残っています。二つのテーブルを再度同期するには、再びクローンのオペレーションを実行します(ステップ2)。
CREATE OR REPLACE TABLE loan_details_delta_clone
DEEP CLONE loan_details_delta
クローンテーブルとオリジナルテーブルは同期状態に戻ります(これは以降のセクションでさらに明らかになります)。しかし、オリジナルテーブルのコンテンツ全体をコピーするのではなく、インクリメンタルに行が削除されるので、劇的にプロセスを高速にします。クローンされたテーブルはオリジナルテーブルで更新された行のみを更新するので、この場合、オハイオに該当する行が削除されますが、他の行は変更されません。
OK、このブログの障害から復旧しましょう
クローンによるディザスターリカバリーはコンセプト的にはわかりやすいものですが、あらゆるDBAやDevOpsエンジニアが証言するように、ディザスターリカバリーのソリューションの実際の実装はさらに複雑なものとなります。多くのプロダクションシステムは、RDBMSにおけるアクティブ-アクティブクラスターと同じような双方向のディザスターリカバリープロセスを必要とします。アクティブなサーバー(ソース)がオフラインになった際、セカンダリーサーバー(クローン)は読み書きのオペレーションを行えるようにオンラインになる必要があります。以降のシステム対する変更(データに対するインサート、変更)は、今時点でクラスターでアクティブであるセカンダリーサーバーに対して行われます。そして、オリジナルのサーバー(ソース)がオンラインに復帰したら、クローンに対して行われた全ての変更をソースに再度同期する必要があります。再同期の完了を持って、ソースサーバーが再度アクティブに復帰し、クローンサーバーはセカンダリーの状態に戻ります。システムは継続的にデータを提供し、データを変更し続けるため、データの損失をなくすためにデータのコピーはクイックに同期することが重要となります。
ディープクローンを用いることで、以下の図に示すようにマルチリージョンの分散システムでおいても、このワークフローを容易に実行することができます。
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline.png
この例では、ソースはアクティブなDatabrikcsのリージョンのテーブルであり、クローンはセカンダリーリージョンのテーブルとなります。
- t0時点: insert/update文はソーステーブルに対して実行され、ソースとクローンテーブルが同期状態にあり続けるように
DEEP CLONE
を実行します。 - t1時点: 2つのテーブルは同期しています。
- t2時点: ソーステーブルにアクセスできません。クローンテーブルが、このタイムスタンプ以降の全てのクエリーとデータ変更が行われるソース' になります。
- t3時点: DELETE文がソース' に実行されます。
- t4時点: ソーステーブルにアクセスできるようになりましたが、ソース' とソースは同期していません。
- t4'時点: ソース' とソースを同期するために
DEEP CLONE
を実行します。 - t5時点: 2つのコピーは同期されたので、ソースはアクティブテーブルとして稼働を再開し、ソース' はセカンダリーテーブル、クローンに戻ります。
次に、DatabricksでSQLコマンドを用いてこれらのステップをどのように行うのかを説明します。Using Deep Clone for Disaster Recovery with Delta Lake on DatabricksのDatabricksノートブックを実行することで、作業を再現することもできます。
ソースの変更
通常のデータ処理の一部として、アクティブリージョン(ソース)のテーブルのデータを変更するところからスタートします。
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline-0.png
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-insert-update-example.png
この場合、TX
に対するUPDATE
文(Amount
カラムの更新)とOH
に対するINSERT
文(TX
とAZ
のエントリーに基づく新規行の挿入)を用いてマージを実装します。
ソーステーブルとクローンテーブルのバージョンチェックします。このシナリオはloan_details_deltaとloan_details_delta_cloneテーブルが同期しているt0時点からスタートしています。そして、loan_details_deltaテーブルを変更しました。どうすれば、両方のテーブルをクエリーして比較することなしに、データのバージョンが同じと言えるのでしょうか?Delta Lakeでは、この情報はトランザクションログに記録されているので、DEEP CLONE
文は一つのテーブルクエリーでソースとクローンのバージョンの両方を自動で特定することができます。
DESCRIBE HISTORY DeltaTable
を実行した際には、以下のようなスクリーンショットのような結果を確認できるはずです。
注意
オリジナルのテーブルはloan_details_delta
であり、クローンテーブルはloan_details_delta_clone
です。
これを詳細に見ていきます。
- ソーステーブルにおいては、テーブルバージョンを特定する最も最新のバージョン番号はここではバージョン2となります。
- クローンテーブルにおいては、クローンテーブルがどのソースバージョンから作られたのかを特定するために、最新の
operationParameters.sourceVersion
をクエリーします。ここではバージョン1となります。
上で述べたように、この情報は全てDelta Lakeのトランザクションログに格納されています。また、二つのテーブルのバージョンを確認するためにトランザクションログに対してクエリーを行うために関連ノートブックに含まれているcheckTableVersions()
関数を使うこともできます。
checkTableVersions()
Delta Lake Original Table Version: 2, Cloned Table Version: 1
ログの詳細については、Delta Lakeにダイビング:トランザクションログを読み解くをご覧ください。
ソースとクローンの再同期
上のセクションで見てきたように、今ではソーステーブルはv2ですが、クローンテーブルはv1となっています。
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline-0b1.png
二つのテーブルを同期するために、t1時点で以下のコマンドを実行します。
CREATE OR REPLACE TABLE loan_details_delta_clone
DEEP CLONE loan_details_delta;
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline-1.png
ソーステーブルにアクセスできません
t2時点で、ソーステーブルにアクセスできなくなりました。ユーザーの誤操作あるいはリージョンのダウンなど、この原因がなんであれ、これが目を覚ますための偉大なライフハックではないことを認めなくてはなりません。
ソース: https://www.reddit.com/r/ProgrammerHumor/comments/kvwj9f/burn_the_backups_if_you_need_that_extra_kick
私がどのようにモーニングルーチンをハックしたのか: プロダクションデータベースを消去したら100%完全に目が覚めました。
冗談はさておき、実際のところ、あなたはプロダクションシステムがオフラインになることに常に備えていなくてはなりません。幸運なことに、あなたのビジネス継続性プランのおかげで、データを読み書きするためにお使いのサービスをクローンにリダイレクトできるセカンダリーのクローンがあります。
データの訂正
オリジナルのソースが利用できないため、セカンダリーリージョン(クローン)が今ではソース' テーブルになります。
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline-2.png
すぐにデータを変更する必要がないいくつかのサービスはソースにアクセスできない間、read-onlyモードに切り替えることができますが、多くのサービスやプロダクション環境はそのような遅延を許容できないでしょう。この場合、t3時点ではソース' データを変更し、いくつかのレコードをDELETEしなくてはなりません。
-- Running `DELETE` on the Delta Lake Source' table
DELETE FROM loan_detail_delta_clone WHERE addr_state = 'OH';
テーブル履歴を確認するか、checkTableVersions()
を実行すると、(Source’ )テーブルはDELETE文の実行後にバージョン4になっています。
# Check the table versions
checkTableVersions(2)
Delta Lake Original Table Version: None, Cloned Table Version: 4
オリジナルのソーステーブルには到達できないので、バージョンはNoneとなります。
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline-3b.png
クローンテーブルがバージョン4である理由は、履歴を確認することでクイックに特定することができ、以前に実行した3つのCLONE
オペレーションとDELETE
コマンドです。
DESCRIBE HISTORY loan_details_delta_clone
ソースに戻す
やりました、<何かしらの修正>
のあとで、オリジナルのソーステーブルがオンラインに戻りました!
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline-4b.png
しかし、以前のステップで見たように、ソースとソース' レプリカの間には違いがあります。幸運なことにこの問題の修正は簡単です。
/* Fail back from the `loan_details_delta_clone` table to the `loan_details_delta` table */
CREATE OR REPLACE TABLE loan_details_delta
DEEP CLONE loan_details_delta_clone;
オリジナルのソーステーブル(loans_details_delta_clone
)を置き換えるためにDEEP CLONE
を実行することで、クイックにオリジナルの状態に戻すことができます。
ソース: https://raw.githubusercontent.com/databricks/tech-talks/master/images/delta-lake-deep-clone-timeline-5.png
これで、我々の全てのサービスがオリジナルのソース、ソース' テーブルがクローン(セカンダリー)の状態にまで戻りました。
何人かの人は、今ではクローンテーブルのバージョンは4ですが、ソーステーブルのバージョンが3であることに気づいたかもしれません。これは、バージョン番号はテーブルに対してなされたオペレーションの数に関連づけられることに起因します。この場合、ソーステーブルになされたオペレーションの数は少ないです。
DESCRIBE HISTORY loan_details_delta
| ------- | --------- | --- | --------- | --- |
| version | timestamp | --- | operation | --- |
| ------- | --------- | --- | --------- | --- |
| 3 | ... | ... | CLONE | ... |
| 2 | ... | ... | MERGE | ... |
| 1 | ... | ... | DELETE | ... |
| 0 | ... | ... | WRITE | ... |
注意事項
ディザスターリカバリーに対するこの手法は、障害に関係なく読み書きの両方の可用性を保証します。しかし、途中の変更を失う可能性があるというコストが存在します。以下のシナリオを考えてみます。
2つのCLONE
オペレーションの間のt=1でアップデートがあることに注意します。2回目のCLONE
オペレーションが行われるとt=4の時点でこの間隔で行われた変化が失われる可能性があります。いかなる変更も失われないようにするためには、t=1とt=4の間でソーステーブルに書き込みを行わないことを保証する必要があります。リージョン全体が不調になる可能性があることを考えると、これを達成することは難しいです。とはいえ、可用性が最も重要な検討事項であるユースケースは多く存在します。
まとめ
本書では、DatabricksのDelta LakeのDEEP CLONE
機能を用いた双方向ディザスターリカバリーの実行方法をデモンストレーションしました。Delta LakeのSQL文のみを用いることで、ビジネス継続性プランの一部として、データのレプリケーションを劇的にシンプルにし、高速化することができます。Deltaクローンの詳細に関しては、Easily Clone your Delta Lake for Testing, Sharing, and ML Reproducibilityを参照ください。ご自身でDatabricksランタイムを用いてこのエクササイズをウォークスルーするためにUsing Deep Clone for Disaster Recovery with Delta Lake on Databricksをチェックしてみてください。
謝辞
この記事に貢献してくれたPeter Stern, Rachel Head, Ryan Kennedy, Afsana Afzal, Ashley Trainorに感謝の意を表します。