OceanBaseデータベースは、2種類の整合性レベル(Consistency Level)を提供しています:STRONGとWEAKです。STRONGは強い整合性を指し、最新のデータを読み取り、リクエストはプライマリレプリカにルーティングされます。WEAKは弱い整合性を指し、最新のデータを読み取る必要がなく、リクエストはセカンダリレプリカに優先的にルーティングされます。OceanBaseデータベースの書き込み操作は常に強い整合性であり、常にプライマリレプリカがサービスを提供します。読み取り操作はデフォルトで強い整合性であり、プライマリレプリカがサービスを提供しますが、ユーザーは弱い整合性の読み取りを指定することもでき、その場合はセカンダリレプリカが優先的にサービスを提供します。
一貫性レベルの指定方法
一貫性レベルを指定するには、以下の2つの方法があります。
ob_read_consistencyシステム変数を使用して指定するセッション変数を設定すると、現在のセッションにのみ影響します。
obclient> SET ob_read_consistency = WEAK; obclient> SELECT * FROM t1; -- 弱い一貫性での読み取りグローバル変数を設定すると、その後新規作成されるすべてのセッションに影響します。
obclient> SET GLOBAL ob_read_consistency = STRONG;
ヒントを指定する方法
WEAK Consistencyを指定すると、
ob_read_consistencyよりも優先順位が高くなります。obclient> SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM t1;STRONG Consistencyを指定する
obclient> SELECT /*+READ_CONSISTENCY(STRONG) */ * FROM t1;
SQLステートメントの一貫性レベル
書き込みステートメントDML (INSERT/DELETE/UPDATE):STRONG Consistencyの使用を強制し、最新データに基づいて変更を行うことを要求します。
SELECT FOR UPDATE(SFU):書き込みステートメントと同様に、STRONG Consistencyの使用を強制します。読み取り専用ステートメント
SELECT:ユーザーは異なるConsistency Levelを設定でき、さまざまな読み取り要件を満たせます。
トランザクションの一貫性レベル
弱い一貫性読み取りのベストプラクティスは、トランザクション外のSELECTステートメントにWEAK一貫性レベルを指定することです。その意味は明確です。明示的にトランザクションを開始するシナリオでは、構文的にOceanBaseデータベースは異なるステートメントに異なる一貫性レベルを設定できますが、これはユーザーを混乱させる可能性があり、不適切に使用した場合はSQLエラーが発生します。
原則:
- 一貫性レベルの最低設定はステートメントレベルです。セッションまたはステートメントが弱い読み取りとしてマークされている場合、システムは弱い読み取りパスを採用しようとします。
- 書き込みステートメントとSFUステートメントは強い読み取りのみを使用できます。弱い読み取りのマークが存在しても、これらのステートメントは強い読み取り方式で実行されます。
- トランザクション内で、最初に書き込みステートメントまたはSFUステートメントを実行した場合、後続の読み取りステートメントがそのトランザクションの未コミット変更を読み取る必要がある場合は、強い読み取り方式で実行する必要があります。
以下に例を示します。
BEGIN;
-- 変更ステートメント、consistency_level=STRONG、トランザクション全体はSTRONGであるべきです
insert into t1 values (1);
-- SQL自体のconsistency_level=WEAKですが、最初のステートメントがSTRONGであるため、
-- このステートメントのconsistency_levelは強制的にSTRONGに設定されます
select /*+READ_CONSISTENCY(WEAK) */ * from t1;
COMMIT;
BEGIN;
-- SFUは変更ステートメントに属し、consistency_level=STRONG、トランザクション全体もSTRONGであるべきです
select * from t1 for update;
-- SQL自体のconsistency_level=WEAKですが、最初のステートメントがSTRONGであるため、
-- このステートメントのconsistency_levelは強制的にSTRONGに設定されます
select /*+READ_CONSISTENCY(WEAK) */ * from t1;
COMMIT;
BEGIN;
-- 最初のステートメントはWEAKです
select /*+READ_CONSISTENCY(WEAK) */ * from t1;
-- セッションまたはグローバルのob_read_consistencyがWEAKに設定されていない限り、このステートメントは通常のStrong Read形式で実行できます
select * from t1;
COMMIT;
BEGIN;
-- 最初のステートメントはWEAKです
select /*+READ_CONSISTENCY(WEAK) */ * from t1;
-- 変更ステートメントは必ずSTRONGでなければならず、このステートメントは正常に実行できます
insert into t1 values (1);
-- SQL自体のconsistency_level=WEAKですが、前のステートメントが変更ステートメントであるため、
-- このステートメントのconsistency_levelは強制的にSTRONGに設定されます
select /*+READ_CONSISTENCY(WEAK) */ * from t1;
COMMIT;
したがって、単一のSQLについて、一貫性レベルの決定ルールの優先順位は、大きい順に以下のように要約できます:
ステートメントタイプに基づいて決定される一貫性レベル。例えば、DMLとSFUは必ずSTRONGを使用する必要があります。
トランザクションの一貫性レベル。ステートメントがトランザクション内にあり、かつ最初のステートメントでない場合は、トランザクションの一貫性レベルを使用します。
ヒントで指定された一貫性レベル。
システム変数で指定された一貫性レベル。
デフォルトでSTRONGを使用します。
分離レベルとの関係
STRONGはすべての分離レベルをサポートします。
WEAKは読み取りコミット済み
READ COMMITTED分離レベルのみをサポートし、その他の分離レベルではOB_NOT_SUPPORTEDエラーが発生します。分離レベルが
Repeatable ReadおよびSerializableの場合、弱い読み取りリクエストの実行も有効です。
弱い整合性読み取りのパラメータ
V2.2.x より前のバージョン
名前 |
機構 |
セマンティクス |
|---|---|---|
| enbale_causal_order_read | クラスタレベル | 単調読み取りを有効にするかどうか。デフォルトはfalseです。 |
| max_stale_time_for_weak_consistency | クラスタレベル | 弱い一貫性読み取りの最大遅延時間。デフォルト値は5秒です。 |
V2.2.x より前のバージョンでは、Proxy レベルでのモノトニック読み取りのみをサポートしています。つまり、クライアントが常に同じ Proxy にアクセスする限り、モノトニック読み取りが保証されます。具体的な実装方法は、Proxy 上でモノトニックに増加する弱い一貫性の読み取りバージョン番号を維持することです。クライアントが Proxy 間でアクセスする場合は、モノトニック読み取りは保証されません。クラスタレベルでのモノトニック読み取りが必要な場合は、V2.2.x 以降のバージョンを使用する必要があります。
V2.2.x ~ V3.x バージョン
名前 |
範囲 |
セマンティクス |
|---|---|---|
| enable_monotonic_weak_read | テナントレベル | 単調読み取りを有効にするかどうか。デフォルトはTrueです。 |
| max_stale_time_for_weak_consistency | テナントレベル | 弱い一貫性読み取りの最大遅延時間。デフォルト値は5秒です |
| weak_read_version_refresh_interval | クラスタレベル | 弱い一貫性読み取りのバージョン番号リフレッシュ間隔。デフォルト値は50ミリ秒です |
各パラメータの具体的な意味は以下の通りです:
enable_monotonic_weak_read:テナントレベルモノトニック読み取りスイッチ弱い一貫性の読み取りは異なるレプリカにルーティングされ、異なるレプリカで読み取ったデータの新旧は保証されません。モノトニック読み取りスイッチをオンにすると、OceanBase データベースは読み取ったデータバージョンがロールバックしないこと、つまりモノトニック性が保証されることを保証します。典型的なユースケースは因果順序の保証です:2 つのトランザクション T1 と T2 があり、T1 がコミットした後に T2 がコミットします。クライアントが T2 トランザクションの変更を読み取った場合、その後必ず T1 トランザクションの変更を読み取ることができます。
max_stale_time_for_weak_consistency:弱い一貫性読み取りの最大遅延時間OceanBase データベースの弱い一貫性読み取りは、有界な古さの保証を提供します。つまり、読み取ったデータが
max_stale_time_for_weak_consistencyの時間だけ遅れていることを保証します。デフォルト設定値は 5 秒で、テナントレベルでの設定が可能です。通常、各パーティションのスタンバイレプリカの遅延時間は 100 ミリ秒から 200 ミリ秒です。弱い一貫性読み取りの時効性は百ミリ秒レベルです。ネットワークジッターやリーダー不在などの状況が発生すると、弱い一貫性読み取りの時効性は低下します。あるレプリカの遅延時間が
max_stale_time_for_weak_consistencyを超えると、そのレプリカは読み取り不可となり、内部の再試行メカニズムが他の有効なレプリカに対して再試行を行います。すべてのレプリカが読み取り不可の場合は、ステートメントがタイムアウトするまで継続的に再試行します。モノトニック読み取りスイッチをオンにすると、OceanBase データベースは内部で各テナントに対してクラスタレベルの弱い一貫性読み取りバージョン番号を維持します。このバージョン番号も
max_stale_time_for_weak_consistencyの制約を満たします。その生成方法は、テナント内のすべてのパーティションレプリカの返却進度の最小値を統計することです。特定のパーティションレプリカの遅延時間がmax_stale_time_for_weak_consistencyを超える場合は、そのレプリカは統計に含まれません。現在のメカニズムでは、1 つの遅延レプリカが全体のモノトニック読み取りバージョン番号に影響します。例えば、2 つのパーティションの 2 つのレプリカがあり、1 つのレプリカが 100 ms、もう 1 つのレプリカが 1 秒遅れている場合、全体のモノトニック読み取りバージョン番号は 1 秒となります。私たちは、レプリカが長時間遅れることは通常の状態ではないと考えています。通常の状況では、モノトニック読み取りバージョン番号は百ミリ秒レベルであるべきです。weak_read_version_refresh_interval:弱い一貫性読み取りバージョン番号のリフレッシュ間隔弱い一貫性読み取りバージョン番号のリフレッシュ間隔は、読み取ったデータの新旧の程度に影響します。設定値は
max_stale_time_for_weak_consistencyより大きくできません。0 に設定されている場合、弱い一貫性モノトニック読み取り機能は無効になり、クラスタレベルの弱い一貫性読み取りバージョン番号は維持されなくなります。また、これはクラスタレベルのパラメータであり、テナントレベルでの設定はサポートされていません。
V4.x系
4.x系では、max_stale_time_for_weak_consistencyとweak_read_version_refresh_intervalの2つのパラメータの機能は、以前のバージョンと同じです。
弱い一貫性読み取りのタイムスタンプ
弱い一貫性読み取りは、通常、レプリカやスタンバイデータベースからのクエリステートメントを指します。OceanBaseデータベースの弱い一貫性読み取りは、依然としてトランザクションの一貫性ポイントを返し、未コミットのトランザクションや半分のトランザクションが返されることはありません。
弱い一貫性読み取りのタイムスタンプには、2つの側面が含まれます:
弱い読み取りを実行する前に、読み取りスナップショットデータを確定する必要があります。
パーティション自体が最大安全読み取り可能なポイントをリアルタイムで維持しており、読み取りスナップショットがこのポイントより大きい読み取り要求は、そのレプリカから読むことができません。
タイムスタンプの生成方法
OceanBaseデータベースの弱い読み取りの一貫性は、大きくモノトニック読み取りとノンモノトニック読み取りの2つに分類されます。異なる能力に応じて、タイムスタンプの生成方法も異なります。
モノトニック読み取り
モノトニック読み取りとは、読み取り要求が発行された絶対時間に基づき、後に発行された要求が使用する読み取りスナップショットが前者より小さくならないようにし、読み取ったデータがロールバックされないことを保証するものです。ここでの「モノトニック」とは、ステートメントの読み取りスナップショットに関するものです。モノトニック読み取りの保証は、クラスタレベルのモノトニック弱い読み取りバージョン番号に依存しており、グローバルバージョン番号はロールバックしない必要があります。
グローバルバージョン番号の生成は、各OBServerノードが維持する最小最大安全バージョン番号に由来します。このバージョン番号の生成は、ローカルログ同期の進捗に依存します。OceanBaseデータベースでは、トランザクションのログデータは、apply service、replay_service、Transaction の3つのモジュールによって維持されます:
apply serviceは、トランザクションログのローカルディスクへの書き込み、スタンバイ機への送信、リーダーから同期されたログの受信などの操作を担当します。スタンバイ機にとって、それは各ログストリームに対してスライディングウィンドウを維持し、受信したログをlogidの小さい順に管理します。ログはスライディングウィンドウから順次滑り出し、replay_serviceに送られて再生されます。replay_serviceはログの再生を担当します。同じトランザクションの複数のログを同じワーカースレッドにハッシュし、同じトランザクションのログを順序良く再生することを保証します。しかし、同じパーティションの複数のトランザクションは並行して再生されます。あるパーティションのログについて言えば、ログはコミットタイムスタンプに従って順序良くリンクリストに連結され、複数のスレッドによって並行して再生されます。Transactionはトランザクション状態の管理を担当します。Transactionはログの再生操作を実行します。すなわち、RedoデータをMemStoreに再生し、トランザクションの状態を記録します。
上記の説明からわかるように、ログが apply service から受信され、replay_service に再生タスクとして渡され、さらに Transaction によってトランザクションログが再生されるまでには、一定の時間がかかります。単一のパーティションのスタンバイ機が途中のトランザクションを読み取らないようにするためには、そのパーティションのスタンバイ機が読むことができる安全なバージョン番号を見つけ出し、そのバージョン番号以前のすべてのトランザクションが既に再生完了していることを保証する必要があります。計算式は以下のとおりです:
slave_read_ts = min(replay_service_ts, apply_service_ts, trans_service_ts) - 1
ここで:
apply_service_tsはapply serviceのスライディングウィンドウ内で次に滑り出すか生成されるログのTimestampを表します。replay_service_tsは、そのログストリームでまだ再生されていないログのTimestampの最小値を表します。trans_service_tsは、現在再生中のすべてのトランザクションのprepare_log_tsの最小値を表します。
例を挙げて説明します:仮に apply service のスライディングウィンドウに2つのログが存在し、logidとログのコミットタイムスタンプがそれぞれ(10、100)、(11、200)である場合、replay_service 内では、そのログストリームでまだ再生されていないログは (7、70)、(8、80) です。Transaction 内では、現在再生中のトランザクションは1つだけで、redoとprepare logの再生が終了したところであり、prepare log のlogidは 9、prepare_log_ts=90です。この時点で、そのパーティションの 安全なバージョン番号=min(100, 70, 90) - 1 = 69 となります。
ノンモノトニック読み取り
モノトニック読み取りと比較して、ノンモノトニック読み取りが保証する能力は弱いです。ノンモノトニック読み取りは、前後に発行された要求のスナップショットが増加することを保証しません。同一データの異なるレプリカ間で同期進度に差異があるため、前後の2回の読み取りで異なるレプリカを読んだ場合、データがロールバックされる可能性があります。
原子性
モノトニック読み取りであれノンモノトニック読み取りであれ、単一パーティション内の同一トランザクションによって変更されたデータについては、原子性が保証されます。どのようなシナリオでも、読み取りスナップショットが単一パーティションが維持する最大安全読み取り可能バージョン番号より小さい限り、読み取ったデータは必ず原子性を備えています。これが原子性保証の原則です。
したがって、設計上、パーティションが読み取り可能かどうかの検証を導入する必要があります。読み取り不可能なパーティションについては、SQL実行エンジンに他のレプリカを再試行させます。