Upgrade to Pro — share decks privately, control downloads, hide ads and more …

1. ScalarDB Cluster Development - ScalarDB Tran...

1. ScalarDB Cluster Development - ScalarDB Transaction: Fundamentals

本スライド「ScalarDB Transaction Fundamentals」は、異種・複数データベース間にまたがる分散トランザクションを実現する「ScalarDB」のコアプロトコル(Consensus Commit)の基礎を解説した資料です。

リレーショナルデータベースやNoSQLを組み合わせた環境において、どのようにACID特性とデータの一貫性を保証しているのか、その内部構造と動作原理を詳細に解説しています。

【主な内容】
・ScalarDBの概要とトランザクションプロトコルの技術的選択
・分散WAL(Distributed WAL)の仕組みとレコードに付与されるメタデータ構造
・トランザクション状態を一元管理するコーディネーターテーブル(coordinator.state)の役割
・Consensus Commitの具体的な動作フロー(単一/複数データベースにおけるPrepare〜Commitフェーズの遷移)
・書き込み競合が発生した際の検知とRollback(Abort)の挙動
・Strict Serializabilityを保証するためのアプローチ(Serializable Strategy / Extra-read)
・Parallel Commit等を活用した性能最適化の仕組み

マイクロサービスアーキテクチャや複数データストア環境におけるデータ整合性の課題に取り組む開発者や、楽観的並行性制御(OCC)ベースの分散トランザクションの仕組みに関心のあるエンジニアにおすすめの資料です。

Avatar for Scalar, Inc.

Scalar, Inc. PRO

May 14, 2026

More Decks by Scalar, Inc.

Other Decks in Technology

