見出し画像

第7章 トランザクション

要約

ACIDは、トランザクションの安全性を確保するための原則を指す頭字語で、原子性、一貫性、分離性、耐久性から構成されます。
原子性は、障害時にトランザクションを中止し、一貫性はデータベースが「良好な状態」を維持することを指します。分離性は、トランザクションの相互干渉を防ぎ、耐久性はデータの不滅性を保障します。
BASEはACIDを満たさないシステムを指し、基本的に利用可能、厳密ではない状態遷移、結果整合性を特徴とします。

3つのリード現象(ダーティリード、ノンリピータブルリード、ファントムリード)とトランザクション分離レベル(Read Committed、Repeatable Read、Serializable)も解説しており、 Repeatable Readではスナップショット分離が問題を解決し、Serializableは直列化可能分離で最高の一貫性を提供しますが、ツーフェーズロックの問題点から直列化可能なスナップショット分離(SSI)が登場し、性能向上と利便性についても説明しています。

前の章

前の章である第6章 パーティショニングはこちらです。

ACID

トランザクションによって提供される安全性の保証は、下記の頭字語ACIDで説明されます。

  •  原子性(Atomicity)

  • 一貫性(Consistency)

  • 分離性(Isolation)

  • 耐久性(Durability)

原子性、分離性、耐久性はデータベースの特性ですが、一貫性 はアプリケーションの特性となります。

原子性

原子とは、より小さく分解できないものを指します。
書き込みがアトミック トランザクションにグループ化されており、障害によりトランザクションを完了 (コミット) できない場合、トランザクションは中止され、データベースはそのトランザクション内でこれまでに行った書き込みを破棄するか取り消す必要があります。

一貫性

データベースが「良好な状態」にあるというアプリケーション固有の概念を指します。
データに関する特定のステートメント (不変条件) が常に真である必要があります。たとえば、会計システムでは、すべての口座の貸方と借方のバランスが常に保たれている必要があります。

ただし、これはアプリケーションの不変条件の概念に依存します。

分離性

同時に実行されるトランザクションは互いに分離されます。トランザクションはお互いに足を踏み入れることはできません。(旧用語: 直列化可能性)
実際には、シリアル化可能な分離はパフォーマンスに影響を与えるため、ほとんど使用されません。

耐久性

トランザクションが正常にコミットされると、ハードウェア障害やデータベースのクラッシュが発生した場合でも、書き込まれたデータは無くなりません。

単一ノード データベースの耐久性とは、通常、データがハード ドライブや SSD などの不揮発性ストレージに書き込まれていることを意味します。
複製されたデータベースでは、耐久性とは、データがいくつかのノードに正常にコピーされたことを意味する場合があります。

BASE

