マルチバージョン読み取りの一貫性について
データの読み書きが相互排他でないようにサポートするため、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、すなわちprepare version)が存在する場合があります。コミットされたトランザクションには、グローバルコミットバージョン番号(global commit version、すなわち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の関係を決定するのを待機します。