Transcript

  1. 変更履歴 Version Date Name Supported products and versions Description 1.0

    2025/4/9 Satoshi Hikida ScalarDB Cluster 3.15.1 First draft
  2. 4 ⽬次 • 概要 • 分散WAL (Distributed WAL) • コーディネーターテーブル(coordinator.state)

    • Consensus Commit の動作 ◦ 単⼀データベースにおけるトランザクション ◦ 複数データベースにおけるトランザクション • Serializable Strategy • 性能最適化
  3. 7 データベース構成に応じたトランザクションの種類 単⼀DBにおけるトランザクション 複数DBにおける分散トランザクション Transaction Manager (DBMS) Transaction Manager (Coordinator)

    DBMS 1 DBMS 2 DBMS 3 • 単⼀のDBMSによりトランザクションを管理 • 例:MySQL, PostgreSQL, Oracle, etc TM: Transaction Manager • Coordinatorと呼ばれるプロセス(サーバー)がトラ ンザクションを⼀元的に管理 • 例:Oracle Tuxedo, Atomikos, Seata XA, ScalarDB
  4. 8 ScalarDBの技術的選択 Multi-level Transaction Management Single-level Transaction Management Pros: XAなどの既存製品がある

    Pros: 性能を上げやすい Cons: データベース依存度が⾼い Cons: アプローチが侵襲的 Pros: データベース依存度が低い Pros: アプローチが侵襲的でない Cons: 弱い分離性 Cons: 性能が上げにくい TM (Coordinator) Abstraction Abstraction TM Abstraction TM DB1 Global Transactions Local Transactions DB2 TM: Transaction Manager TM (Coordinator) Abstraction DB1 Global Transactions Local Transactions DB2 CC: Concurrency Control No CC is required No CC is required
  5. ScalarDB のアプローチ TM (Coordinator) Abstraction Abstraction TM Abstraction TM DB1

    Global Transactions Local Transactions DB2 TM (Coordinator) Abstraction DB1 Global Transactions Local Transactions DB2 No CC is required No CC is required ScalarDBが解決 9 ScalarDBの技術的選択 Multi-level Transaction Management Single-level Transaction Management Pros: XAなどの既存製品がある Pros: 性能を上げやすい Cons: データベース依存度が⾼い Cons: アプローチが侵襲的 Pros: データベース依存度が低い Pros: アプローチが侵襲的でない Cons: 弱い分離性 Cons: 性能が上げにくい Global Transactions CC: Concurrency Control
  6. 10 ScalarDBのトランザクションプロトコル概要(1) • コミットプロトコル:⼆相コミットの亜種 • Prepareフェーズ -> Commitフェーズ1 -> Commitフェーズ2

    • 分散WAL(Write Ahead Logging)により多様なデータベースに対応 • トランザクション状態を⼀元的に管理するコーディネータテーブルを利⽤ • 並⾏性制御:楽観的並⾏性制御(OCC) • Linearizableな条件付き書き込みにより競合を検出 • Strict Serializabilityを保証
  7. 11 (補⾜)Strict Serializability, Linearizability, Serializability • Strict Serializability: Linearizability +

    Serializability • Linearizability: • ⼀つのオブジェクトに対するオペレーションの挙動においてリアルタイム性を保証する性質 • 書き込みが完了したら、その後の読み込みは、その書き込みまたはその後の書き込みの結果を読む • Serializability: • 複数のトランザクションの実⾏結果が、それらを逐次実⾏した結果と同⼀になることを保証する性質 • 例)T1でAを書き込んでコミットし、その後にT2でAを読み込む • Serializabilityのみを保証するデータベース • T1 -> T2 または T2 -> T1 で実⾏された結果と同⼀になることを保証 • Strict Serializabilityを保証するデータベース • T1 -> T2 で実⾏された結果と同⼀になることを保証
  8. ScalarDBのトランザクションプロトコル概要(2) 12 • Single version OCC (Optimistic Concurrency Control, 楽観的並⾏性制御)

    • Snapshot Isolation のシンプルな実装 • トランザクションの競合は条件付き更新によって検知する • HLC (Hybrid Logical Clock) 等の時刻には依存しない • サポートしている分離レベル • Read-committed Snapshot Isolation (RCSI) • Read-skew, Write-skew, Read-only, Phantom アノマリー(異常)が発⽣する可能性有り • Serializable • アノマリーは発⽣しない。(Strict Serializability) • RCSI ベースであるが、Serializable でないスケジュールは Abort される Concurrency Control/Isolation
  9. 13 ScalarDBのトランザクションプロトコル概要(3) • 分散WAL(Write Ahead Logging※) • WALのログ(Before/After image)を各レコードに付加する(レコードに分散配置する) •

    コーディネーターテーブル • トランザクション状態(コミット or アボート)を管理 ScalarDBがトランザクションを管理するために利⽤するメタデータ ※ Write-Ahead Logging. DBへ更新前/更新後の内容を永続ストレージ(HDD等)に書き込み、その後でDBのデータを更新する。主に障害回復のために⽤いられる。
  10. • After image 内のアプリケーションデータはユーザーが更新するデータ • それ以外の部分は Scalar DB が管理するメタデータ 分散WAL

    (Distributed WAL) Tx Status Tx ID Version Tx Status Tx ID Version After image Before image Application data Application data (Before) 16 Transaction metadata Transaction metadata (Before) アプリケーション が管理 ScalarDBが管理
  11. • id / balance という 2つのアプリケーションデータ (カラム) を持つテーブルに、初期値 として id

    = user1, balance = 1000 というデータを INSERT すると、レコードの値は以 下のようになる Distributed WAL column | value -----------------------+------------------------------------- id | user1 balance | 1000 tx_id | 29f9d6bc-1f11-432f-9070-a079ba5867f1 tx_state | 3 tx_version | 1 tx_prepared_at | 1643633112430 tx_committed_at | 1643633112470 before_balance | before_tx_id | before_tx_state | before_tx_version | before_tx_prepared_at | before_tx_committed_at | Before image After image 17
  12. • user1 の balance を -200 するトランザクションを実⾏する (他のユーザーへ 200 送⾦

    する処理を実施する) と、各カラムの値は以下のようになる • before_XXXX というカラムは Before image であり、1つ前のトランザクションで更新 された (送⾦前の) ユーザーデータ及びメタデータが保持されている Distributed WAL column | value -----------------------+------------------------------------- id | user1 balance | 800 tx_id | 04867263-ea11-49fb-9f7d-0b152466f3e0 tx_state | 3 tx_version | 2 tx_prepared_at | 1643633195199 tx_committed_at | 1643633195245 before_balance | 1000 before_tx_id | 29f9d6bc-1f11-432f-9070-a079ba5867f1 before_tx_state | 3 before_tx_version | 1 before_tx_prepared_at | 1643633112430 before_tx_committed_at | 1643633112470 Before image After image 18
  13. • Consensus Commit では主に tx_id, tx_state, tx_version の値を利⽤する • tx_id

    は、当該レコードを更新したトランザクションの ID が格納される • tx_state は、当該レコード書き込んだトランザクションの状態が格納される • tx_version は、トランザクションにて当該レコードが更新される毎に値が増加する (+1 される) Distributed WAL column | value -----------------------+------------------------------------- id | user1 balance | 800 tx_id | 04867263-ea11-49fb-9f7d-0b152466f3e0 tx_state | 3 tx_version | 2 tx_prepared_at | 1643633195199 tx_committed_at | 1643633195245 before_balance | 1000 before_tx_id | 29f9d6bc-1f11-432f-9070-a079ba5867f1 before_tx_state | 3 before_tx_version | 1 before_tx_prepared_at | 1643633112430 before_tx_committed_at | 1643633112470 Before image After image 19
  14. Distributed WAL column | value -----------------------+------------------------------------- id | user1 balance

    | 800 tx_id | 04867263-ea11-49fb-9f7d-0b152466f3e0 tx_state | 3 tx_version | 2 tx_prepared_at | 1643633195199 tx_committed_at | 1643633195245 before_balance | 1000 before_tx_id | 29f9d6bc-1f11-432f-9070-a079ba5867f1 before_tx_state | 3 before_tx_version | 1 before_tx_prepared_at | 1643633112430 before_tx_committed_at | 1643633112470 Before image After image 20 • tx_state には以下のような値が格納される。 • 1: Prepared (トランザクションは実⾏中、 Commit / Abort は未確定) • 2: Deleted (トランザクションは実⾏中、レコードは削除状態、Commit/Abortは未確定) • 3: Committed (トランザクションは Commit 済み)
  15. Distributed WAL column | value -----------------------+------------------------------------- id | user1 balance

    | 800 tx_id | 04867263-ea11-49fb-9f7d-0b152466f3e0 tx_state | 1 tx_version | 2 tx_prepared_at | 1643633195199 tx_committed_at | 1643633195245 before_balance | 1000 before_tx_id | 29f9d6bc-1f11-432f-9070-a079ba5867f1 before_tx_state | 3 before_tx_version | 1 before_tx_prepared_at | 1643633112430 before_tx_committed_at | 1643633112470 Before image After image 21 • トランザクション実⾏中(の特定のタイミングで)障害が発⽣した場合は、Before image を利⽤して Rollback 処理が実施される (Lazy Recovery) • Before imageによってAfter imageを上書きする
  16. • アプリケーションデータを格納するテーブルとは別に、トランザクションの状態を管 理するための coordinator.state テーブルを⽤意する(ScalarDBが⾃動で作成) • coordinator.state テーブルにはトランザクションの ID (tx_id)

    とトランザクションの 状態 (tx_state) が格納される コーディネーターテーブル(coordinator.state) tx_id | tx_state | tx_created_at --------------------------------------+----------+--------------- 29f9d6bc-1f11-432f-9070-a079ba5867f1 | 3 | 1643633112459 a4be06dd-a2e7-4d79-9415-04e324412361 | 3 | 1643633120152 04867263-ea11-49fb-9f7d-0b152466f3e0 | 3 | 1643633195233 23
  17. • coordinator.state テーブルの tx_state には以下のような値が格納される • 3: Committed (トランザクションは Commit

    済み) • 4: Aborted (トランザクションは Abort 済み) • 多様なデータベース上で実施されるトランザクションの状態を⼀元的に管理する • Atomicityを担保 コーディネーターテーブル( coordinator.state) tx_id | tx_state | tx_created_at --------------------------------------+----------+--------------- 29f9d6bc-1f11-432f-9070-a079ba5867f1 | 3 | 1643633112459 a4be06dd-a2e7-4d79-9415-04e324412361 | 3 | 1643633120152 04867263-ea11-49fb-9f7d-0b152466f3e0 | 3 | 1643633195233 24
  18. Backend DB Tx1's memory space 書き込みトランザクション user1からuser2へ200を送⾦するトランザクションを実⾏する。 tx_id XXX YYY

    tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) 28
  19. Backend DB Tx1's memory space 書き込みトランザクション:Prepare フェーズ前 トランザクション(Tx1)はレコードのデータを⾃⾝のメモリ上に読み込む。 ID Balance

    tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) メモリ上に読み込み 29
  20. Backend DB Tx1's memory space 書き込みトランザクション:Prepare フェーズ前 メモリ内でuser1 から user2

    に 200 送⾦する処理を実施(読み込んだレコードを更新)。 tx_state の値を Prepare (コミットの準備状態) に設定。 tx_id には⾃⾝のトランザクション ID を設定。 tx_version を +1 だけインクリメント。 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) メモリ上で更新 30
  21. Backend DB Tx1's memory space 書き込みトランザクション:Prepare フェーズ DBに書き込む際に更新対象レコードの tx_id と

    tx_version の値がメモリに読み込んだ時の値と⼀致するかをチェック。 もし tx_id と tx_version の値が⼀致しなかった場合は書き込みは失敗する (トランザクションは ABORT) 。(詳細は後述) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ⽐較 31
  22. Backend DB Tx1's memory space 書き込みトランザクション:Prepare フェーズ tx_id と tx_version

    の値がメモリに読み込んだ時の値と⼀致する場合は更新内容を DB に書き込む。 (条件付き書き込み※) 更新前のデータ(Before image)も⼀緒に保存される (詳細は後述) この時点では未だ Commit ではない (値は確定していない)。 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) 書き込み 32 ※ 値の⼀致のチェックとDBへの書き込みはアトミック(不可分)に実⾏される
  23. Backend DB Tx1's memory space 書き込みトランザクション: Commit フェーズ1 Prepare フェーズの完了後、トランザクションの状態

    (Abort / Commit) を管理している coordinator.state テーブルに トランザクションが Commit であることを書き込む。 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 tx_id XXX YYY tx_state Commit Commit Tx1 Commit ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) Tx1 の Commit を追記 33
  24. Backend DB Tx1's memory space 書き込みトランザクション: Commit フェーズ2 Commitフェーズ1の完了後、更新対象レコードの tx_state

    の値を PrepareからCommit に更新する。 もし対象レコードの tx_id が⾃⾝のトランザクション ID と⼀致しなかった場合 (Commitフェーズ1からCommitフェーズ2 の間に他のトランザクションが更にデータを更新している場合) は何もしない。 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 tx_id XXX YYY tx_state Commit Commit Tx1 Commit ID Balance tx_state tx_id tx_version user1 800 Commit Tx1 4 user2 700 Commit Tx1 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) tx_state の値を Commit に変更 34
  25. Backend DB Tx1's memory space 書き込み競合時の挙動 現在、account テーブルに「user1 の Balance

    = 1000」「user2 の Balance = 500」という 2つのレコードが Commit 済みの 状態で格納されている (Backend の DB に格納されている)。この状態で「Tx1が user1 から user2 に 200 送⾦」「Tx2 が user1 から user2 に 600 送⾦」という「2つの競合する処理」がほぼ同時に施⾏された際の動作について記載する。 Tx2's memory space tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) 36
  26. Backend DB Tx1's memory space 書き込み競合時の挙動 初めに、各トランザクションがレコードのデータを⾃⾝のメモリ上に読み込む (Read の時点で競合は検知しない)。 ID

    Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 Tx2's memory space メモリ上に読み込み 37 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5
  27. Backend DB Tx1's memory space 書き込み競合時の挙動 各トランザクション内で、メモリ上に読み込んだデータを基に、メモリ内で更新処理 (user1 から user2

    に送⾦する処理) を 実施する。この時、tx_state の値を Prepare (トランザクションの状態は未確定) に設定する。また、tx_id には⾃⾝のトラン ザクションの ID を設定しつつ、tx_version の値を +1 する。ここまでの処理は各トランザクションのメモリ上での処理であ るため、競合することはない。 Tx2's memory space メモリ上で更新 38 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6
  28. Backend DB Tx1's memory space 書き込み競合時の挙動 今回は「Application2 (Tx2) が先に Write

    した」場合について記載する。メモリ上でのレコードの更新完了後、更新したデー タを DB に Write する前に、更新対象のレコードの tx_id と tx_version の値が事前に読み込んだ際の (更新前の) レコードの 値と⼀致するか否かを確認する。 Tx2's memory space ⽐較 39 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6
  29. Backend DB Tx1's memory space 書き込み競合時の挙動 更新対象のレコードの tx_id と tx_version

    の値が事前に読み込んだ際の (更新前の) レコードの値と⼀致する場合は、更新し たデータを DB に Write する (Tx2 側での Prepare フェーズ)。 Tx2's memory space 40 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 書き込み
  30. Backend DB Tx1's memory space 書き込み競合時の挙動 Tx2 側での Prepareフェーズ完了後に、Tx1 側で更新したデータの書き込みを試⾏した場合について記載する。Tx1

    は、更新 対象のレコードの tx_id と tx_version の値が事前に読み込んだ際の (更新前の) レコードの値と⼀致するか否かを確認する。 Tx2's memory space 41 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 ⽐較
  31. Backend DB Tx1's memory space 書き込み競合時の挙動 しかし、既に Tx2 で更新されたデータが適⽤ (DB

    上のデータが更新) されているため、Tx1 側では tx_id と tx_version の値が ⼀致しない。 Tx2's memory space 42 tx_id XXX YYY tx_state Commit Commit ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 不⼀致
  32. Backend DB Tx1's memory space 書き込み競合時の挙動 そのため、Tx1 は Abort されることになる。この時、Tx1

    は coordinator.state テーブルに Tx1 が Abort したことを書き込む (競合したレコード以外に Tx1 が既に Prepare フェーズで書き込んだ他のレコードが存在する場合は、それらのレコードを Rollback する処理も実施される)。 Tx2's memory space 43 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 tx_id XXX YYY tx_state Commit Commit Tx1 Abort Abort Abort を追記
  33. Backend DB Tx1's memory space 書き込み競合時の挙動 Tx2 側の処理はそのまま継続されるため、coordinator.state テーブルへの書き込み (Commitフェーズ1)

    が実⾏される。 Tx2's memory space 44 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 tx_id XXX YYY tx_state Commit Commit Tx1 Abort Tx2 Commit Commit を追記 Aborted
  34. Backend DB 書き込み競合時の挙動 Tx2 は、coordinator.state テーブルに⾃⾝が Commit したことを書き込んだ後、Commitフェーズ2 を実⾏し、Prepare 状態

    で書き込んでいたレコードの tx_state の値を Commit に更新する。 Tx2's memory space 45 ID Balance tx_state tx_id tx_version user1 400 Commit Tx2 4 user2 1100 Commit Tx2 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 tx_id XXX YYY tx_state Commit Commit Tx1 Abort Tx2 Commit
  35. Backend DB 書き込み競合時の挙動 このように、ScalarDBのトランザクションプロトコルでは tx_id と tx_version の値を利⽤することで、書き込みの競合を検 知し、データの不整合を防ぎ正しく処理を実施 (競合したトランザクションのどちらかを

    Abort)することができる。 Tx2's memory space 46 ID Balance tx_state tx_id tx_version user1 400 Commit Tx2 4 user2 1100 Commit Tx2 6 account テーブル (ユーザーデータ) coordinator.state テーブル (Tx 管理⽤メタデータ) ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 400 Prepare Tx2 4 user2 1100 Prepare Tx2 6 tx_id XXX YYY tx_state Commit Commit Tx1 Abort Tx2 Commit Tx1's memory space ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 user2 500 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 user2 700 Prepare Tx1 6 Aborted Committed
  36. Tx1's memory space 書き込みトランザクション あるユーザー (user1) がクレジットカード決済で商品を購⼊する場合の処理の⼀部を例として記載する。ユーザーの⼝座 (残 ⾼) 情報は

    Backend DB 1 に、ユーザーのクレジットカードの利⽤額 (利⽤総額) 情報は Backend DB 2 にそれぞれ格納されて いる。この状態で、Scalar DB を利⽤し「⼝座から残⾼を減算 (-200) する処理」と「クレジットカードの利⽤総額を加算 (+200) する処理」を 1つのトランザクションで実⾏する。 Backend DB 1 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 credit ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 48
  37. Tx1's memory space 書き込みトランザクション: Prepare フェーズ前 基本的には 1つの Backend DB

    に対する Consensus Commit と仕組みは変わらない。まず、Scalar DB (アプリケーション) はトランザクションで更新するデータを⾃⾝のメモリ上に読み込む。 Backend DB 1 Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 メモリ上に読み込み 49 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 credit ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5
  38. Tx1's memory space 書き込みトランザクション: Prepare フェーズ前 メモリ上で各データを更新する。この時、tx_state の値を Prepare (トランザクションの状態は未確定)

    に設定する。また、 tx_id には⾃⾝のトランザクションの ID を設定しつつ、tx_version の値を +1 する。 Backend DB 1 Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 50 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 credit ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 メモリ上で更新 Balance = Balance - 200 Amount = Amount + 200 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6
  39. Tx1's memory space 書き込みトランザクション: Prepare フェーズ メモリ上でのレコードの更新完了後、更新したデータを DB に Write

    する前に、更新対象のレコードの tx_id と tx_version の値が事前に読み込んだ際の (更新前の) レコードの値と⼀致するか否かを確認する。この時、tx_id と tx_version の値が⼀ 致しなかった場合は、書き込みが失敗 (トランザクションは ABORT) する。詳細は前述した「単⼀データベース上でのトラン ザクション (Write で競合が発⽣した場合)」参照。 Backend DB 1 Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 51 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 credit ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6 読み込んだ値と現在の DB 上の値を⽐較
  40. Tx1's memory space 書き込みトランザクション: Prepare フェーズ 更新対象のレコードの tx_id と tx_version

    の値が事前に読み込んだ際の (更新前の) レコードの値と⼀致する場合は、更新し たデータを DB に Write する。また、更新前のデータを Before image として同⼀レコード内に保存する。 Backend DB 1 Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 52 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 credit ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6 更新したデータを書き込む 更新前のデータを Before image に保存
  41. Tx1's memory space 書き込みトランザクション: Commit フェーズ1 Prepare Phase 完了後、トランザクションの状態 (Abort

    / Commit) を管理しているテーブル coordinator.state に、⾃⾝のト ランザクション ID (Tx1) の状態が Commit であることを書き込む。 Backend DB 1 Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 53 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 credit ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6 coordinator.state に Commit した旨を追 記 Tx1 Commit
  42. Tx1's memory space 書き込みトランザクション: Commit フェーズ2 Commit Phase 1 完了後、Prepare

    状態で書き込んでいたレコードの tx_state の値を Commit に更新する。 Backend DB 1 Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 54 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account ID Balance tx_state tx_id tx_version user1 800 Commit Tx1 4 credit ID Amount tx_state tx_id tx_version user1 3200 Commit Tx1 6 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6 Tx1 Commit tx_state の値を Commit に更新
  43. Tx1's memory space 書き込みトランザクション:完了 このように、「複数の DB に対してそれぞれ Consensus Commit を実⾏」かつ「coordinator.state

    でトランザクションの状 態を⼀元管理」することで、「複数 DB を跨ぐトランザクション」を実施できる。 Backend DB 1 Backend DB 2 ID Balance tx_state tx_id tx_version user1 1000 Commit XXX 3 ID Amount tx_state tx_id tx_version user1 3000 Commit YYY 5 55 coordinator.state tx_id AAA BBB tx_state Commit Commit XXX Commit YYY Commit account ID Balance tx_state tx_id tx_version user1 800 Commit Tx1 4 credit ID Amount tx_state tx_id tx_version user1 3200 Commit Tx1 6 ID Balance tx_state tx_id tx_version user1 800 Prepare Tx1 4 ID Amount tx_state tx_id tx_version user1 3200 Prepare Tx1 6 Tx1 Commit
  44. 59 Serializable Strategy: Extra-read • Commit 直前にトランザクション内で Read したデータの Validationを実施

    • Readしたデータが他のトランザクションによって更新されていないかを再度Readしてチェック Read(X) Commit phase 2 (Y) Write(Y) Prepare(Y) Commit phase 1 Read(X) Commit phase 2 (Y) Write(Y) Prepare(Y) Commit phase 1 Validation(X) Validation: • もしReadしたデータが他のトラン ザクションによって更新されていな かった場合 => Commit • もしReadしたデータが他のトラン ザクションによって更新されていた 場合 => Abort Without serializable strategy With serializable strategy (Extra-read)
  45. 性能最適化 61 • Parallel Commit • 各レコードに対する Prepare フェーズの処理と Commit

    フェーズ2の処理を並列で実⾏する • 関連する設定値 設定値名 概要 デフォルト値 scalar.db.consensus_commit.parallel_executor_count 並列に実行するスレッド数 128 scalar.db.consensus_commit.parallel_preparation.enabled Prepareフェーズの並列実行を設定 true scalar.db.consensus_commit.parallel_validation.enabled Validationフェーズ (Extra-read有効化時)の並列実行を設定 true scalar.db.consensus_commit.parallel_commit.enabled Commitフェーズの並列実行を設定 true scalar.db.consensus_commit.parallel_rollback.enabled Rollback処理の並列実行を設定 true scalar.db.consensus_commit.parallel_implicit_pre_read.enabled Inplicit pre-read※ の並列実行を設定 true ※ Implicit pre-readについてはこちらのドキュメントをご参照ください。
  46. 性能最適化 62 Write(X) Write(Y) Commit Phase 1 Parallel Commit Write(X)

    Write(Y) Prepare(X) Prepare(Y) Commit Phase 1 Commit Phase 2 (X) Commit Phase 2 (Y) 複数のレコードに対する Prepare 処理とCommit フェーズ2の処理を並列で 実⾏する。 Prepare(X) Prepare(Y) Commit Phase 2 (Y) Commit Phase 2 (X) Parallel Commit