ACID 基準を満たさないシステムは、下記3つの特徴を表すBASEと呼ばれることもあります。

  • 基本的に利用可能(Basically Available)

  • 厳密ではない状態遷移(Soft state)

  • 結果整合性(Eventual consistency

BASEは ACID の定義よりもさらに曖昧です。

3つのリード現象

ダーティリード(Dirty reads)

ダーティリードは、COMMITされていないトランザクションでの変更を他トランザクションがReadすることができてしまう現象のことを指します。

ノンリピータブルリード(Non-repeatable reads)

ノンリピータブルリードは、他トランザクション(T2)がコミットにより対象レコードを更新した場合、1トランザクション(T1)中でReadするレコードデータが異なってしまう現象を指します。

ファントムリード(Phantom reads)

ファントムリードは、他トランザクション(T2)がコミットにより新規レコード追加(または削除)をした場合、1トランザクション(T1)中でReadするテーブルデータが異なってしまう現象を指します。

トランザクション分離レベル

分離レベルには、一般的に4つのレベルが設けられており、それぞれがどのリード現象に対応できるかがまとめられています。

トランザクション分離レベルの種類(トランザクション分離レベルについてのまとめより)

本書では、Read Committed、Repeatable Read(≒スナップショット分離), Serializableの3つが登場します。

Read Committed

最も基本的(一般的に使用されている)レベルがRead Committedになりま
す。

ダーティリード・ライトは発生しない

上記の対応表(画像)の通り、このレベルではダーティリードは発生しません。

writeロックはトランザクションが終わるまで解放されない一方で、readロックは読み取り操作が終わり次第解放します。readロックが取られているレコードに別のトランザクションからwriteロックを取ること(書き込み)ができないので、読み取ったレコードはコミット済みであることが保証されます。

またwriteロックが取られているレコードに別のトランザクションからwriteロックを取ることができないので、上書きするのはコミットされたレコードのみであることが保証されます。これらによって、ダーティリードとダーティライトを防ぐことができます。

問題点

読み取ってすぐにロックを解放するのでノンリピータブルリードや読み取りスキューの問題は回避することができません。

Repeatable Read(≒スナップショット分離)

それぞれのトランザクションが一貫性のあるスナップショットから読み取りを行うことでノンリピータブルリードや読み取りスキューの問題を解決します。

読み取りと書き込みでブロックが発生しない

MVCC(multi-version concurrency controll)という手法によって、データベースは複数のコミット済みバージョンを管理することができます。

各バージョンはトランザクションIDやコピー元のトランザクションIDなどをメタデータとして持つことで、他のトランザクションが書き込みをしてもトランザクション内では常に開始時のデータベースの状態を参照できるので、読み取りと書き込みでブロックが発生しなくなります。
また、ノンリピータブルリードを回避することもできます。

下記の画像は非常にわかりやすいです。

Snapshot(トランザクションの分離性(isolation)の概要より

さらに、書き込みをコミットする際に、トランザクション開始時に取得したスナップショットが既に変更されていた場合は、別のトランザクションが開始後に書き込みをコミットしたことになります。
よって、トランザクションを中断することで、更新ロストも回避することができます。

問題点

完全に直列可能ではないことから、ファントムリードによる書き込みスキューが発生し得ることがあります。

Serializable(直列化可能分離)

直列化可能分離(Serializable)は、最も強い分離レベルでです。トランザクションを実行しても順番に実行された時と同じ結果になることを保証します。
よって、ファントムリードによる書き込みスキューが発生しません。

①完全な順次実行と問題点

直列可能分離レベルを実現するには、並列性を排除して順番にトランザクションを実行することもできますが、そうするとトランザクションの待ち時間が大きくなり過ぎてしまいます

そこで、ツーフェーズロック(2相ロック)を用いて直列可能分離レベルを実現します。

②ツーフェーズロック(2相ロック)と問題点

2相ロックでは誰も書き込んでいない限り、複数のトランザクションが同じオブジェクトを同時に読み取ることができます。

ただし、下記のような問題点があります

  • ライターは他のライターをブロックするだけではありません。リーダーもブロックしますし、その逆も同様です。

  • トランザクションのスループットとクエリの応答時間は、弱い分離よりも 2 フェーズ ロックの方が大幅に悪化します。

これらの問題点から2相ロックは使用されないことが多いです。

③直列化可能なスナップショット分離(SSI)

これは完全な直列化可能性を提供しながら、スナップショット分離レベルに比べるとパフォーマンス上のペナルティーが少なくて済むというメリットがあります。

また、2 相ロックと比較した場合の大きな利点は、あるトランザクションが別のトランザクションが保持するロックを待機してブロックする必要がないことです。

SSIはデータウェアハウスで使用されていて、Amazon RedshiftやGoogle BigQueryでも採用されています。

補足

悲観的な同時実行制御と楽観的な同時実行制御

  • 2相ロックは、悲観的な同時実行制御になります。

  • 直列化可能なスナップショット分離(SSI)は、楽観的な同時実行制御です。

トランザクションを使った実務アプローチ

メルペイのテックブログにトランザクション管理についての記事があります。 処理が途中で落ちた場合に、トランザクションのデータの整合性を担保しないといけないという課題に対して、複数のアプローチが書かれています。

まとめ

以上、トランザクションについて解説しました。

ACIDから始まり、トランザクションにおいての問題点やその解決法が網羅的に書かれていました。

現代のDWHでもよく使われる直列化可能なスナップショット分離(SSI)は非常に重要です。

トランザクションについて特に重要な点を解説しました。ただし、非常に量が多いため解説していない部分が多々あります。詳細は本書を手にとってみて下さい。


いいなと思ったら応援しよう!

zono
よろしければ応援お願いします! いただいたチップはデータエンジニアとしての活動費や勉強代、教育に使わせていただきます!