マルチバージョン読み取り一貫性の紹介
データの読み書きを相互排他しないようにサポートするため、OceanBaseデータベースは複数のバージョンのデータを格納しています。マルチバージョンデータのセマンティクスを処理するためには、マルチバージョンの一貫性を維持する必要があります。OceanBaseデータベースのマルチバージョン一貫性は、読み取りバージョンとデータバージョンによって保証され、読み取りバージョン番号を参照し、そのバージョンより小さいすべてのコミット済みデータを返すことで定義されます。
したがって、以下の点に注意する必要があります:
未コミットトランザクション:自身のトランザクション以外の未コミットデータを読み取ることはできません。そうでない場合、対応するトランザクションがロールバックされた際にダーティリード(dirty read)が発生します。
トランザクション一貫性スナップショット:読み取りバージョン番号より小さいすべてのコミット済みデータを読み取ることで、ユーザーが理解可能な一貫性ポイントを保証します。そうでない場合、フラクチャードリード(fractured read)が発生します。
読み書きの非相互排他:未コミットトランザクションとトランザクション一貫性ポイントの条件を満たす前提で、読み書きの非相互排他も保証する必要があります。
マルチバージョン読み取り一貫性の使用
マルチバージョン読み取り一貫性はデータベース内部で広く使用されており、並行制御を実現する鍵の一つです:
弱い一貫性の読み取り:OceanBaseデータベースの弱い一貫性の読み取りは、トランザクションの一貫性スナップショットを提供し続け、未コミットトランザクションやフラクチャードリードの状況を返すことはありません。
強い一貫性の読み取り:OceanBaseデータベースの強い一貫性の読み取りは、トランザクションレベルの読み取りバージョン番号とステートメントレベルのバージョン番号の2種類に分かれており、それぞれスナップショット読み取りとコミット済み読み取りの2つの分離レベルで使用されます。トランザクションの一貫性ポイントを返す機能が必要です。
読み取り専用トランザクション:OceanBaseデータベースの読み取り専用ステートメントも、強い一貫性の読み取りと同じ機能を提供する必要があり、トランザクションの一貫性ポイントを返す機能が必要です。
バックアップ復元ポイント:OceanBaseデータベースは、トランザクションの一貫性スナップショットまでバックアップできる機能を提供する必要があります。これにより、余分な未コミットトランザクションをバックアップしたり、バックアップが必要なトランザクションをバックアップしなかったりすることを防ぎます。
ユーザーがマルチバージョンを使用する過程は、以下の図のようになります:
上記の左図のように、データAには100バージョンのコミット済みデータaが含まれており、対応するトランザクションはトランザクション10です。また、コミット済みデータbが含まれており、対応するトランザクションはトランザクション7です。データBには未決定バージョンのデータjと対応するトランザクション12、およびコミット済みデータbが含まれており、対応するトランザクションはトランザクション10です。データCには未決定バージョンのデータxと対応するトランザクション15、およびコミット済みデータyが含まれており、対応するトランザクションはトランザクション10です。
マルチバージョン読み取り一貫性の実装
トランザクションテーブル
トランザクションテーブルはメモリテーブルであり、現在そのレプリカで実行中のトランザクションの集合を表します。トランザクションは実行中、異なるトランザクションステータスに基づいて、対応するデータを読み取るかどうかを判断します。データのステータスには、コミット(COMMIT)、実行中(RUNNING)、ロールバック(ABORT)が含まれます。実行中(RUNNING)のトランザクションには ローカルコミットバージョン番号(local commit version、準備バージョン)が存在する場合があります。コミット済みのトランザクションには グローバルコミットバージョン番号(global commit version、コミットバージョン)が存在します。ここで グローバルコミットバージョン番号 がトランザクションの最終バージョンを表し、私たちの一貫性ポイントを決定する要因となります。
上記の右図のように、トランザクション6はロールバック状態です。トランザクション7はコミット状態で、グローバルコミットバージョン番号 は80です。トランザクション12は実行状態で、ローカルコミットバージョン番号 は存在しません。トランザクション15は実行状態で、ローカルコミットバージョン番号 は130です。
読み取りリクエストの処理
読み取り時には、読み取りバージョン番号を用いて対応するデータを読み取ります。
次に分けて分析します。コミットまたはロールバックされたトランザクションを読み取る場合、グローバルコミットタイムスタンプと状態を比較することで、対応するデータを読み取る必要があるかどうかを簡単に推測できます。下図のように、読み取りリクエストr1は読み取りバージョン番号90で読み取りを行いますが、スナップショット読み取りポリシーに基づき、バージョン番号80、データbのデータを選択して読み取ります。
RUNNING状態のトランザクションを読み取る場合、そのデータを安全にスキップできます。下図のように、読み取りリクエストr2は読み取りバージョン番号130で読み取りを行い、2フェーズコミットに入っていないトランザクション12を安全にスキップし、バージョン番号100、データbのデータを読み取ります。
PREPARE状態のトランザクションを読み取る場合、トランザクションがコミットされるかどうかは不確定なため、その行のトランザクションを待機します。下図のように、読み取りリクエストr3は読み取りバージョン番号140で読み取りを行い、2フェーズコミット状態でローカルコミットタイムスタンプが130のトランザクションを待ち、最終的にグローバルコミットタイムスタンプと読み取りタイムスタンプ140の関係を決定します。