DatabricksにおけるACID保証とは？

[What are ACID guarantees on Databricks? \| Databricks on AWS](https://docs.databricks.com/lakehouse/acid.html) [2022/11/14時点]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

Databricksではデフォルトですべての読み書きにDelta Lakeを使用しており、[オープンソースのDelta Lakeプロトコル](https://delta.io/)によって提供されるACID保証の上に成り立っています。

- [原子性(Atomicity)](#databricksではどのように原子性を実装しているのか)とは、すべてのトランザクションが完全に成功するか、完全に失敗するかのいずれかになることを意味します。
- [一貫性(Consistency)](#databricksではどのように一貫性を実装しているのか)は、同時のオペレーションにおいて、ある状態のデータがどの様に観測されるのかに関して保証します。
- [分離性(Isolation)](#databricksではどのように分離性を実装しているのか)は同時のオペレーションが違いにどの様に競合するのかに関するものです。
- [耐久性(Durability)](#databricksではどのように耐久性を実装しているのか)はコミットされた変更が永続的であることを意味します。

多くのデータ処理、ウェアハウジングの技術ではACIDトランサクションがあると言及されていますが、特定の保証内容はシステムによって異なり、Databricksにおけるトランザクションは皆様が使われている他のシステムとは異なる場合があります。

:::note
**注意**
本書ではDelta Lakeによって実現されるテーブルの保証を説明します。他のデータフォーマットや連携システムにおいては、読み書きのトランザクション保証を行わない場合があります。

クラウドオブジェクトストレージに対するすべてのDatabricksの書き込みでトランザクションによるコミットを使用し、データファイルとともに`_started_<id>`や`_committed_<id>`で始まるメタデータファイルを作成します。Databricksが定期的に古いメタデータファイルをクリーンアップするので、皆様はこのファイルを機にする必要はありません。
:::

# Databricksにおけるトランザクションはどの様なスコープなのか？

Databricksではテーブルレベルでトランザクションを管理します。トランザクションは常に一度に一つのテーブルに対して適用されます。同時実行されるトランザクションを管理するために、Databricksでは楽観的コンカレンシー制御を使用します。これは、テーブルの読み書きにおいてロックを行わず、デッドロックが発生しないことを意味します。

デフォルトでは、Databricksでは読み込みにおいてはスナップショットのアイソレーション、書き込みにおいては[write serializableのアイソレーション](https://qiita.com/taka_yayoi/items/62a581c20ab4096a990b#write-serializable%E3%82%A2%E3%82%A4%E3%82%BD%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%AC%E3%83%99%E3%83%AB-%E5%AF%BE-serializable%E3%82%A2%E3%82%A4%E3%82%BD%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%AC%E3%83%99%E3%83%AB)を提供します。Write serializableアイソレーションは、スナップショットのアイソレーションよりも強力な保証を行いますが、書き込み時にのみこの強力なアイソレーションを適用します。

複数のテーブルを参照する読み込みオペレーションは、アクセス時の現行テーブルバージョンを返却しますが、参照しているテーブルを変更する可能性がある同時実行されているトランザクションに干渉しません。

Databricksでは複数のオペレーションを一つのトランザクションにグループ化できる`BEGIN/END`構文は提供していません。複数のテーブルを変更するアプリケーションは、直列化された形でそれぞれのテーブルにトランザクションをコミットします。`MERGE INTO`を用いることで、テーブルに対するインサート、アップデート、デリートを一つの書き込みトランザクションにまとめることができます。

# Databricksではどのように原子性を実装しているのか？

トランザクションログがコミットの原子性を制御します。トランザクション中は、テーブルを構成するファイルディレクトリにデータファイルが書き込まれます。トランザクションが完了すると、トランザクション中に書き込まれたすべてのファイルへのパスを含む新規エントリーがトランザクションログにコミットされます。それぞれのコミットはテーブルバージョンを増加させ、読み込みオペレーションで新たなデータファイルが参照できる様になります。テーブルの現在の状態は、トランザクションログにおいて適正とマークされたすべてのファイルから構成されます。

トランザクションログが新規バージョンを記録しない限り、データファイルは追跡されません。テーブルにデータファイルを書き込んだ後にトランザクションが失敗すると、これらのデータファイルがテーブルの状態を破損させることはありませんが、このファイルはテーブルの一部とはなりません。`VACUUM`オペレーションは、失敗したトランザクションによる未コミットのファイルを含む未追跡のデータファイルの全てを削除します。

# Databricksではどのように耐久性を実装しているのか？

Databricksでは、すべてのデータファイルとトランザクションログを格納するためにクラウドオブジェクトストレージを使用します。クラウドオブジェクトストレージは高い可用性と耐久性を提供します。トランザクションは完全に成功するか完全に失敗するかのいずれかであり、クラウドオブジェクトストレージに格納されるデータファイルとともにトランザクションログが存在し、Databricksのテーブルは格納されているクラウドオブジェクトストレージの耐久性保証を受け継ぎます。

# Databricksではどのように一貫性を実装しているのか？

Delta Lakeは書き込みにおけるトランザクション保証を提供するために、楽観的コンカレンシー制御を使用します。この機構のもとで、書き込みは3つのステージでオペレーションされます

1. **読み込み:** どのファイルを修正(再書き込み)する必要があるのかを特定するために、利用できる最新バージョンのテーブルを(必要であれば)読み込みます。
    - 追加のみを行う書き込みは、書き込み前にテーブルの現在の状態を読み込みません。スキーマの検証ではトランザクションログのメタデータを活用します。
1. **書き込み:** テーブルの定義で使用されているディレクトリにデータファイルを書き込みます。
1. **検証とコミット:**
    - スナップショットを読み込んだ以降、同時処理でコミットされた他の変更と提案された変更が競合しないかどうかをチェックします。
    - 競合しない場合、ステージングされたすべての変更は新規バージョンのスナップショットとしてコミットされ、書き込みのオペレーションが成功します。
    - 競合する場合、同時実行更新の例外で書き込みオペレーションが失敗します。失敗することによってデータの破損を防ぎます。

楽観的コンカレンシーは、皆様のデータに対する同時実行トランザクションの多くが他のトランザクションと競合しないが、競合は起こりうるものであるという前提に立っています。[Databricksにおけるアイソレーションレベルと書き込みの競合](https://qiita.com/taka_yayoi/items/62a581c20ab4096a990b)をご覧ください。

# Databricksではどのように分離性を実装しているのか？

Databricksでは、デフォルトですべてのテーブルへの書き込み、更新でwrite serializableアイソレーションを使用します。すべてのテーブル読み込みでは、スナップショットアイソレーションが使用されます。

書き込みの高スループットを実現するために、書き込みのシリアライズ可能性と楽観的コンカレンシー制御が連携して動作します。現行の適正なテーブルの状態が常に利用でき、任意のタイミングでテーブルの書き込みをスタートすることができます。同時実行される読み込み処理は、メタストアとクラウドリソースのスループットによってのみ制限を受けます。

[Databricksにおけるアイソレーションレベルと書き込みの競合](https://qiita.com/taka_yayoi/items/62a581c20ab4096a990b)をご覧ください。

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)